Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2010 Google 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 are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "WebViewImpl.h"
     33 
     34 #include "AutoFillPopupMenuClient.h"
     35 #include "AutocompletePopupMenuClient.h"
     36 #include "AXObjectCache.h"
     37 #include "Chrome.h"
     38 #include "ContextMenu.h"
     39 #include "ContextMenuController.h"
     40 #include "ContextMenuItem.h"
     41 #include "CSSStyleSelector.h"
     42 #include "CSSValueKeywords.h"
     43 #include "Cursor.h"
     44 #include "Document.h"
     45 #include "DocumentLoader.h"
     46 #include "DOMUtilitiesPrivate.h"
     47 #include "DragController.h"
     48 #include "DragData.h"
     49 #include "Editor.h"
     50 #include "EventHandler.h"
     51 #include "FocusController.h"
     52 #include "FontDescription.h"
     53 #include "FrameLoader.h"
     54 #include "FrameTree.h"
     55 #include "FrameView.h"
     56 #include "GraphicsContext.h"
     57 #include "HitTestResult.h"
     58 #include "HTMLInputElement.h"
     59 #include "HTMLMediaElement.h"
     60 #include "HTMLNames.h"
     61 #include "Image.h"
     62 #include "InspectorController.h"
     63 #include "IntRect.h"
     64 #include "KeyboardCodes.h"
     65 #include "KeyboardEvent.h"
     66 #include "MIMETypeRegistry.h"
     67 #include "NodeRenderStyle.h"
     68 #include "Page.h"
     69 #include "PageGroup.h"
     70 #include "PageGroupLoadDeferrer.h"
     71 #include "Pasteboard.h"
     72 #include "PlatformContextSkia.h"
     73 #include "PlatformKeyboardEvent.h"
     74 #include "PlatformMouseEvent.h"
     75 #include "PlatformWheelEvent.h"
     76 #include "PluginInfoStore.h"
     77 #include "PopupMenuChromium.h"
     78 #include "PopupMenuClient.h"
     79 #include "ProgressTracker.h"
     80 #include "RenderView.h"
     81 #include "ResourceHandle.h"
     82 #include "SecurityOrigin.h"
     83 #include "SelectionController.h"
     84 #include "Settings.h"
     85 #include "TypingCommand.h"
     86 #include "WebAccessibilityObject.h"
     87 #include "WebDevToolsAgentPrivate.h"
     88 #include "WebDragData.h"
     89 #include "WebFrameImpl.h"
     90 #include "WebInputEvent.h"
     91 #include "WebInputEventConversion.h"
     92 #include "WebMediaPlayerAction.h"
     93 #include "WebNode.h"
     94 #include "WebPoint.h"
     95 #include "WebPopupMenuImpl.h"
     96 #include "WebRect.h"
     97 #include "WebSettingsImpl.h"
     98 #include "WebString.h"
     99 #include "WebVector.h"
    100 #include "WebViewClient.h"
    101 
    102 #if OS(WINDOWS)
    103 #include "KeyboardCodesWin.h"
    104 #include "RenderThemeChromiumWin.h"
    105 #else
    106 #if OS(LINUX)
    107 #include "RenderThemeChromiumLinux.h"
    108 #endif
    109 #include "KeyboardCodesPosix.h"
    110 #include "RenderTheme.h"
    111 #endif
    112 
    113 // Get rid of WTF's pow define so we can use std::pow.
    114 #undef pow
    115 #include <cmath> // for std::pow
    116 
    117 using namespace WebCore;
    118 
    119 namespace WebKit {
    120 
    121 // Change the text zoom level by kTextSizeMultiplierRatio each time the user
    122 // zooms text in or out (ie., change by 20%).  The min and max values limit
    123 // text zoom to half and 3x the original text size.  These three values match
    124 // those in Apple's port in WebKit/WebKit/WebView/WebView.mm
    125 static const double textSizeMultiplierRatio = 1.2;
    126 static const double minTextSizeMultiplier = 0.5;
    127 static const double maxTextSizeMultiplier = 3.0;
    128 
    129 // The group name identifies a namespace of pages.  Page group is used on OSX
    130 // for some programs that use HTML views to display things that don't seem like
    131 // web pages to the user (so shouldn't have visited link coloring).  We only use
    132 // one page group.
    133 const char* pageGroupName = "default";
    134 
    135 // Used to defer all page activity in cases where the embedder wishes to run
    136 // a nested event loop.
    137 static PageGroupLoadDeferrer* pageGroupLoadDeferrer;
    138 
    139 // Ensure that the WebDragOperation enum values stay in sync with the original
    140 // DragOperation constants.
    141 #define COMPILE_ASSERT_MATCHING_ENUM(coreName) \
    142     COMPILE_ASSERT(int(coreName) == int(Web##coreName), dummy##coreName)
    143 COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone);
    144 COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy);
    145 COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink);
    146 COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric);
    147 COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate);
    148 COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove);
    149 COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete);
    150 COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery);
    151 
    152 // Note that focusOnShow is false so that the suggestions popup is shown not
    153 // activated.  We need the page to still have focus so the user can keep typing
    154 // while the popup is showing.
    155 static const PopupContainerSettings suggestionsPopupSettings = {
    156     false,  // focusOnShow
    157     false,  // setTextOnIndexChange
    158     false,  // acceptOnAbandon
    159     true,   // loopSelectionNavigation
    160     true,   // restrictWidthOfListBox. Same as other browser (Fx, IE, and safari)
    161     // For suggestions, we use the direction of the input field as the direction
    162     // of the popup items. The main reason is to keep the display of items in
    163     // drop-down the same as the items in the input field.
    164     PopupContainerSettings::DOMElementDirection,
    165 };
    166 
    167 // WebView ----------------------------------------------------------------
    168 
    169 WebView* WebView::create(WebViewClient* client)
    170 {
    171     return new WebViewImpl(client);
    172 }
    173 
    174 void WebView::updateVisitedLinkState(unsigned long long linkHash)
    175 {
    176     Page::visitedStateChanged(PageGroup::pageGroup(pageGroupName), linkHash);
    177 }
    178 
    179 void WebView::resetVisitedLinkState()
    180 {
    181     Page::allVisitedStateChanged(PageGroup::pageGroup(pageGroupName));
    182 }
    183 
    184 void WebView::willEnterModalLoop()
    185 {
    186     // It is not valid to nest more than once.
    187     ASSERT(!pageGroupLoadDeferrer);
    188 
    189     PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
    190     ASSERT(pageGroup);
    191     ASSERT(!pageGroup->pages().isEmpty());
    192 
    193     // Pick any page in the page group since we are deferring all pages.
    194     pageGroupLoadDeferrer = new PageGroupLoadDeferrer(*pageGroup->pages().begin(), true);
    195 }
    196 
    197 void WebView::didExitModalLoop()
    198 {
    199     // The embedder must have called willEnterNestedEventLoop.
    200     ASSERT(pageGroupLoadDeferrer);
    201 
    202     delete pageGroupLoadDeferrer;
    203     pageGroupLoadDeferrer = 0;
    204 }
    205 
    206 void WebViewImpl::initializeMainFrame(WebFrameClient* frameClient)
    207 {
    208     // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame
    209     // and releases that reference once the corresponding Frame is destroyed.
    210     RefPtr<WebFrameImpl> frame = WebFrameImpl::create(frameClient);
    211 
    212     frame->initializeAsMainFrame(this);
    213 
    214     // Restrict the access to the local file system
    215     // (see WebView.mm WebView::_commonInitializationWithFrameName).
    216     SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForLocalOnly);
    217 }
    218 
    219 WebViewImpl::WebViewImpl(WebViewClient* client)
    220     : m_client(client)
    221     , m_backForwardListClientImpl(this)
    222     , m_chromeClientImpl(this)
    223     , m_contextMenuClientImpl(this)
    224     , m_dragClientImpl(this)
    225     , m_editorClientImpl(this)
    226     , m_inspectorClientImpl(this)
    227     , m_observedNewNavigation(false)
    228 #ifndef NDEBUG
    229     , m_newNavigationLoader(0)
    230 #endif
    231     , m_zoomLevel(0)
    232     , m_contextMenuAllowed(false)
    233     , m_doingDragAndDrop(false)
    234     , m_ignoreInputEvents(false)
    235     , m_suppressNextKeypressEvent(false)
    236     , m_initialNavigationPolicy(WebNavigationPolicyIgnore)
    237     , m_imeAcceptEvents(true)
    238     , m_dragTargetDispatch(false)
    239     , m_dragIdentity(0)
    240     , m_dropEffect(DropEffectDefault)
    241     , m_operationsAllowed(WebDragOperationNone)
    242     , m_dragOperation(WebDragOperationNone)
    243     , m_suggestionsPopupShowing(false)
    244     , m_suggestionsPopupClient(0)
    245     , m_suggestionsPopup(0)
    246     , m_isTransparent(false)
    247     , m_tabsToLinks(false)
    248 {
    249     // WebKit/win/WebView.cpp does the same thing, except they call the
    250     // KJS specific wrapper around this method. We need to have threading
    251     // initialized because CollatorICU requires it.
    252     WTF::initializeThreading();
    253 
    254     // set to impossible point so we always get the first mouse pos
    255     m_lastMousePosition = WebPoint(-1, -1);
    256 
    257     // the page will take ownership of the various clients
    258     m_page.set(new Page(&m_chromeClientImpl,
    259                         &m_contextMenuClientImpl,
    260                         &m_editorClientImpl,
    261                         &m_dragClientImpl,
    262                         &m_inspectorClientImpl,
    263                         0,
    264                         0));
    265 
    266     m_page->backForwardList()->setClient(&m_backForwardListClientImpl);
    267     m_page->setGroupName(pageGroupName);
    268 }
    269 
    270 WebViewImpl::~WebViewImpl()
    271 {
    272     ASSERT(!m_page);
    273 }
    274 
    275 RenderTheme* WebViewImpl::theme() const
    276 {
    277     return m_page.get() ? m_page->theme() : RenderTheme::defaultTheme().get();
    278 }
    279 
    280 WebFrameImpl* WebViewImpl::mainFrameImpl()
    281 {
    282     return m_page.get() ? WebFrameImpl::fromFrame(m_page->mainFrame()) : 0;
    283 }
    284 
    285 bool WebViewImpl::tabKeyCyclesThroughElements() const
    286 {
    287     ASSERT(m_page.get());
    288     return m_page->tabKeyCyclesThroughElements();
    289 }
    290 
    291 void WebViewImpl::setTabKeyCyclesThroughElements(bool value)
    292 {
    293     if (m_page)
    294         m_page->setTabKeyCyclesThroughElements(value);
    295 }
    296 
    297 void WebViewImpl::mouseMove(const WebMouseEvent& event)
    298 {
    299     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
    300         return;
    301 
    302     m_lastMousePosition = WebPoint(event.x, event.y);
    303 
    304     // We call mouseMoved here instead of handleMouseMovedEvent because we need
    305     // our ChromeClientImpl to receive changes to the mouse position and
    306     // tooltip text, and mouseMoved handles all of that.
    307     mainFrameImpl()->frame()->eventHandler()->mouseMoved(
    308         PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
    309 }
    310 
    311 void WebViewImpl::mouseLeave(const WebMouseEvent& event)
    312 {
    313     // This event gets sent as the main frame is closing.  In that case, just
    314     // ignore it.
    315     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
    316         return;
    317 
    318     m_client->setMouseOverURL(WebURL());
    319 
    320     mainFrameImpl()->frame()->eventHandler()->handleMouseMoveEvent(
    321         PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
    322 }
    323 
    324 void WebViewImpl::mouseDown(const WebMouseEvent& event)
    325 {
    326     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
    327         return;
    328 
    329     m_lastMouseDownPoint = WebPoint(event.x, event.y);
    330 
    331     // If a text field that has focus is clicked again, we should display the
    332     // suggestions popup.
    333     RefPtr<Node> clickedNode;
    334     if (event.button == WebMouseEvent::ButtonLeft) {
    335         RefPtr<Node> focusedNode = focusedWebCoreNode();
    336         if (focusedNode.get() && toHTMLInputElement(focusedNode.get())) {
    337             IntPoint point(event.x, event.y);
    338             point = m_page->mainFrame()->view()->windowToContents(point);
    339             HitTestResult result(point);
    340             result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, false);
    341             if (result.innerNonSharedNode() == focusedNode) {
    342                 // Already focused text field was clicked, let's remember this.  If
    343                 // focus has not changed after the mouse event is processed, we'll
    344                 // trigger the autocomplete.
    345                 clickedNode = focusedNode;
    346             }
    347         }
    348     }
    349 
    350     mainFrameImpl()->frame()->eventHandler()->handleMousePressEvent(
    351         PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
    352 
    353     if (clickedNode.get() && clickedNode == focusedWebCoreNode()) {
    354         // Focus has not changed, show the suggestions popup.
    355         static_cast<EditorClientImpl*>(m_page->editorClient())->
    356             showFormAutofillForNode(clickedNode.get());
    357     }
    358 
    359     // Dispatch the contextmenu event regardless of if the click was swallowed.
    360     // On Windows, we handle it on mouse up, not down.
    361 #if OS(DARWIN)
    362     if (event.button == WebMouseEvent::ButtonRight
    363         || (event.button == WebMouseEvent::ButtonLeft
    364             && event.modifiers & WebMouseEvent::ControlKey))
    365         mouseContextMenu(event);
    366 #elif OS(LINUX)
    367     if (event.button == WebMouseEvent::ButtonRight)
    368         mouseContextMenu(event);
    369 #endif
    370 }
    371 
    372 void WebViewImpl::mouseContextMenu(const WebMouseEvent& event)
    373 {
    374     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
    375         return;
    376 
    377     m_page->contextMenuController()->clearContextMenu();
    378 
    379     PlatformMouseEventBuilder pme(mainFrameImpl()->frameView(), event);
    380 
    381     // Find the right target frame. See issue 1186900.
    382     HitTestResult result = hitTestResultForWindowPos(pme.pos());
    383     Frame* targetFrame;
    384     if (result.innerNonSharedNode())
    385         targetFrame = result.innerNonSharedNode()->document()->frame();
    386     else
    387         targetFrame = m_page->focusController()->focusedOrMainFrame();
    388 
    389 #if OS(WINDOWS)
    390     targetFrame->view()->setCursor(pointerCursor());
    391 #endif
    392 
    393     m_contextMenuAllowed = true;
    394     targetFrame->eventHandler()->sendContextMenuEvent(pme);
    395     m_contextMenuAllowed = false;
    396     // Actually showing the context menu is handled by the ContextMenuClient
    397     // implementation...
    398 }
    399 
    400 void WebViewImpl::mouseUp(const WebMouseEvent& event)
    401 {
    402     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
    403         return;
    404 
    405 #if OS(LINUX)
    406     // If the event was a middle click, attempt to copy text into the focused
    407     // frame. We execute this before we let the page have a go at the event
    408     // because the page may change what is focused during in its event handler.
    409     //
    410     // This code is in the mouse up handler. There is some debate about putting
    411     // this here, as opposed to the mouse down handler.
    412     //   xterm: pastes on up.
    413     //   GTK: pastes on down.
    414     //   Firefox: pastes on up.
    415     //   Midori: couldn't paste at all with 0.1.2
    416     //
    417     // There is something of a webcompat angle to this well, as highlighted by
    418     // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
    419     // down then the text is pasted just before the onclick handler runs and
    420     // clears the text box. So it's important this happens after the
    421     // handleMouseReleaseEvent() earlier in this function
    422     if (event.button == WebMouseEvent::ButtonMiddle) {
    423         Frame* focused = focusedWebCoreFrame();
    424         FrameView* view = m_page->mainFrame()->view();
    425         IntPoint clickPoint(m_lastMouseDownPoint.x, m_lastMouseDownPoint.y);
    426         IntPoint contentPoint = view->windowToContents(clickPoint);
    427         HitTestResult hitTestResult = focused->eventHandler()->hitTestResultAtPoint(contentPoint, false, false, ShouldHitTestScrollbars);
    428         // We don't want to send a paste when middle clicking a scroll bar or a
    429         // link (which will navigate later in the code).  The main scrollbars
    430         // have to be handled separately.
    431         if (!hitTestResult.scrollbar() && !hitTestResult.isLiveLink() && focused && !view->scrollbarAtPoint(clickPoint)) {
    432             Editor* editor = focused->editor();
    433             Pasteboard* pasteboard = Pasteboard::generalPasteboard();
    434             bool oldSelectionMode = pasteboard->isSelectionMode();
    435             pasteboard->setSelectionMode(true);
    436             editor->command(AtomicString("Paste")).execute();
    437             pasteboard->setSelectionMode(oldSelectionMode);
    438         }
    439     }
    440 #endif
    441 
    442     mouseCaptureLost();
    443     mainFrameImpl()->frame()->eventHandler()->handleMouseReleaseEvent(
    444         PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
    445 
    446 #if OS(WINDOWS)
    447     // Dispatch the contextmenu event regardless of if the click was swallowed.
    448     // On Mac/Linux, we handle it on mouse down, not up.
    449     if (event.button == WebMouseEvent::ButtonRight)
    450         mouseContextMenu(event);
    451 #endif
    452 }
    453 
    454 void WebViewImpl::mouseWheel(const WebMouseWheelEvent& event)
    455 {
    456     PlatformWheelEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
    457     mainFrameImpl()->frame()->eventHandler()->handleWheelEvent(platformEvent);
    458 }
    459 
    460 bool WebViewImpl::keyEvent(const WebKeyboardEvent& event)
    461 {
    462     ASSERT((event.type == WebInputEvent::RawKeyDown)
    463         || (event.type == WebInputEvent::KeyDown)
    464         || (event.type == WebInputEvent::KeyUp));
    465 
    466     // Please refer to the comments explaining the m_suppressNextKeypressEvent
    467     // member.
    468     // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
    469     // Webkit. A keyDown event is typically associated with a keyPress(char)
    470     // event and a keyUp event. We reset this flag here as this is a new keyDown
    471     // event.
    472     m_suppressNextKeypressEvent = false;
    473 
    474     // Give Autocomplete a chance to consume the key events it is interested in.
    475     if (autocompleteHandleKeyEvent(event))
    476         return true;
    477 
    478     Frame* frame = focusedWebCoreFrame();
    479     if (!frame)
    480         return false;
    481 
    482     EventHandler* handler = frame->eventHandler();
    483     if (!handler)
    484         return keyEventDefault(event);
    485 
    486 #if OS(WINDOWS) || OS(LINUX)
    487     const WebInputEvent::Type contextMenuTriggeringEventType =
    488 #if OS(WINDOWS)
    489         WebInputEvent::KeyUp;
    490 #elif OS(LINUX)
    491         WebInputEvent::RawKeyDown;
    492 #endif
    493 
    494     if (((!event.modifiers && (event.windowsKeyCode == VKEY_APPS))
    495         || ((event.modifiers == WebInputEvent::ShiftKey) && (event.windowsKeyCode == VKEY_F10)))
    496         && event.type == contextMenuTriggeringEventType) {
    497         sendContextMenuEvent(event);
    498         return true;
    499     }
    500 #endif
    501 
    502     // It's not clear if we should continue after detecting a capslock keypress.
    503     // I'll err on the side of continuing, which is the pre-existing behaviour.
    504     if (event.windowsKeyCode == VKEY_CAPITAL)
    505         handler->capsLockStateMayHaveChanged();
    506 
    507     PlatformKeyboardEventBuilder evt(event);
    508 
    509     if (handler->keyEvent(evt)) {
    510         if (WebInputEvent::RawKeyDown == event.type)
    511             m_suppressNextKeypressEvent = true;
    512         return true;
    513     }
    514 
    515     return keyEventDefault(event);
    516 }
    517 
    518 bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event)
    519 {
    520     if (!m_suggestionsPopupShowing
    521         // Home and End should be left to the text field to process.
    522         || event.windowsKeyCode == VKEY_HOME
    523         || event.windowsKeyCode == VKEY_END)
    524       return false;
    525 
    526     // Pressing delete triggers the removal of the selected suggestion from the DB.
    527     if (event.windowsKeyCode == VKEY_DELETE
    528         && m_suggestionsPopup->selectedIndex() != -1) {
    529         Node* node = focusedWebCoreNode();
    530         if (!node || (node->nodeType() != Node::ELEMENT_NODE)) {
    531             ASSERT_NOT_REACHED();
    532             return false;
    533         }
    534         Element* element = static_cast<Element*>(node);
    535         if (!element->hasLocalName(HTMLNames::inputTag)) {
    536             ASSERT_NOT_REACHED();
    537             return false;
    538         }
    539 
    540         int selectedIndex = m_suggestionsPopup->selectedIndex();
    541         HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(element);
    542         WebString name = inputElement->name();
    543         WebString value = m_autocompletePopupClient->itemText(selectedIndex);
    544         m_client->removeAutofillSuggestions(name, value);
    545         // Update the entries in the currently showing popup to reflect the
    546         // deletion.
    547         m_autocompletePopupClient->removeSuggestionAtIndex(selectedIndex);
    548         refreshSuggestionsPopup();
    549         return false;
    550     }
    551 
    552     if (!m_suggestionsPopup->isInterestedInEventForKey(event.windowsKeyCode))
    553         return false;
    554 
    555     if (m_suggestionsPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) {
    556         // We need to ignore the next Char event after this otherwise pressing
    557         // enter when selecting an item in the menu will go to the page.
    558         if (WebInputEvent::RawKeyDown == event.type)
    559             m_suppressNextKeypressEvent = true;
    560         return true;
    561     }
    562 
    563     return false;
    564 }
    565 
    566 bool WebViewImpl::charEvent(const WebKeyboardEvent& event)
    567 {
    568     ASSERT(event.type == WebInputEvent::Char);
    569 
    570     // Please refer to the comments explaining the m_suppressNextKeypressEvent
    571     // member.  The m_suppressNextKeypressEvent is set if the KeyDown is
    572     // handled by Webkit. A keyDown event is typically associated with a
    573     // keyPress(char) event and a keyUp event. We reset this flag here as it
    574     // only applies to the current keyPress event.
    575     bool suppress = m_suppressNextKeypressEvent;
    576     m_suppressNextKeypressEvent = false;
    577 
    578     Frame* frame = focusedWebCoreFrame();
    579     if (!frame)
    580         return suppress;
    581 
    582     EventHandler* handler = frame->eventHandler();
    583     if (!handler)
    584         return suppress || keyEventDefault(event);
    585 
    586     PlatformKeyboardEventBuilder evt(event);
    587     if (!evt.isCharacterKey())
    588         return true;
    589 
    590     // Accesskeys are triggered by char events and can't be suppressed.
    591     if (handler->handleAccessKey(evt))
    592         return true;
    593 
    594     // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
    595     // the eventHandler::keyEvent. We mimic this behavior on all platforms since
    596     // for now we are converting other platform's key events to windows key
    597     // events.
    598     if (evt.isSystemKey())
    599         return false;
    600 
    601     if (!suppress && !handler->keyEvent(evt))
    602         return keyEventDefault(event);
    603 
    604     return true;
    605 }
    606 
    607 // The WebViewImpl::SendContextMenuEvent function is based on the Webkit
    608 // function
    609 // bool WebView::handleContextMenuEvent(WPARAM wParam, LPARAM lParam) in
    610 // webkit\webkit\win\WebView.cpp. The only significant change in this
    611 // function is the code to convert from a Keyboard event to the Right
    612 // Mouse button up event.
    613 //
    614 // This function is an ugly copy/paste and should be cleaned up when the
    615 // WebKitWin version is cleaned: https://bugs.webkit.org/show_bug.cgi?id=20438
    616 #if OS(WINDOWS) || OS(LINUX)
    617 // FIXME: implement on Mac
    618 bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event)
    619 {
    620     static const int kContextMenuMargin = 1;
    621     Frame* mainFrameImpl = page()->mainFrame();
    622     FrameView* view = mainFrameImpl->view();
    623     if (!view)
    624         return false;
    625 
    626     IntPoint coords(-1, -1);
    627 #if OS(WINDOWS)
    628     int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
    629 #else
    630     int rightAligned = 0;
    631 #endif
    632     IntPoint location;
    633 
    634 
    635     Frame* focusedFrame = page()->focusController()->focusedOrMainFrame();
    636     Node* focusedNode = focusedFrame->document()->focusedNode();
    637     Position start = mainFrameImpl->selection()->selection().start();
    638 
    639     if (focusedFrame->editor() && focusedFrame->editor()->canEdit() && start.node()) {
    640         RenderObject* renderer = start.node()->renderer();
    641         if (!renderer)
    642             return false;
    643 
    644         RefPtr<Range> selection = mainFrameImpl->selection()->toNormalizedRange();
    645         IntRect firstRect = mainFrameImpl->firstRectForRange(selection.get());
    646 
    647         int x = rightAligned ? firstRect.right() : firstRect.x();
    648         location = IntPoint(x, firstRect.bottom());
    649     } else if (focusedNode)
    650         location = focusedNode->getRect().bottomLeft();
    651     else {
    652         location = IntPoint(
    653             rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
    654             kContextMenuMargin);
    655     }
    656 
    657     location = view->contentsToWindow(location);
    658     // FIXME: The IntSize(0, -1) is a hack to get the hit-testing to result in
    659     // the selected element. Ideally we'd have the position of a context menu
    660     // event be separate from its target node.
    661     coords = location + IntSize(0, -1);
    662 
    663     // The contextMenuController() holds onto the last context menu that was
    664     // popped up on the page until a new one is created. We need to clear
    665     // this menu before propagating the event through the DOM so that we can
    666     // detect if we create a new menu for this event, since we won't create
    667     // a new menu if the DOM swallows the event and the defaultEventHandler does
    668     // not run.
    669     page()->contextMenuController()->clearContextMenu();
    670 
    671     focusedFrame->view()->setCursor(pointerCursor());
    672     WebMouseEvent mouseEvent;
    673     mouseEvent.button = WebMouseEvent::ButtonRight;
    674     mouseEvent.x = coords.x();
    675     mouseEvent.y = coords.y();
    676     mouseEvent.type = WebInputEvent::MouseUp;
    677 
    678     PlatformMouseEventBuilder platformEvent(view, mouseEvent);
    679 
    680     m_contextMenuAllowed = true;
    681     bool handled = focusedFrame->eventHandler()->sendContextMenuEvent(platformEvent);
    682     m_contextMenuAllowed = false;
    683     return handled;
    684 }
    685 #endif
    686 
    687 bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event)
    688 {
    689     Frame* frame = focusedWebCoreFrame();
    690     if (!frame)
    691         return false;
    692 
    693     switch (event.type) {
    694     case WebInputEvent::Char:
    695         if (event.windowsKeyCode == VKEY_SPACE) {
    696             int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT);
    697             return scrollViewWithKeyboard(keyCode, event.modifiers);
    698         }
    699         break;
    700     case WebInputEvent::RawKeyDown:
    701         if (event.modifiers == WebInputEvent::ControlKey) {
    702             switch (event.windowsKeyCode) {
    703 #if !OS(DARWIN)
    704             case 'A':
    705                 focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll"));
    706                 return true;
    707             case VKEY_INSERT:
    708             case 'C':
    709                 focusedFrame()->executeCommand(WebString::fromUTF8("Copy"));
    710                 return true;
    711 #endif
    712             // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
    713             // key combinations which affect scrolling. Safari is buggy in the
    714             // sense that it scrolls the page for all Ctrl+scrolling key
    715             // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
    716             case VKEY_HOME:
    717             case VKEY_END:
    718                 break;
    719             default:
    720                 return false;
    721             }
    722         }
    723         if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey))
    724             return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers);
    725         break;
    726     default:
    727         break;
    728     }
    729     return false;
    730 }
    731 
    732 bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers)
    733 {
    734     ScrollDirection scrollDirection;
    735     ScrollGranularity scrollGranularity;
    736 
    737     switch (keyCode) {
    738     case VKEY_LEFT:
    739         scrollDirection = ScrollLeft;
    740         scrollGranularity = ScrollByLine;
    741         break;
    742     case VKEY_RIGHT:
    743         scrollDirection = ScrollRight;
    744         scrollGranularity = ScrollByLine;
    745         break;
    746     case VKEY_UP:
    747         scrollDirection = ScrollUp;
    748         scrollGranularity = ScrollByLine;
    749         break;
    750     case VKEY_DOWN:
    751         scrollDirection = ScrollDown;
    752         scrollGranularity = ScrollByLine;
    753         break;
    754     case VKEY_HOME:
    755         scrollDirection = ScrollUp;
    756         scrollGranularity = ScrollByDocument;
    757         break;
    758     case VKEY_END:
    759         scrollDirection = ScrollDown;
    760         scrollGranularity = ScrollByDocument;
    761         break;
    762     case VKEY_PRIOR:  // page up
    763         scrollDirection = ScrollUp;
    764         scrollGranularity = ScrollByPage;
    765         break;
    766     case VKEY_NEXT:  // page down
    767         scrollDirection = ScrollDown;
    768         scrollGranularity = ScrollByPage;
    769         break;
    770     default:
    771         return false;
    772     }
    773 
    774     return propagateScroll(scrollDirection, scrollGranularity);
    775 }
    776 
    777 bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection,
    778                                   ScrollGranularity scrollGranularity)
    779 {
    780     Frame* frame = focusedWebCoreFrame();
    781     if (!frame)
    782         return false;
    783 
    784     bool scrollHandled =
    785         frame->eventHandler()->scrollOverflow(scrollDirection,
    786                                               scrollGranularity);
    787     Frame* currentFrame = frame;
    788     while (!scrollHandled && currentFrame) {
    789         scrollHandled = currentFrame->view()->scroll(scrollDirection,
    790                                                      scrollGranularity);
    791         currentFrame = currentFrame->tree()->parent();
    792     }
    793     return scrollHandled;
    794 }
    795 
    796 Frame* WebViewImpl::focusedWebCoreFrame()
    797 {
    798     return m_page.get() ? m_page->focusController()->focusedOrMainFrame() : 0;
    799 }
    800 
    801 WebViewImpl* WebViewImpl::fromPage(Page* page)
    802 {
    803     if (!page)
    804         return 0;
    805 
    806     return static_cast<ChromeClientImpl*>(page->chrome()->client())->webView();
    807 }
    808 
    809 // WebWidget ------------------------------------------------------------------
    810 
    811 void WebViewImpl::close()
    812 {
    813     RefPtr<WebFrameImpl> mainFrameImpl;
    814 
    815     if (m_page.get()) {
    816         // Initiate shutdown for the entire frameset.  This will cause a lot of
    817         // notifications to be sent.
    818         if (m_page->mainFrame()) {
    819             mainFrameImpl = WebFrameImpl::fromFrame(m_page->mainFrame());
    820             m_page->mainFrame()->loader()->frameDetached();
    821         }
    822         m_page.clear();
    823     }
    824 
    825     // Should happen after m_page.clear().
    826     if (m_devToolsAgent.get())
    827         m_devToolsAgent.clear();
    828 
    829     // Reset the delegate to prevent notifications being sent as we're being
    830     // deleted.
    831     m_client = 0;
    832 
    833     deref();  // Balances ref() acquired in WebView::create
    834 }
    835 
    836 void WebViewImpl::resize(const WebSize& newSize)
    837 {
    838     if (m_size == newSize)
    839         return;
    840     m_size = newSize;
    841 
    842     if (mainFrameImpl()->frameView()) {
    843         mainFrameImpl()->frameView()->resize(m_size.width, m_size.height);
    844         mainFrameImpl()->frame()->eventHandler()->sendResizeEvent();
    845     }
    846 
    847     if (m_client) {
    848         WebRect damagedRect(0, 0, m_size.width, m_size.height);
    849         m_client->didInvalidateRect(damagedRect);
    850     }
    851 }
    852 
    853 void WebViewImpl::layout()
    854 {
    855     WebFrameImpl* webframe = mainFrameImpl();
    856     if (webframe) {
    857         // In order for our child HWNDs (NativeWindowWidgets) to update properly,
    858         // they need to be told that we are updating the screen.  The problem is
    859         // that the native widgets need to recalculate their clip region and not
    860         // overlap any of our non-native widgets.  To force the resizing, call
    861         // setFrameRect().  This will be a quick operation for most frames, but
    862         // the NativeWindowWidgets will update a proper clipping region.
    863         FrameView* view = webframe->frameView();
    864         if (view)
    865             view->setFrameRect(view->frameRect());
    866 
    867         // setFrameRect may have the side-effect of causing existing page
    868         // layout to be invalidated, so layout needs to be called last.
    869 
    870         webframe->layout();
    871     }
    872 }
    873 
    874 void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect)
    875 {
    876     WebFrameImpl* webframe = mainFrameImpl();
    877     if (webframe)
    878         webframe->paint(canvas, rect);
    879 }
    880 
    881 // FIXME: m_currentInputEvent should be removed once ChromeClient::show() can
    882 // get the current-event information from WebCore.
    883 const WebInputEvent* WebViewImpl::m_currentInputEvent = 0;
    884 
    885 bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
    886 {
    887     // If we've started a drag and drop operation, ignore input events until
    888     // we're done.
    889     if (m_doingDragAndDrop)
    890         return true;
    891 
    892     if (m_ignoreInputEvents)
    893         return true;
    894 
    895     // FIXME: Remove m_currentInputEvent.
    896     // This only exists to allow ChromeClient::show() to know which mouse button
    897     // triggered a window.open event.
    898     // Safari must perform a similar hack, ours is in our WebKit glue layer
    899     // theirs is in the application.  This should go when WebCore can be fixed
    900     // to pass more event information to ChromeClient::show()
    901     m_currentInputEvent = &inputEvent;
    902 
    903     bool handled = true;
    904 
    905     // FIXME: WebKit seems to always return false on mouse events processing
    906     // methods. For now we'll assume it has processed them (as we are only
    907     // interested in whether keyboard events are processed).
    908     switch (inputEvent.type) {
    909     case WebInputEvent::MouseMove:
    910         mouseMove(*static_cast<const WebMouseEvent*>(&inputEvent));
    911         break;
    912 
    913     case WebInputEvent::MouseLeave:
    914         mouseLeave(*static_cast<const WebMouseEvent*>(&inputEvent));
    915         break;
    916 
    917     case WebInputEvent::MouseWheel:
    918         mouseWheel(*static_cast<const WebMouseWheelEvent*>(&inputEvent));
    919         break;
    920 
    921     case WebInputEvent::MouseDown:
    922         mouseDown(*static_cast<const WebMouseEvent*>(&inputEvent));
    923         break;
    924 
    925     case WebInputEvent::MouseUp:
    926         mouseUp(*static_cast<const WebMouseEvent*>(&inputEvent));
    927         break;
    928 
    929     case WebInputEvent::RawKeyDown:
    930     case WebInputEvent::KeyDown:
    931     case WebInputEvent::KeyUp:
    932         handled = keyEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent));
    933         break;
    934 
    935     case WebInputEvent::Char:
    936         handled = charEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent));
    937         break;
    938 
    939     default:
    940         handled = false;
    941     }
    942 
    943     m_currentInputEvent = 0;
    944 
    945     return handled;
    946 }
    947 
    948 void WebViewImpl::mouseCaptureLost()
    949 {
    950 }
    951 
    952 void WebViewImpl::setFocus(bool enable)
    953 {
    954     m_page->focusController()->setFocused(enable);
    955     if (enable) {
    956         // Note that we don't call setActive() when disabled as this cause extra
    957         // focus/blur events to be dispatched.
    958         m_page->focusController()->setActive(true);
    959         RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
    960         if (focusedFrame) {
    961             Node* focusedNode = focusedFrame->document()->focusedNode();
    962             if (focusedNode && focusedNode->isElementNode()
    963                 && focusedFrame->selection()->selection().isNone()) {
    964                 // If the selection was cleared while the WebView was not
    965                 // focused, then the focus element shows with a focus ring but
    966                 // no caret and does respond to keyboard inputs.
    967                 Element* element = static_cast<Element*>(focusedNode);
    968                 if (element->isTextFormControl())
    969                     element->updateFocusAppearance(true);
    970                 else if (focusedNode->isContentEditable()) {
    971                     // updateFocusAppearance() selects all the text of
    972                     // contentseditable DIVs. So we set the selection explicitly
    973                     // instead. Note that this has the side effect of moving the
    974                     // caret back to the beginning of the text.
    975                     Position position(focusedNode, 0,
    976                                       Position::PositionIsOffsetInAnchor);
    977                     focusedFrame->selection()->setSelection(
    978                         VisibleSelection(position, SEL_DEFAULT_AFFINITY));
    979                 }
    980             }
    981         }
    982         m_imeAcceptEvents = true;
    983     } else {
    984         hideSuggestionsPopup();
    985 
    986         // Clear focus on the currently focused frame if any.
    987         if (!m_page.get())
    988             return;
    989 
    990         Frame* frame = m_page->mainFrame();
    991         if (!frame)
    992             return;
    993 
    994         RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
    995         if (focusedFrame.get()) {
    996             // Finish an ongoing composition to delete the composition node.
    997             Editor* editor = focusedFrame->editor();
    998             if (editor && editor->hasComposition())
    999                 editor->confirmComposition();
   1000             m_imeAcceptEvents = false;
   1001         }
   1002     }
   1003 }
   1004 
   1005 bool WebViewImpl::handleCompositionEvent(WebCompositionCommand command,
   1006                                          int cursorPosition,
   1007                                          int targetStart,
   1008                                          int targetEnd,
   1009                                          const WebString& imeString)
   1010 {
   1011     Frame* focused = focusedWebCoreFrame();
   1012     if (!focused || !m_imeAcceptEvents)
   1013         return false;
   1014     Editor* editor = focused->editor();
   1015     if (!editor)
   1016         return false;
   1017     if (!editor->canEdit()) {
   1018         // The input focus has been moved to another WebWidget object.
   1019         // We should use this |editor| object only to complete the ongoing
   1020         // composition.
   1021         if (!editor->hasComposition())
   1022             return false;
   1023     }
   1024 
   1025     // We should verify the parent node of this IME composition node are
   1026     // editable because JavaScript may delete a parent node of the composition
   1027     // node. In this case, WebKit crashes while deleting texts from the parent
   1028     // node, which doesn't exist any longer.
   1029     PassRefPtr<Range> range = editor->compositionRange();
   1030     if (range) {
   1031         const Node* node = range->startPosition().node();
   1032         if (!node || !node->isContentEditable())
   1033             return false;
   1034     }
   1035 
   1036     if (command == WebCompositionCommandDiscard) {
   1037         // A browser process sent an IPC message which does not contain a valid
   1038         // string, which means an ongoing composition has been canceled.
   1039         // If the ongoing composition has been canceled, replace the ongoing
   1040         // composition string with an empty string and complete it.
   1041         String emptyString;
   1042         Vector<CompositionUnderline> emptyUnderlines;
   1043         editor->setComposition(emptyString, emptyUnderlines, 0, 0);
   1044     } else {
   1045         // A browser process sent an IPC message which contains a string to be
   1046         // displayed in this Editor object.
   1047         // To display the given string, set the given string to the
   1048         // m_compositionNode member of this Editor object and display it.
   1049         if (targetStart < 0)
   1050             targetStart = 0;
   1051         if (targetEnd < 0)
   1052             targetEnd = static_cast<int>(imeString.length());
   1053         String compositionString(imeString);
   1054         // Create custom underlines.
   1055         // To emphasize the selection, the selected region uses a solid black
   1056         // for its underline while other regions uses a pale gray for theirs.
   1057         Vector<CompositionUnderline> underlines(3);
   1058         underlines[0].startOffset = 0;
   1059         underlines[0].endOffset = targetStart;
   1060         underlines[0].thick = true;
   1061         underlines[0].color.setRGB(0xd3, 0xd3, 0xd3);
   1062         underlines[1].startOffset = targetStart;
   1063         underlines[1].endOffset = targetEnd;
   1064         underlines[1].thick = true;
   1065         underlines[1].color.setRGB(0x00, 0x00, 0x00);
   1066         underlines[2].startOffset = targetEnd;
   1067         underlines[2].endOffset = static_cast<int>(imeString.length());
   1068         underlines[2].thick = true;
   1069         underlines[2].color.setRGB(0xd3, 0xd3, 0xd3);
   1070         // When we use custom underlines, WebKit ("InlineTextBox.cpp" Line 282)
   1071         // prevents from writing a text in between 'selectionStart' and
   1072         // 'selectionEnd' somehow.
   1073         // Therefore, we use the 'cursorPosition' for these arguments so that
   1074         // there are not any characters in the above region.
   1075         editor->setComposition(compositionString, underlines,
   1076                                cursorPosition, cursorPosition);
   1077         // The given string is a result string, which means the ongoing
   1078         // composition has been completed. I have to call the
   1079         // Editor::confirmCompletion() and complete this composition.
   1080         if (command == WebCompositionCommandConfirm)
   1081             editor->confirmComposition();
   1082     }
   1083 
   1084     return editor->hasComposition();
   1085 }
   1086 
   1087 bool WebViewImpl::queryCompositionStatus(bool* enableIME, WebRect* caretRect)
   1088 {
   1089     // Store whether the selected node needs IME and the caret rectangle.
   1090     // This process consists of the following four steps:
   1091     //  1. Retrieve the selection controller of the focused frame;
   1092     //  2. Retrieve the caret rectangle from the controller;
   1093     //  3. Convert the rectangle, which is relative to the parent view, to the
   1094     //     one relative to the client window, and;
   1095     //  4. Store the converted rectangle.
   1096     const Frame* focused = focusedWebCoreFrame();
   1097     if (!focused)
   1098         return false;
   1099 
   1100     const Editor* editor = focused->editor();
   1101     if (!editor || !editor->canEdit())
   1102         return false;
   1103 
   1104     SelectionController* controller = focused->selection();
   1105     if (!controller)
   1106         return false;
   1107 
   1108     const Node* node = controller->start().node();
   1109     if (!node)
   1110         return false;
   1111 
   1112     *enableIME = node->shouldUseInputMethod() && !controller->isInPasswordField();
   1113     const FrameView* view = node->document()->view();
   1114     if (!view)
   1115         return false;
   1116 
   1117     *caretRect = view->contentsToWindow(controller->absoluteCaretBounds());
   1118     return true;
   1119 }
   1120 
   1121 void WebViewImpl::setTextDirection(WebTextDirection direction)
   1122 {
   1123     // The Editor::setBaseWritingDirection() function checks if we can change
   1124     // the text direction of the selected node and updates its DOM "dir"
   1125     // attribute and its CSS "direction" property.
   1126     // So, we just call the function as Safari does.
   1127     const Frame* focused = focusedWebCoreFrame();
   1128     if (!focused)
   1129         return;
   1130 
   1131     Editor* editor = focused->editor();
   1132     if (!editor || !editor->canEdit())
   1133         return;
   1134 
   1135     switch (direction) {
   1136     case WebTextDirectionDefault:
   1137         editor->setBaseWritingDirection(NaturalWritingDirection);
   1138         break;
   1139 
   1140     case WebTextDirectionLeftToRight:
   1141         editor->setBaseWritingDirection(LeftToRightWritingDirection);
   1142         break;
   1143 
   1144     case WebTextDirectionRightToLeft:
   1145         editor->setBaseWritingDirection(RightToLeftWritingDirection);
   1146         break;
   1147 
   1148     default:
   1149         notImplemented();
   1150         break;
   1151     }
   1152 }
   1153 
   1154 // WebView --------------------------------------------------------------------
   1155 
   1156 WebSettings* WebViewImpl::settings()
   1157 {
   1158     if (!m_webSettings.get())
   1159         m_webSettings.set(new WebSettingsImpl(m_page->settings()));
   1160     ASSERT(m_webSettings.get());
   1161     return m_webSettings.get();
   1162 }
   1163 
   1164 WebString WebViewImpl::pageEncoding() const
   1165 {
   1166     if (!m_page.get())
   1167         return WebString();
   1168 
   1169     return m_page->mainFrame()->loader()->encoding();
   1170 }
   1171 
   1172 void WebViewImpl::setPageEncoding(const WebString& encodingName)
   1173 {
   1174     if (!m_page.get())
   1175         return;
   1176 
   1177     // Only change override encoding, don't change default encoding.
   1178     // Note that the new encoding must be 0 if it isn't supposed to be set.
   1179     String newEncodingName;
   1180     if (!encodingName.isEmpty())
   1181         newEncodingName = encodingName;
   1182     m_page->mainFrame()->loader()->reloadWithOverrideEncoding(newEncodingName);
   1183 }
   1184 
   1185 bool WebViewImpl::dispatchBeforeUnloadEvent()
   1186 {
   1187     // FIXME: This should really cause a recursive depth-first walk of all
   1188     // frames in the tree, calling each frame's onbeforeunload.  At the moment,
   1189     // we're consistent with Safari 3.1, not IE/FF.
   1190     Frame* frame = m_page->mainFrame();
   1191     if (!frame)
   1192         return true;
   1193 
   1194     return frame->shouldClose();
   1195 }
   1196 
   1197 void WebViewImpl::dispatchUnloadEvent()
   1198 {
   1199     // Run unload handlers.
   1200     m_page->mainFrame()->loader()->closeURL();
   1201 }
   1202 
   1203 WebFrame* WebViewImpl::mainFrame()
   1204 {
   1205     return mainFrameImpl();
   1206 }
   1207 
   1208 WebFrame* WebViewImpl::findFrameByName(
   1209     const WebString& name, WebFrame* relativeToFrame)
   1210 {
   1211     if (!relativeToFrame)
   1212         relativeToFrame = mainFrame();
   1213     Frame* frame = static_cast<WebFrameImpl*>(relativeToFrame)->frame();
   1214     frame = frame->tree()->find(name);
   1215     return WebFrameImpl::fromFrame(frame);
   1216 }
   1217 
   1218 WebFrame* WebViewImpl::focusedFrame()
   1219 {
   1220     return WebFrameImpl::fromFrame(focusedWebCoreFrame());
   1221 }
   1222 
   1223 void WebViewImpl::setFocusedFrame(WebFrame* frame)
   1224 {
   1225     if (!frame) {
   1226         // Clears the focused frame if any.
   1227         Frame* frame = focusedWebCoreFrame();
   1228         if (frame)
   1229             frame->selection()->setFocused(false);
   1230         return;
   1231     }
   1232     WebFrameImpl* frameImpl = static_cast<WebFrameImpl*>(frame);
   1233     Frame* webcoreFrame = frameImpl->frame();
   1234     webcoreFrame->page()->focusController()->setFocusedFrame(webcoreFrame);
   1235 }
   1236 
   1237 void WebViewImpl::setInitialFocus(bool reverse)
   1238 {
   1239     if (!m_page.get())
   1240         return;
   1241 
   1242     // Since we don't have a keyboard event, we'll create one.
   1243     WebKeyboardEvent keyboardEvent;
   1244     keyboardEvent.type = WebInputEvent::RawKeyDown;
   1245     if (reverse)
   1246         keyboardEvent.modifiers = WebInputEvent::ShiftKey;
   1247 
   1248     // VK_TAB which is only defined on Windows.
   1249     keyboardEvent.windowsKeyCode = 0x09;
   1250     PlatformKeyboardEventBuilder platformEvent(keyboardEvent);
   1251     RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0);
   1252     page()->focusController()->setInitialFocus(
   1253         reverse ? FocusDirectionBackward : FocusDirectionForward,
   1254         webkitEvent.get());
   1255 }
   1256 
   1257 void WebViewImpl::clearFocusedNode()
   1258 {
   1259     if (!m_page.get())
   1260         return;
   1261 
   1262     RefPtr<Frame> frame = m_page->mainFrame();
   1263     if (!frame.get())
   1264         return;
   1265 
   1266     RefPtr<Document> document = frame->document();
   1267     if (!document.get())
   1268         return;
   1269 
   1270     RefPtr<Node> oldFocusedNode = document->focusedNode();
   1271 
   1272     // Clear the focused node.
   1273     document->setFocusedNode(0);
   1274 
   1275     if (!oldFocusedNode.get())
   1276         return;
   1277 
   1278     // If a text field has focus, we need to make sure the selection controller
   1279     // knows to remove selection from it. Otherwise, the text field is still
   1280     // processing keyboard events even though focus has been moved to the page and
   1281     // keystrokes get eaten as a result.
   1282     if (oldFocusedNode->hasTagName(HTMLNames::textareaTag)
   1283         || (oldFocusedNode->hasTagName(HTMLNames::inputTag)
   1284             && static_cast<HTMLInputElement*>(oldFocusedNode.get())->isTextField())) {
   1285         // Clear the selection.
   1286         SelectionController* selection = frame->selection();
   1287         selection->clear();
   1288     }
   1289 }
   1290 
   1291 int WebViewImpl::zoomLevel()
   1292 {
   1293     return m_zoomLevel;
   1294 }
   1295 
   1296 int WebViewImpl::setZoomLevel(bool textOnly, int zoomLevel)
   1297 {
   1298     float zoomFactor = static_cast<float>(
   1299         std::max(std::min(std::pow(textSizeMultiplierRatio, zoomLevel),
   1300                           maxTextSizeMultiplier),
   1301                  minTextSizeMultiplier));
   1302     Frame* frame = mainFrameImpl()->frame();
   1303     if (zoomFactor != frame->zoomFactor()) {
   1304         m_zoomLevel = zoomLevel;
   1305         frame->setZoomFactor(zoomFactor, textOnly);
   1306     }
   1307     return m_zoomLevel;
   1308 }
   1309 
   1310 void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action,
   1311                                            const WebPoint& location)
   1312 {
   1313     HitTestResult result =
   1314         hitTestResultForWindowPos(location);
   1315     RefPtr<Node> node = result.innerNonSharedNode();
   1316     if (!node->hasTagName(HTMLNames::videoTag) && !node->hasTagName(HTMLNames::audioTag))
   1317       return;
   1318 
   1319     RefPtr<HTMLMediaElement> mediaElement =
   1320         static_pointer_cast<HTMLMediaElement>(node);
   1321     switch (action.type) {
   1322     case WebMediaPlayerAction::Play:
   1323         if (action.enable)
   1324             mediaElement->play(mediaElement->processingUserGesture());
   1325         else
   1326             mediaElement->pause(mediaElement->processingUserGesture());
   1327         break;
   1328     case WebMediaPlayerAction::Mute:
   1329         mediaElement->setMuted(action.enable);
   1330         break;
   1331     case WebMediaPlayerAction::Loop:
   1332         mediaElement->setLoop(action.enable);
   1333         break;
   1334     default:
   1335         ASSERT_NOT_REACHED();
   1336     }
   1337 }
   1338 
   1339 void WebViewImpl::copyImageAt(const WebPoint& point)
   1340 {
   1341     if (!m_page.get())
   1342         return;
   1343 
   1344     HitTestResult result = hitTestResultForWindowPos(point);
   1345 
   1346     if (result.absoluteImageURL().isEmpty()) {
   1347         // There isn't actually an image at these coordinates.  Might be because
   1348         // the window scrolled while the context menu was open or because the page
   1349         // changed itself between when we thought there was an image here and when
   1350         // we actually tried to retreive the image.
   1351         //
   1352         // FIXME: implement a cache of the most recent HitTestResult to avoid having
   1353         //        to do two hit tests.
   1354         return;
   1355     }
   1356 
   1357     m_page->mainFrame()->editor()->copyImage(result);
   1358 }
   1359 
   1360 void WebViewImpl::dragSourceEndedAt(
   1361     const WebPoint& clientPoint,
   1362     const WebPoint& screenPoint,
   1363     WebDragOperation operation)
   1364 {
   1365     PlatformMouseEvent pme(clientPoint,
   1366                            screenPoint,
   1367                            LeftButton, MouseEventMoved, 0, false, false, false,
   1368                            false, 0);
   1369     m_page->mainFrame()->eventHandler()->dragSourceEndedAt(pme,
   1370         static_cast<DragOperation>(operation));
   1371 }
   1372 
   1373 void WebViewImpl::dragSourceSystemDragEnded()
   1374 {
   1375     // It's possible for us to get this callback while not doing a drag if
   1376     // it's from a previous page that got unloaded.
   1377     if (m_doingDragAndDrop) {
   1378         m_page->dragController()->dragEnded();
   1379         m_doingDragAndDrop = false;
   1380     }
   1381 }
   1382 
   1383 WebDragOperation WebViewImpl::dragTargetDragEnter(
   1384     const WebDragData& webDragData, int identity,
   1385     const WebPoint& clientPoint,
   1386     const WebPoint& screenPoint,
   1387     WebDragOperationsMask operationsAllowed)
   1388 {
   1389     ASSERT(!m_currentDragData.get());
   1390 
   1391     m_currentDragData = webDragData;
   1392     m_dragIdentity = identity;
   1393     m_operationsAllowed = operationsAllowed;
   1394 
   1395     DragData dragData(
   1396         m_currentDragData.get(),
   1397         clientPoint,
   1398         screenPoint,
   1399         static_cast<DragOperation>(operationsAllowed));
   1400 
   1401     m_dropEffect = DropEffectDefault;
   1402     m_dragTargetDispatch = true;
   1403     DragOperation effect = m_page->dragController()->dragEntered(&dragData);
   1404     // Mask the operation against the drag source's allowed operations.
   1405     if ((effect & dragData.draggingSourceOperationMask()) != effect)
   1406         effect = DragOperationNone;
   1407     m_dragTargetDispatch = false;
   1408 
   1409     if (m_dropEffect != DropEffectDefault) {
   1410         m_dragOperation = (m_dropEffect != DropEffectNone) ? WebDragOperationCopy
   1411                                                            : WebDragOperationNone;
   1412     } else
   1413         m_dragOperation = static_cast<WebDragOperation>(effect);
   1414     return m_dragOperation;
   1415 }
   1416 
   1417 WebDragOperation WebViewImpl::dragTargetDragOver(
   1418     const WebPoint& clientPoint,
   1419     const WebPoint& screenPoint,
   1420     WebDragOperationsMask operationsAllowed)
   1421 {
   1422     ASSERT(m_currentDragData.get());
   1423 
   1424     m_operationsAllowed = operationsAllowed;
   1425     DragData dragData(
   1426         m_currentDragData.get(),
   1427         clientPoint,
   1428         screenPoint,
   1429         static_cast<DragOperation>(operationsAllowed));
   1430 
   1431     m_dropEffect = DropEffectDefault;
   1432     m_dragTargetDispatch = true;
   1433     DragOperation effect = m_page->dragController()->dragUpdated(&dragData);
   1434     // Mask the operation against the drag source's allowed operations.
   1435     if ((effect & dragData.draggingSourceOperationMask()) != effect)
   1436         effect = DragOperationNone;
   1437     m_dragTargetDispatch = false;
   1438 
   1439     if (m_dropEffect != DropEffectDefault) {
   1440         m_dragOperation = (m_dropEffect != DropEffectNone) ? WebDragOperationCopy
   1441                                                            : WebDragOperationNone;
   1442     } else
   1443         m_dragOperation = static_cast<WebDragOperation>(effect);
   1444     return m_dragOperation;
   1445 }
   1446 
   1447 void WebViewImpl::dragTargetDragLeave()
   1448 {
   1449     ASSERT(m_currentDragData.get());
   1450 
   1451     DragData dragData(
   1452         m_currentDragData.get(),
   1453         IntPoint(),
   1454         IntPoint(),
   1455         static_cast<DragOperation>(m_operationsAllowed));
   1456 
   1457     m_dragTargetDispatch = true;
   1458     m_page->dragController()->dragExited(&dragData);
   1459     m_dragTargetDispatch = false;
   1460 
   1461     m_currentDragData = 0;
   1462     m_dropEffect = DropEffectDefault;
   1463     m_dragOperation = WebDragOperationNone;
   1464     m_dragIdentity = 0;
   1465 }
   1466 
   1467 void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint,
   1468                                  const WebPoint& screenPoint)
   1469 {
   1470     ASSERT(m_currentDragData.get());
   1471 
   1472     // If this webview transitions from the "drop accepting" state to the "not
   1473     // accepting" state, then our IPC message reply indicating that may be in-
   1474     // flight, or else delayed by javascript processing in this webview.  If a
   1475     // drop happens before our IPC reply has reached the browser process, then
   1476     // the browser forwards the drop to this webview.  So only allow a drop to
   1477     // proceed if our webview m_dragOperation state is not DragOperationNone.
   1478 
   1479     if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop.
   1480         dragTargetDragLeave();
   1481         return;
   1482     }
   1483 
   1484     DragData dragData(
   1485         m_currentDragData.get(),
   1486         clientPoint,
   1487         screenPoint,
   1488         static_cast<DragOperation>(m_operationsAllowed));
   1489 
   1490     m_dragTargetDispatch = true;
   1491     m_page->dragController()->performDrag(&dragData);
   1492     m_dragTargetDispatch = false;
   1493 
   1494     m_currentDragData = 0;
   1495     m_dropEffect = DropEffectDefault;
   1496     m_dragOperation = WebDragOperationNone;
   1497     m_dragIdentity = 0;
   1498 }
   1499 
   1500 int WebViewImpl::dragIdentity()
   1501 {
   1502     if (m_dragTargetDispatch)
   1503         return m_dragIdentity;
   1504     return 0;
   1505 }
   1506 
   1507 unsigned long WebViewImpl::createUniqueIdentifierForRequest() {
   1508     if (m_page)
   1509         return m_page->progress()->createUniqueIdentifier();
   1510     return 0;
   1511 }
   1512 
   1513 void WebViewImpl::inspectElementAt(const WebPoint& point)
   1514 {
   1515     if (!m_page.get())
   1516         return;
   1517 
   1518     if (point.x == -1 || point.y == -1)
   1519         m_page->inspectorController()->inspect(0);
   1520     else {
   1521         HitTestResult result = hitTestResultForWindowPos(point);
   1522 
   1523         if (!result.innerNonSharedNode())
   1524             return;
   1525 
   1526         m_page->inspectorController()->inspect(result.innerNonSharedNode());
   1527     }
   1528 }
   1529 
   1530 WebString WebViewImpl::inspectorSettings() const
   1531 {
   1532     return m_inspectorSettings;
   1533 }
   1534 
   1535 void WebViewImpl::setInspectorSettings(const WebString& settings)
   1536 {
   1537     m_inspectorSettings = settings;
   1538 }
   1539 
   1540 WebDevToolsAgent* WebViewImpl::devToolsAgent()
   1541 {
   1542     return m_devToolsAgent.get();
   1543 }
   1544 
   1545 void WebViewImpl::setDevToolsAgent(WebDevToolsAgent* devToolsAgent)
   1546 {
   1547     ASSERT(!m_devToolsAgent.get()); // May only set once!
   1548     m_devToolsAgent.set(static_cast<WebDevToolsAgentPrivate*>(devToolsAgent));
   1549 }
   1550 
   1551 WebAccessibilityObject WebViewImpl::accessibilityObject()
   1552 {
   1553     if (!mainFrameImpl())
   1554         return WebAccessibilityObject();
   1555 
   1556     Document* document = mainFrameImpl()->frame()->document();
   1557     return WebAccessibilityObject(
   1558         document->axObjectCache()->getOrCreate(document->renderer()));
   1559 }
   1560 
   1561 void WebViewImpl::applyAutofillSuggestions(
   1562     const WebNode& node,
   1563     const WebVector<WebString>& suggestions,
   1564     int defaultSuggestionIndex)
   1565 {
   1566     applyAutocompleteSuggestions(node, suggestions, defaultSuggestionIndex);
   1567 }
   1568 
   1569 void WebViewImpl::applyAutoFillSuggestions(
   1570     const WebNode& node,
   1571     const WebVector<WebString>& names,
   1572     const WebVector<WebString>& labels,
   1573     int defaultSuggestionIndex)
   1574 {
   1575     ASSERT(names.size() == labels.size());
   1576     ASSERT(defaultSuggestionIndex < static_cast<int>(names.size()));
   1577 
   1578     if (names.isEmpty()) {
   1579         hideSuggestionsPopup();
   1580         return;
   1581     }
   1582 
   1583     RefPtr<Node> focusedNode = focusedWebCoreNode();
   1584     // If the node for which we queried the AutoFill suggestions is not the
   1585     // focused node, then we have nothing to do.  FIXME: also check the
   1586     // caret is at the end and that the text has not changed.
   1587     if (!focusedNode || focusedNode != PassRefPtr<Node>(node)) {
   1588         hideSuggestionsPopup();
   1589         return;
   1590     }
   1591 
   1592     HTMLInputElement* inputElem =
   1593         static_cast<HTMLInputElement*>(focusedNode.get());
   1594 
   1595     // The first time the AutoFill popup is shown we'll create the client and
   1596     // the popup.
   1597     if (!m_autoFillPopupClient.get())
   1598         m_autoFillPopupClient.set(new AutoFillPopupMenuClient);
   1599 
   1600     m_autoFillPopupClient->initialize(inputElem, names, labels,
   1601                                       defaultSuggestionIndex);
   1602 
   1603     if (m_suggestionsPopupClient != m_autoFillPopupClient.get()) {
   1604         hideSuggestionsPopup();
   1605         m_suggestionsPopupClient = m_autoFillPopupClient.get();
   1606     }
   1607 
   1608     if (!m_autoFillPopup.get()) {
   1609         m_autoFillPopup = PopupContainer::create(m_suggestionsPopupClient,
   1610                                                  suggestionsPopupSettings);
   1611     }
   1612 
   1613     if (m_suggestionsPopup != m_autoFillPopup.get())
   1614         m_suggestionsPopup = m_autoFillPopup.get();
   1615 
   1616     if (m_suggestionsPopupShowing) {
   1617         m_autoFillPopupClient->setSuggestions(names, labels);
   1618         refreshSuggestionsPopup();
   1619     } else {
   1620         m_suggestionsPopup->show(focusedNode->getRect(),
   1621                                  focusedNode->ownerDocument()->view(), 0);
   1622         m_suggestionsPopupShowing = true;
   1623     }
   1624 }
   1625 
   1626 void WebViewImpl::applyAutocompleteSuggestions(
   1627     const WebNode& node,
   1628     const WebVector<WebString>& suggestions,
   1629     int defaultSuggestionIndex)
   1630 {
   1631     ASSERT(defaultSuggestionIndex < static_cast<int>(suggestions.size()));
   1632 
   1633     if (!m_page.get() || suggestions.isEmpty()) {
   1634         hideSuggestionsPopup();
   1635         return;
   1636     }
   1637 
   1638     RefPtr<Node> focusedNode = focusedWebCoreNode();
   1639     // If the node for which we queried the Autocomplete suggestions is not the
   1640     // focused node, then we have nothing to do.  FIXME: also check the
   1641     // caret is at the end and that the text has not changed.
   1642     if (!focusedNode || focusedNode != PassRefPtr<Node>(node)) {
   1643         hideSuggestionsPopup();
   1644         return;
   1645     }
   1646 
   1647     HTMLInputElement* inputElem =
   1648         static_cast<HTMLInputElement*>(focusedNode.get());
   1649 
   1650     // The first time the Autocomplete is shown we'll create the client and the
   1651     // popup.
   1652     if (!m_autocompletePopupClient.get())
   1653         m_autocompletePopupClient.set(new AutocompletePopupMenuClient);
   1654 
   1655     m_autocompletePopupClient->initialize(inputElem, suggestions,
   1656                                           defaultSuggestionIndex);
   1657 
   1658     if (m_suggestionsPopupClient != m_autocompletePopupClient.get()) {
   1659         hideSuggestionsPopup();
   1660         m_suggestionsPopupClient = m_autocompletePopupClient.get();
   1661     }
   1662 
   1663     if (!m_autocompletePopup.get()) {
   1664         m_autocompletePopup = PopupContainer::create(m_suggestionsPopupClient,
   1665                                                      suggestionsPopupSettings);
   1666     }
   1667 
   1668     if (m_suggestionsPopup != m_autocompletePopup.get())
   1669         m_suggestionsPopup = m_autocompletePopup.get();
   1670 
   1671     if (m_suggestionsPopupShowing) {
   1672         m_autocompletePopupClient->setSuggestions(suggestions);
   1673         refreshSuggestionsPopup();
   1674     } else {
   1675         m_suggestionsPopup->show(focusedNode->getRect(),
   1676                                  focusedNode->ownerDocument()->view(), 0);
   1677         m_suggestionsPopupShowing = true;
   1678     }
   1679 }
   1680 
   1681 void WebViewImpl::hideAutofillPopup()
   1682 {
   1683     hideSuggestionsPopup();
   1684 }
   1685 
   1686 void WebViewImpl::hideSuggestionsPopup()
   1687 {
   1688     if (m_suggestionsPopupShowing) {
   1689         m_suggestionsPopup->hidePopup();
   1690         m_suggestionsPopupShowing = false;
   1691     }
   1692 }
   1693 
   1694 void WebViewImpl::performCustomContextMenuAction(unsigned action)
   1695 {
   1696     if (!m_page)
   1697         return;
   1698     ContextMenu* menu = m_page->contextMenuController()->contextMenu();
   1699     if (!menu)
   1700         return;
   1701     ContextMenuItem* item = menu->itemWithAction(static_cast<ContextMenuAction>(ContextMenuItemBaseCustomTag + action));
   1702     if (item)
   1703         m_page->contextMenuController()->contextMenuItemSelected(item);
   1704     m_page->contextMenuController()->clearContextMenu();
   1705 }
   1706 
   1707 // WebView --------------------------------------------------------------------
   1708 
   1709 bool WebViewImpl::setDropEffect(bool accept)
   1710 {
   1711     if (m_dragTargetDispatch) {
   1712         m_dropEffect = accept ? DropEffectCopy : DropEffectNone;
   1713         return true;
   1714     }
   1715     return false;
   1716 }
   1717 
   1718 void WebViewImpl::setIsTransparent(bool isTransparent)
   1719 {
   1720     // Set any existing frames to be transparent.
   1721     Frame* frame = m_page->mainFrame();
   1722     while (frame) {
   1723         frame->view()->setTransparent(isTransparent);
   1724         frame = frame->tree()->traverseNext();
   1725     }
   1726 
   1727     // Future frames check this to know whether to be transparent.
   1728     m_isTransparent = isTransparent;
   1729 }
   1730 
   1731 bool WebViewImpl::isTransparent() const
   1732 {
   1733     return m_isTransparent;
   1734 }
   1735 
   1736 void WebViewImpl::setIsActive(bool active)
   1737 {
   1738     if (page() && page()->focusController())
   1739         page()->focusController()->setActive(active);
   1740 }
   1741 
   1742 bool WebViewImpl::isActive() const
   1743 {
   1744     return (page() && page()->focusController()) ? page()->focusController()->isActive() : false;
   1745 }
   1746 
   1747 void WebViewImpl::setScrollbarColors(unsigned inactiveColor,
   1748                                      unsigned activeColor,
   1749                                      unsigned trackColor) {
   1750 #if OS(LINUX)
   1751     RenderThemeChromiumLinux::setScrollbarColors(inactiveColor,
   1752                                                  activeColor,
   1753                                                  trackColor);
   1754 #endif
   1755 }
   1756 
   1757 void WebViewImpl::setSelectionColors(unsigned activeBackgroundColor,
   1758                                      unsigned activeForegroundColor,
   1759                                      unsigned inactiveBackgroundColor,
   1760                                      unsigned inactiveForegroundColor) {
   1761 #if OS(LINUX)
   1762     RenderThemeChromiumLinux::setSelectionColors(activeBackgroundColor,
   1763                                                  activeForegroundColor,
   1764                                                  inactiveBackgroundColor,
   1765                                                  inactiveForegroundColor);
   1766     theme()->platformColorsDidChange();
   1767 #endif
   1768 }
   1769 
   1770 void WebViewImpl::addUserScript(const WebString& sourceCode, bool runAtStart)
   1771 {
   1772     PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
   1773     RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create());
   1774     pageGroup->addUserScriptToWorld(world.get(), sourceCode, WebURL(), 0, 0,
   1775                                     runAtStart ? InjectAtDocumentStart : InjectAtDocumentEnd);
   1776 }
   1777 
   1778 void WebViewImpl::removeAllUserContent()
   1779 {
   1780     PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
   1781     pageGroup->removeAllUserContent();
   1782 }
   1783 
   1784 void WebViewImpl::didCommitLoad(bool* isNewNavigation)
   1785 {
   1786     if (isNewNavigation)
   1787         *isNewNavigation = m_observedNewNavigation;
   1788 
   1789 #ifndef NDEBUG
   1790     ASSERT(!m_observedNewNavigation
   1791         || m_page->mainFrame()->loader()->documentLoader() == m_newNavigationLoader);
   1792     m_newNavigationLoader = 0;
   1793 #endif
   1794     m_observedNewNavigation = false;
   1795 }
   1796 
   1797 bool WebViewImpl::navigationPolicyFromMouseEvent(unsigned short button,
   1798                                                  bool ctrl, bool shift,
   1799                                                  bool alt, bool meta,
   1800                                                  WebNavigationPolicy* policy)
   1801 {
   1802 #if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD)
   1803     const bool newTabModifier = (button == 1) || ctrl;
   1804 #elif OS(DARWIN)
   1805     const bool newTabModifier = (button == 1) || meta;
   1806 #endif
   1807     if (!newTabModifier && !shift && !alt)
   1808       return false;
   1809 
   1810     ASSERT(policy);
   1811     if (newTabModifier) {
   1812         if (shift)
   1813           *policy = WebNavigationPolicyNewForegroundTab;
   1814         else
   1815           *policy = WebNavigationPolicyNewBackgroundTab;
   1816     } else {
   1817         if (shift)
   1818           *policy = WebNavigationPolicyNewWindow;
   1819         else
   1820           *policy = WebNavigationPolicyDownload;
   1821     }
   1822     return true;
   1823 }
   1824 
   1825 void WebViewImpl::startDragging(const WebPoint& eventPos,
   1826                                 const WebDragData& dragData,
   1827                                 WebDragOperationsMask mask)
   1828 {
   1829     if (!m_client)
   1830         return;
   1831     ASSERT(!m_doingDragAndDrop);
   1832     m_doingDragAndDrop = true;
   1833     m_client->startDragging(eventPos, dragData, mask);
   1834 }
   1835 
   1836 void WebViewImpl::setCurrentHistoryItem(HistoryItem* item)
   1837 {
   1838     m_backForwardListClientImpl.setCurrentHistoryItem(item);
   1839 }
   1840 
   1841 HistoryItem* WebViewImpl::previousHistoryItem()
   1842 {
   1843     return m_backForwardListClientImpl.previousHistoryItem();
   1844 }
   1845 
   1846 void WebViewImpl::observeNewNavigation()
   1847 {
   1848     m_observedNewNavigation = true;
   1849 #ifndef NDEBUG
   1850     m_newNavigationLoader = m_page->mainFrame()->loader()->documentLoader();
   1851 #endif
   1852 }
   1853 
   1854 void WebViewImpl::setIgnoreInputEvents(bool newValue)
   1855 {
   1856     ASSERT(m_ignoreInputEvents != newValue);
   1857     m_ignoreInputEvents = newValue;
   1858 }
   1859 
   1860 #if ENABLE(NOTIFICATIONS)
   1861 NotificationPresenterImpl* WebViewImpl::notificationPresenterImpl()
   1862 {
   1863     if (!m_notificationPresenter.isInitialized() && m_client)
   1864         m_notificationPresenter.initialize(m_client->notificationPresenter());
   1865     return &m_notificationPresenter;
   1866 }
   1867 #endif
   1868 
   1869 void WebViewImpl::refreshSuggestionsPopup()
   1870 {
   1871     ASSERT(m_suggestionsPopupShowing);
   1872 
   1873     // Hide the popup if it has become empty.
   1874     if (!m_autocompletePopupClient->listSize()) {
   1875         hideSuggestionsPopup();
   1876         return;
   1877     }
   1878 
   1879     IntRect oldBounds = m_suggestionsPopup->boundsRect();
   1880     m_suggestionsPopup->refresh();
   1881     IntRect newBounds = m_suggestionsPopup->boundsRect();
   1882     // Let's resize the backing window if necessary.
   1883     if (oldBounds != newBounds) {
   1884         WebPopupMenuImpl* popupMenu =
   1885             static_cast<WebPopupMenuImpl*>(m_suggestionsPopup->client());
   1886         popupMenu->client()->setWindowRect(newBounds);
   1887     }
   1888 }
   1889 
   1890 Node* WebViewImpl::focusedWebCoreNode()
   1891 {
   1892     Frame* frame = m_page->focusController()->focusedFrame();
   1893     if (!frame)
   1894         return 0;
   1895 
   1896     Document* document = frame->document();
   1897     if (!document)
   1898         return 0;
   1899 
   1900     return document->focusedNode();
   1901 }
   1902 
   1903 HitTestResult WebViewImpl::hitTestResultForWindowPos(const IntPoint& pos)
   1904 {
   1905     IntPoint docPoint(m_page->mainFrame()->view()->windowToContents(pos));
   1906     return m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(docPoint, false);
   1907 }
   1908 
   1909 void WebViewImpl::setTabsToLinks(bool enable)
   1910 {
   1911     m_tabsToLinks = enable;
   1912 }
   1913 
   1914 bool WebViewImpl::tabsToLinks() const
   1915 {
   1916     return m_tabsToLinks;
   1917 }
   1918 
   1919 } // namespace WebKit
   1920