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 "AXObjectCache.h"
36#include "BackForwardListChromium.h"
37#include "CSSStyleSelector.h"
38#include "CSSValueKeywords.h"
39#include "Chrome.h"
40#include "ColorSpace.h"
41#include "CompositionUnderlineVectorBuilder.h"
42#include "ContextMenu.h"
43#include "ContextMenuController.h"
44#include "ContextMenuItem.h"
45#include "Cursor.h"
46#include "DOMUtilitiesPrivate.h"
47#include "DeviceOrientationClientProxy.h"
48#include "Document.h"
49#include "DocumentLoader.h"
50#include "DragController.h"
51#include "DragData.h"
52#include "DragScrollTimer.h"
53#include "Editor.h"
54#include "EventHandler.h"
55#include "Extensions3D.h"
56#include "FocusController.h"
57#include "FontDescription.h"
58#include "FrameLoader.h"
59#include "FrameTree.h"
60#include "FrameView.h"
61#include "GeolocationClientProxy.h"
62#include "GraphicsContext.h"
63#include "GraphicsContext3D.h"
64#include "GraphicsContext3DInternal.h"
65#include "HTMLInputElement.h"
66#include "HTMLMediaElement.h"
67#include "HTMLNames.h"
68#include "HitTestResult.h"
69#include "Image.h"
70#include "ImageBuffer.h"
71#include "InspectorController.h"
72#include "KeyboardCodes.h"
73#include "KeyboardEvent.h"
74#include "MIMETypeRegistry.h"
75#include "NodeRenderStyle.h"
76#include "Page.h"
77#include "PageGroup.h"
78#include "PageGroupLoadDeferrer.h"
79#include "Pasteboard.h"
80#include "PlatformContextSkia.h"
81#include "PlatformKeyboardEvent.h"
82#include "PlatformMouseEvent.h"
83#include "PlatformThemeChromiumGtk.h"
84#include "PlatformWheelEvent.h"
85#include "PopupMenuChromium.h"
86#include "PopupMenuClient.h"
87#include "ProgressTracker.h"
88#include "RenderView.h"
89#include "ResourceHandle.h"
90#include "SecurityOrigin.h"
91#include "SelectionController.h"
92#include "Settings.h"
93#include "SpeechInputClientImpl.h"
94#include "Timer.h"
95#include "TraceEvent.h"
96#include "TypingCommand.h"
97#include "UserGestureIndicator.h"
98#include "Vector.h"
99#include "WebAccessibilityObject.h"
100#include "WebAutoFillClient.h"
101#include "WebDevToolsAgentImpl.h"
102#include "WebDevToolsAgentPrivate.h"
103#include "WebDragData.h"
104#include "WebFrameImpl.h"
105#include "WebGraphicsContext3D.h"
106#include "WebImage.h"
107#include "WebInputElement.h"
108#include "WebInputEvent.h"
109#include "WebInputEventConversion.h"
110#include "WebKit.h"
111#include "WebKitClient.h"
112#include "WebMediaPlayerAction.h"
113#include "WebNode.h"
114#include "WebPlugin.h"
115#include "WebPluginContainerImpl.h"
116#include "WebPoint.h"
117#include "WebPopupMenuImpl.h"
118#include "WebRect.h"
119#include "WebRuntimeFeatures.h"
120#include "WebSettingsImpl.h"
121#include "WebString.h"
122#include "WebVector.h"
123#include "WebViewClient.h"
124#include "cc/CCHeadsUpDisplay.h"
125#include <wtf/ByteArray.h>
126#include <wtf/CurrentTime.h>
127#include <wtf/RefPtr.h>
128
129#if USE(CG)
130#include <CoreGraphics/CGBitmapContext.h>
131#include <CoreGraphics/CGContext.h>
132#endif
133
134#if OS(WINDOWS)
135#include "RenderThemeChromiumWin.h"
136#else
137#if OS(LINUX) || OS(FREEBSD)
138#include "RenderThemeChromiumLinux.h"
139#endif
140#include "RenderTheme.h"
141#endif
142
143// Get rid of WTF's pow define so we can use std::pow.
144#undef pow
145#include <cmath> // for std::pow
146
147using namespace WebCore;
148
149namespace {
150
151GraphicsContext3D::Attributes getCompositorContextAttributes()
152{
153    // Explicitly disable antialiasing for the compositor. As of the time of
154    // this writing, the only platform that supported antialiasing for the
155    // compositor was Mac OS X, because the on-screen OpenGL context creation
156    // code paths on Windows and Linux didn't yet have multisampling support.
157    // Mac OS X essentially always behaves as though it's rendering offscreen.
158    // Multisampling has a heavy cost especially on devices with relatively low
159    // fill rate like most notebooks, and the Mac implementation would need to
160    // be optimized to resolve directly into the IOSurface shared between the
161    // GPU and browser processes. For these reasons and to avoid platform
162    // disparities we explicitly disable antialiasing.
163    GraphicsContext3D::Attributes attributes;
164    attributes.antialias = false;
165    return attributes;
166}
167
168} // anonymous namespace
169
170namespace WebKit {
171
172// Change the text zoom level by kTextSizeMultiplierRatio each time the user
173// zooms text in or out (ie., change by 20%).  The min and max values limit
174// text zoom to half and 3x the original text size.  These three values match
175// those in Apple's port in WebKit/WebKit/WebView/WebView.mm
176const double WebView::textSizeMultiplierRatio = 1.2;
177const double WebView::minTextSizeMultiplier = 0.5;
178const double WebView::maxTextSizeMultiplier = 3.0;
179
180
181// The group name identifies a namespace of pages.  Page group is used on OSX
182// for some programs that use HTML views to display things that don't seem like
183// web pages to the user (so shouldn't have visited link coloring).  We only use
184// one page group.
185const char* pageGroupName = "default";
186
187// Used to defer all page activity in cases where the embedder wishes to run
188// a nested event loop. Using a stack enables nesting of message loop invocations.
189static Vector<PageGroupLoadDeferrer*> pageGroupLoadDeferrerStack;
190
191// Ensure that the WebDragOperation enum values stay in sync with the original
192// DragOperation constants.
193#define COMPILE_ASSERT_MATCHING_ENUM(coreName) \
194    COMPILE_ASSERT(int(coreName) == int(Web##coreName), dummy##coreName)
195COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone);
196COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy);
197COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink);
198COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric);
199COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate);
200COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove);
201COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete);
202COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery);
203
204static const PopupContainerSettings autoFillPopupSettings = {
205    false, // setTextOnIndexChange
206    false, // acceptOnAbandon
207    true, // loopSelectionNavigation
208    false // restrictWidthOfListBox (For security reasons show the entire entry
209          // so the user doesn't enter information he did not intend to.)
210};
211
212static bool shouldUseExternalPopupMenus = false;
213
214// WebView ----------------------------------------------------------------
215
216WebView* WebView::create(WebViewClient* client)
217{
218    // Keep runtime flag for device motion turned off until it's implemented.
219    WebRuntimeFeatures::enableDeviceMotion(false);
220
221    // Pass the WebViewImpl's self-reference to the caller.
222    return adoptRef(new WebViewImpl(client)).leakRef();
223}
224
225void WebView::setUseExternalPopupMenus(bool useExternalPopupMenus)
226{
227    shouldUseExternalPopupMenus = useExternalPopupMenus;
228}
229
230void WebView::updateVisitedLinkState(unsigned long long linkHash)
231{
232    Page::visitedStateChanged(PageGroup::pageGroup(pageGroupName), linkHash);
233}
234
235void WebView::resetVisitedLinkState()
236{
237    Page::allVisitedStateChanged(PageGroup::pageGroup(pageGroupName));
238}
239
240void WebView::willEnterModalLoop()
241{
242    PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
243    ASSERT(pageGroup);
244
245    if (pageGroup->pages().isEmpty())
246        pageGroupLoadDeferrerStack.append(static_cast<PageGroupLoadDeferrer*>(0));
247    else {
248        // Pick any page in the page group since we are deferring all pages.
249        pageGroupLoadDeferrerStack.append(new PageGroupLoadDeferrer(*pageGroup->pages().begin(), true));
250    }
251}
252
253void WebView::didExitModalLoop()
254{
255    ASSERT(pageGroupLoadDeferrerStack.size());
256
257    delete pageGroupLoadDeferrerStack.last();
258    pageGroupLoadDeferrerStack.removeLast();
259}
260
261void WebViewImpl::initializeMainFrame(WebFrameClient* frameClient)
262{
263    // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame
264    // and releases that reference once the corresponding Frame is destroyed.
265    RefPtr<WebFrameImpl> frame = WebFrameImpl::create(frameClient);
266
267    frame->initializeAsMainFrame(this);
268
269    // Restrict the access to the local file system
270    // (see WebView.mm WebView::_commonInitializationWithFrameName).
271    SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForLocalOnly);
272}
273
274void WebViewImpl::setDevToolsAgentClient(WebDevToolsAgentClient* devToolsClient)
275{
276    if (devToolsClient)
277        m_devToolsAgent = new WebDevToolsAgentImpl(this, devToolsClient);
278    else
279        m_devToolsAgent.clear();
280}
281
282void WebViewImpl::setAutoFillClient(WebAutoFillClient* autoFillClient)
283{
284    m_autoFillClient = autoFillClient;
285}
286
287void WebViewImpl::setSpellCheckClient(WebSpellCheckClient* spellCheckClient)
288{
289    m_spellCheckClient = spellCheckClient;
290}
291
292WebViewImpl::WebViewImpl(WebViewClient* client)
293    : m_client(client)
294    , m_autoFillClient(0)
295    , m_spellCheckClient(0)
296    , m_chromeClientImpl(this)
297    , m_contextMenuClientImpl(this)
298    , m_dragClientImpl(this)
299    , m_editorClientImpl(this)
300    , m_inspectorClientImpl(this)
301    , m_observedNewNavigation(false)
302#ifndef NDEBUG
303    , m_newNavigationLoader(0)
304#endif
305    , m_zoomLevel(0)
306    , m_minimumZoomLevel(zoomFactorToZoomLevel(minTextSizeMultiplier))
307    , m_maximumZoomLevel(zoomFactorToZoomLevel(maxTextSizeMultiplier))
308    , m_contextMenuAllowed(false)
309    , m_doingDragAndDrop(false)
310    , m_ignoreInputEvents(false)
311    , m_suppressNextKeypressEvent(false)
312    , m_initialNavigationPolicy(WebNavigationPolicyIgnore)
313    , m_imeAcceptEvents(true)
314    , m_operationsAllowed(WebDragOperationNone)
315    , m_dragOperation(WebDragOperationNone)
316    , m_autoFillPopupShowing(false)
317    , m_autoFillPopupClient(0)
318    , m_autoFillPopup(0)
319    , m_isTransparent(false)
320    , m_tabsToLinks(false)
321    , m_dragScrollTimer(new DragScrollTimer())
322#if USE(ACCELERATED_COMPOSITING)
323    , m_layerRenderer(0)
324    , m_isAcceleratedCompositingActive(false)
325    , m_compositorCreationFailed(false)
326    , m_recreatingGraphicsContext(false)
327#endif
328#if ENABLE(INPUT_SPEECH)
329    , m_speechInputClient(SpeechInputClientImpl::create(client))
330#endif
331    , m_deviceOrientationClientProxy(new DeviceOrientationClientProxy(client ? client->deviceOrientationClient() : 0))
332    , m_geolocationClientProxy(new GeolocationClientProxy(client ? client->geolocationClient() : 0))
333{
334    // WebKit/win/WebView.cpp does the same thing, except they call the
335    // KJS specific wrapper around this method. We need to have threading
336    // initialized because CollatorICU requires it.
337    WTF::initializeThreading();
338    WTF::initializeMainThread();
339
340    // set to impossible point so we always get the first mouse pos
341    m_lastMousePosition = WebPoint(-1, -1);
342
343    Page::PageClients pageClients;
344    pageClients.chromeClient = &m_chromeClientImpl;
345    pageClients.contextMenuClient = &m_contextMenuClientImpl;
346    pageClients.editorClient = &m_editorClientImpl;
347    pageClients.dragClient = &m_dragClientImpl;
348    pageClients.inspectorClient = &m_inspectorClientImpl;
349#if ENABLE(INPUT_SPEECH)
350    pageClients.speechInputClient = m_speechInputClient.get();
351#endif
352    pageClients.deviceOrientationClient = m_deviceOrientationClientProxy.get();
353    pageClients.geolocationClient = m_geolocationClientProxy.get();
354    pageClients.backForwardClient = BackForwardListChromium::create(this);
355
356    m_page.set(new Page(pageClients));
357
358    m_geolocationClientProxy->setController(m_page->geolocationController());
359
360    m_page->setGroupName(pageGroupName);
361
362    m_inspectorSettingsMap.set(new SettingsMap);
363}
364
365WebViewImpl::~WebViewImpl()
366{
367    ASSERT(!m_page);
368}
369
370RenderTheme* WebViewImpl::theme() const
371{
372    return m_page.get() ? m_page->theme() : RenderTheme::defaultTheme().get();
373}
374
375WebFrameImpl* WebViewImpl::mainFrameImpl()
376{
377    return m_page.get() ? WebFrameImpl::fromFrame(m_page->mainFrame()) : 0;
378}
379
380bool WebViewImpl::tabKeyCyclesThroughElements() const
381{
382    ASSERT(m_page.get());
383    return m_page->tabKeyCyclesThroughElements();
384}
385
386void WebViewImpl::setTabKeyCyclesThroughElements(bool value)
387{
388    if (m_page)
389        m_page->setTabKeyCyclesThroughElements(value);
390}
391
392void WebViewImpl::mouseMove(const WebMouseEvent& event)
393{
394    if (!mainFrameImpl() || !mainFrameImpl()->frameView())
395        return;
396
397    m_lastMousePosition = WebPoint(event.x, event.y);
398
399    // We call mouseMoved here instead of handleMouseMovedEvent because we need
400    // our ChromeClientImpl to receive changes to the mouse position and
401    // tooltip text, and mouseMoved handles all of that.
402    mainFrameImpl()->frame()->eventHandler()->mouseMoved(
403        PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
404}
405
406void WebViewImpl::mouseLeave(const WebMouseEvent& event)
407{
408    // This event gets sent as the main frame is closing.  In that case, just
409    // ignore it.
410    if (!mainFrameImpl() || !mainFrameImpl()->frameView())
411        return;
412
413    m_client->setMouseOverURL(WebURL());
414
415    mainFrameImpl()->frame()->eventHandler()->handleMouseMoveEvent(
416        PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
417}
418
419void WebViewImpl::mouseDown(const WebMouseEvent& event)
420{
421    if (!mainFrameImpl() || !mainFrameImpl()->frameView())
422        return;
423
424    // If there is a select popup open, close it as the user is clicking on
425    // the page (outside of the popup).  We also save it so we can prevent a
426    // click on the select element from immediately reopening the popup.
427    RefPtr<WebCore::PopupContainer> selectPopup;
428    if (event.button == WebMouseEvent::ButtonLeft) {
429        selectPopup = m_selectPopup;
430        hideSelectPopup();
431        ASSERT(!m_selectPopup);
432    }
433
434    m_lastMouseDownPoint = WebPoint(event.x, event.y);
435
436    RefPtr<Node> clickedNode;
437    if (event.button == WebMouseEvent::ButtonLeft) {
438        IntPoint point(event.x, event.y);
439        point = m_page->mainFrame()->view()->windowToContents(point);
440        HitTestResult result(m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, false));
441        Node* hitNode = result.innerNonSharedNode();
442
443        // Take capture on a mouse down on a plugin so we can send it mouse events.
444        if (hitNode && hitNode->renderer() && hitNode->renderer()->isEmbeddedObject())
445            m_mouseCaptureNode = hitNode;
446
447        // If a text field that has focus is clicked again, we should display the
448        // AutoFill popup.
449        RefPtr<Node> focusedNode = focusedWebCoreNode();
450        if (focusedNode.get() && toHTMLInputElement(focusedNode.get())) {
451            if (hitNode == focusedNode) {
452                // Already focused text field was clicked, let's remember this.  If
453                // focus has not changed after the mouse event is processed, we'll
454                // trigger the autocomplete.
455                clickedNode = focusedNode;
456            }
457        }
458    }
459
460    mainFrameImpl()->frame()->loader()->resetMultipleFormSubmissionProtection();
461
462    mainFrameImpl()->frame()->eventHandler()->handleMousePressEvent(
463        PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
464
465    if (clickedNode.get() && clickedNode == focusedWebCoreNode()) {
466        // Focus has not changed, show the AutoFill popup.
467        static_cast<EditorClientImpl*>(m_page->editorClient())->
468            showFormAutofillForNode(clickedNode.get());
469    }
470    if (m_selectPopup && m_selectPopup == selectPopup) {
471        // That click triggered a select popup which is the same as the one that
472        // was showing before the click.  It means the user clicked the select
473        // while the popup was showing, and as a result we first closed then
474        // immediately reopened the select popup.  It needs to be closed.
475        hideSelectPopup();
476    }
477
478    // Dispatch the contextmenu event regardless of if the click was swallowed.
479    // On Windows, we handle it on mouse up, not down.
480#if OS(DARWIN)
481    if (event.button == WebMouseEvent::ButtonRight
482        || (event.button == WebMouseEvent::ButtonLeft
483            && event.modifiers & WebMouseEvent::ControlKey))
484        mouseContextMenu(event);
485#elif OS(LINUX) || OS(FREEBSD)
486    if (event.button == WebMouseEvent::ButtonRight)
487        mouseContextMenu(event);
488#endif
489}
490
491void WebViewImpl::mouseContextMenu(const WebMouseEvent& event)
492{
493    if (!mainFrameImpl() || !mainFrameImpl()->frameView())
494        return;
495
496    m_page->contextMenuController()->clearContextMenu();
497
498    PlatformMouseEventBuilder pme(mainFrameImpl()->frameView(), event);
499
500    // Find the right target frame. See issue 1186900.
501    HitTestResult result = hitTestResultForWindowPos(pme.pos());
502    Frame* targetFrame;
503    if (result.innerNonSharedNode())
504        targetFrame = result.innerNonSharedNode()->document()->frame();
505    else
506        targetFrame = m_page->focusController()->focusedOrMainFrame();
507
508#if OS(WINDOWS)
509    targetFrame->view()->setCursor(pointerCursor());
510#endif
511
512    m_contextMenuAllowed = true;
513    targetFrame->eventHandler()->sendContextMenuEvent(pme);
514    m_contextMenuAllowed = false;
515    // Actually showing the context menu is handled by the ContextMenuClient
516    // implementation...
517}
518
519void WebViewImpl::mouseUp(const WebMouseEvent& event)
520{
521    if (!mainFrameImpl() || !mainFrameImpl()->frameView())
522        return;
523
524#if OS(LINUX) || OS(FREEBSD)
525    // If the event was a middle click, attempt to copy text into the focused
526    // frame. We execute this before we let the page have a go at the event
527    // because the page may change what is focused during in its event handler.
528    //
529    // This code is in the mouse up handler. There is some debate about putting
530    // this here, as opposed to the mouse down handler.
531    //   xterm: pastes on up.
532    //   GTK: pastes on down.
533    //   Firefox: pastes on up.
534    //   Midori: couldn't paste at all with 0.1.2
535    //
536    // There is something of a webcompat angle to this well, as highlighted by
537    // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
538    // down then the text is pasted just before the onclick handler runs and
539    // clears the text box. So it's important this happens after the
540    // handleMouseReleaseEvent() earlier in this function
541    if (event.button == WebMouseEvent::ButtonMiddle) {
542        Frame* focused = focusedWebCoreFrame();
543        FrameView* view = m_page->mainFrame()->view();
544        IntPoint clickPoint(m_lastMouseDownPoint.x, m_lastMouseDownPoint.y);
545        IntPoint contentPoint = view->windowToContents(clickPoint);
546        HitTestResult hitTestResult = focused->eventHandler()->hitTestResultAtPoint(contentPoint, false, false, ShouldHitTestScrollbars);
547        // We don't want to send a paste when middle clicking a scroll bar or a
548        // link (which will navigate later in the code).  The main scrollbars
549        // have to be handled separately.
550        if (!hitTestResult.scrollbar() && !hitTestResult.isLiveLink() && focused && !view->scrollbarAtPoint(clickPoint)) {
551            Editor* editor = focused->editor();
552            Pasteboard* pasteboard = Pasteboard::generalPasteboard();
553            bool oldSelectionMode = pasteboard->isSelectionMode();
554            pasteboard->setSelectionMode(true);
555            editor->command(AtomicString("Paste")).execute();
556            pasteboard->setSelectionMode(oldSelectionMode);
557        }
558    }
559#endif
560
561    mainFrameImpl()->frame()->eventHandler()->handleMouseReleaseEvent(
562        PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
563
564#if OS(WINDOWS)
565    // Dispatch the contextmenu event regardless of if the click was swallowed.
566    // On Mac/Linux, we handle it on mouse down, not up.
567    if (event.button == WebMouseEvent::ButtonRight)
568        mouseContextMenu(event);
569#endif
570}
571
572bool WebViewImpl::mouseWheel(const WebMouseWheelEvent& event)
573{
574    PlatformWheelEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
575    return mainFrameImpl()->frame()->eventHandler()->handleWheelEvent(platformEvent);
576}
577
578bool WebViewImpl::keyEvent(const WebKeyboardEvent& event)
579{
580    ASSERT((event.type == WebInputEvent::RawKeyDown)
581        || (event.type == WebInputEvent::KeyDown)
582        || (event.type == WebInputEvent::KeyUp));
583
584    // Please refer to the comments explaining the m_suppressNextKeypressEvent
585    // member.
586    // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
587    // Webkit. A keyDown event is typically associated with a keyPress(char)
588    // event and a keyUp event. We reset this flag here as this is a new keyDown
589    // event.
590    m_suppressNextKeypressEvent = false;
591
592    // Give any select popup a chance at consuming the key event.
593    if (selectPopupHandleKeyEvent(event))
594        return true;
595
596    // Give Autocomplete a chance to consume the key events it is interested in.
597    if (autocompleteHandleKeyEvent(event))
598        return true;
599
600    Frame* frame = focusedWebCoreFrame();
601    if (!frame)
602        return false;
603
604    EventHandler* handler = frame->eventHandler();
605    if (!handler)
606        return keyEventDefault(event);
607
608#if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD)
609    const WebInputEvent::Type contextMenuTriggeringEventType =
610#if OS(WINDOWS)
611        WebInputEvent::KeyUp;
612#elif OS(LINUX) || OS(FREEBSD)
613        WebInputEvent::RawKeyDown;
614#endif
615
616    bool isUnmodifiedMenuKey = !(event.modifiers & WebInputEvent::InputModifiers) && event.windowsKeyCode == VKEY_APPS;
617    bool isShiftF10 = event.modifiers == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10;
618    if ((isUnmodifiedMenuKey || isShiftF10) && event.type == contextMenuTriggeringEventType) {
619        sendContextMenuEvent(event);
620        return true;
621    }
622#endif // OS(WINDOWS) || OS(LINUX) || OS(FREEBSD)
623
624    PlatformKeyboardEventBuilder evt(event);
625
626    if (handler->keyEvent(evt)) {
627        if (WebInputEvent::RawKeyDown == event.type) {
628            // Suppress the next keypress event unless the focused node is a plug-in node.
629            // (Flash needs these keypress events to handle non-US keyboards.)
630            Node* node = frame->document()->focusedNode();
631            if (!node || !node->renderer() || !node->renderer()->isEmbeddedObject())
632                m_suppressNextKeypressEvent = true;
633        }
634        return true;
635    }
636
637    return keyEventDefault(event);
638}
639
640bool WebViewImpl::selectPopupHandleKeyEvent(const WebKeyboardEvent& event)
641{
642    if (!m_selectPopup)
643        return false;
644
645    return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
646}
647
648bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event)
649{
650    if (!m_autoFillPopupShowing
651        // Home and End should be left to the text field to process.
652        || event.windowsKeyCode == VKEY_HOME
653        || event.windowsKeyCode == VKEY_END)
654      return false;
655
656    // Pressing delete triggers the removal of the selected suggestion from the DB.
657    if (event.windowsKeyCode == VKEY_DELETE
658        && m_autoFillPopup->selectedIndex() != -1) {
659        Node* node = focusedWebCoreNode();
660        if (!node || (node->nodeType() != Node::ELEMENT_NODE)) {
661            ASSERT_NOT_REACHED();
662            return false;
663        }
664        Element* element = static_cast<Element*>(node);
665        if (!element->hasLocalName(HTMLNames::inputTag)) {
666            ASSERT_NOT_REACHED();
667            return false;
668        }
669
670        int selectedIndex = m_autoFillPopup->selectedIndex();
671
672        if (!m_autoFillPopupClient->canRemoveSuggestionAtIndex(selectedIndex))
673            return false;
674
675        WebString name = WebInputElement(static_cast<HTMLInputElement*>(element)).nameForAutofill();
676        WebString value = m_autoFillPopupClient->itemText(selectedIndex);
677        m_autoFillClient->removeAutocompleteSuggestion(name, value);
678        // Update the entries in the currently showing popup to reflect the
679        // deletion.
680        m_autoFillPopupClient->removeSuggestionAtIndex(selectedIndex);
681        refreshAutoFillPopup();
682        return false;
683    }
684
685    if (!m_autoFillPopup->isInterestedInEventForKey(event.windowsKeyCode))
686        return false;
687
688    if (m_autoFillPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) {
689        // We need to ignore the next Char event after this otherwise pressing
690        // enter when selecting an item in the menu will go to the page.
691        if (WebInputEvent::RawKeyDown == event.type)
692            m_suppressNextKeypressEvent = true;
693        return true;
694    }
695
696    return false;
697}
698
699bool WebViewImpl::charEvent(const WebKeyboardEvent& event)
700{
701    ASSERT(event.type == WebInputEvent::Char);
702
703    // Please refer to the comments explaining the m_suppressNextKeypressEvent
704    // member.  The m_suppressNextKeypressEvent is set if the KeyDown is
705    // handled by Webkit. A keyDown event is typically associated with a
706    // keyPress(char) event and a keyUp event. We reset this flag here as it
707    // only applies to the current keyPress event.
708    bool suppress = m_suppressNextKeypressEvent;
709    m_suppressNextKeypressEvent = false;
710
711    Frame* frame = focusedWebCoreFrame();
712    if (!frame)
713        return suppress;
714
715    EventHandler* handler = frame->eventHandler();
716    if (!handler)
717        return suppress || keyEventDefault(event);
718
719    PlatformKeyboardEventBuilder evt(event);
720    if (!evt.isCharacterKey())
721        return true;
722
723    // Accesskeys are triggered by char events and can't be suppressed.
724    if (handler->handleAccessKey(evt))
725        return true;
726
727    // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
728    // the eventHandler::keyEvent. We mimic this behavior on all platforms since
729    // for now we are converting other platform's key events to windows key
730    // events.
731    if (evt.isSystemKey())
732        return false;
733
734    if (!suppress && !handler->keyEvent(evt))
735        return keyEventDefault(event);
736
737    return true;
738}
739
740#if ENABLE(TOUCH_EVENTS)
741bool WebViewImpl::touchEvent(const WebTouchEvent& event)
742{
743    if (!mainFrameImpl() || !mainFrameImpl()->frameView())
744        return false;
745
746    PlatformTouchEventBuilder touchEventBuilder(mainFrameImpl()->frameView(), event);
747    return mainFrameImpl()->frame()->eventHandler()->handleTouchEvent(touchEventBuilder);
748}
749#endif
750
751#if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD)
752// Mac has no way to open a context menu based on a keyboard event.
753bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event)
754{
755    // The contextMenuController() holds onto the last context menu that was
756    // popped up on the page until a new one is created. We need to clear
757    // this menu before propagating the event through the DOM so that we can
758    // detect if we create a new menu for this event, since we won't create
759    // a new menu if the DOM swallows the event and the defaultEventHandler does
760    // not run.
761    page()->contextMenuController()->clearContextMenu();
762
763    m_contextMenuAllowed = true;
764    Frame* focusedFrame = page()->focusController()->focusedOrMainFrame();
765    bool handled = focusedFrame->eventHandler()->sendContextMenuEventForKey();
766    m_contextMenuAllowed = false;
767    return handled;
768}
769#endif
770
771bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event)
772{
773    Frame* frame = focusedWebCoreFrame();
774    if (!frame)
775        return false;
776
777    switch (event.type) {
778    case WebInputEvent::Char:
779        if (event.windowsKeyCode == VKEY_SPACE) {
780            int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT);
781            return scrollViewWithKeyboard(keyCode, event.modifiers);
782        }
783        break;
784    case WebInputEvent::RawKeyDown:
785        if (event.modifiers == WebInputEvent::ControlKey) {
786            switch (event.windowsKeyCode) {
787#if !OS(DARWIN)
788            case 'A':
789                focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll"));
790                return true;
791            case VKEY_INSERT:
792            case 'C':
793                focusedFrame()->executeCommand(WebString::fromUTF8("Copy"));
794                return true;
795#endif
796            // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
797            // key combinations which affect scrolling. Safari is buggy in the
798            // sense that it scrolls the page for all Ctrl+scrolling key
799            // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
800            case VKEY_HOME:
801            case VKEY_END:
802                break;
803            default:
804                return false;
805            }
806        }
807        if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey))
808            return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers);
809        break;
810    default:
811        break;
812    }
813    return false;
814}
815
816bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers)
817{
818    ScrollDirection scrollDirection;
819    ScrollGranularity scrollGranularity;
820#if OS(DARWIN)
821    // Control-Up/Down should be PageUp/Down on Mac.
822    if (modifiers & WebMouseEvent::ControlKey) {
823      if (keyCode == VKEY_UP)
824        keyCode = VKEY_PRIOR;
825      else if (keyCode == VKEY_DOWN)
826        keyCode = VKEY_NEXT;
827    }
828#endif
829    if (!mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity))
830        return false;
831    return propagateScroll(scrollDirection, scrollGranularity);
832}
833
834bool WebViewImpl::mapKeyCodeForScroll(int keyCode,
835                                      WebCore::ScrollDirection* scrollDirection,
836                                      WebCore::ScrollGranularity* scrollGranularity)
837{
838    switch (keyCode) {
839    case VKEY_LEFT:
840        *scrollDirection = ScrollLeft;
841        *scrollGranularity = ScrollByLine;
842        break;
843    case VKEY_RIGHT:
844        *scrollDirection = ScrollRight;
845        *scrollGranularity = ScrollByLine;
846        break;
847    case VKEY_UP:
848        *scrollDirection = ScrollUp;
849        *scrollGranularity = ScrollByLine;
850        break;
851    case VKEY_DOWN:
852        *scrollDirection = ScrollDown;
853        *scrollGranularity = ScrollByLine;
854        break;
855    case VKEY_HOME:
856        *scrollDirection = ScrollUp;
857        *scrollGranularity = ScrollByDocument;
858        break;
859    case VKEY_END:
860        *scrollDirection = ScrollDown;
861        *scrollGranularity = ScrollByDocument;
862        break;
863    case VKEY_PRIOR:  // page up
864        *scrollDirection = ScrollUp;
865        *scrollGranularity = ScrollByPage;
866        break;
867    case VKEY_NEXT:  // page down
868        *scrollDirection = ScrollDown;
869        *scrollGranularity = ScrollByPage;
870        break;
871    default:
872        return false;
873    }
874
875    return true;
876}
877
878void WebViewImpl::hideSelectPopup()
879{
880    if (m_selectPopup.get())
881        m_selectPopup->hidePopup();
882}
883
884bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection,
885                                  ScrollGranularity scrollGranularity)
886{
887    Frame* frame = focusedWebCoreFrame();
888    if (!frame)
889        return false;
890
891    bool scrollHandled = frame->eventHandler()->scrollOverflow(scrollDirection, scrollGranularity);
892    Frame* currentFrame = frame;
893    while (!scrollHandled && currentFrame) {
894        scrollHandled = currentFrame->view()->scroll(scrollDirection, scrollGranularity);
895        currentFrame = currentFrame->tree()->parent();
896    }
897    return scrollHandled;
898}
899
900void  WebViewImpl::popupOpened(WebCore::PopupContainer* popupContainer)
901{
902    if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
903        ASSERT(!m_selectPopup);
904        m_selectPopup = popupContainer;
905    }
906}
907
908void  WebViewImpl::popupClosed(WebCore::PopupContainer* popupContainer)
909{
910    if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
911        ASSERT(m_selectPopup.get());
912        m_selectPopup = 0;
913    }
914}
915
916void WebViewImpl::hideAutoFillPopup()
917{
918    if (m_autoFillPopupShowing) {
919        m_autoFillPopup->hidePopup();
920        m_autoFillPopupShowing = false;
921    }
922}
923
924Frame* WebViewImpl::focusedWebCoreFrame() const
925{
926    return m_page.get() ? m_page->focusController()->focusedOrMainFrame() : 0;
927}
928
929WebViewImpl* WebViewImpl::fromPage(Page* page)
930{
931    if (!page)
932        return 0;
933
934    ChromeClientImpl* chromeClient = static_cast<ChromeClientImpl*>(page->chrome()->client());
935    return static_cast<WebViewImpl*>(chromeClient->webView());
936}
937
938// WebWidget ------------------------------------------------------------------
939
940void WebViewImpl::close()
941{
942    RefPtr<WebFrameImpl> mainFrameImpl;
943
944    if (m_page.get()) {
945        // Initiate shutdown for the entire frameset.  This will cause a lot of
946        // notifications to be sent.
947        if (m_page->mainFrame()) {
948            mainFrameImpl = WebFrameImpl::fromFrame(m_page->mainFrame());
949            m_page->mainFrame()->loader()->frameDetached();
950        }
951        m_page.clear();
952    }
953
954    // Should happen after m_page.clear().
955    if (m_devToolsAgent.get())
956        m_devToolsAgent.clear();
957
958    // Reset the delegate to prevent notifications being sent as we're being
959    // deleted.
960    m_client = 0;
961
962    deref();  // Balances ref() acquired in WebView::create
963}
964
965void WebViewImpl::resize(const WebSize& newSize)
966{
967    if (m_size == newSize)
968        return;
969    m_size = newSize;
970
971    if (mainFrameImpl()->frameView()) {
972        mainFrameImpl()->frameView()->resize(m_size.width, m_size.height);
973        mainFrameImpl()->frame()->eventHandler()->sendResizeEvent();
974    }
975
976    if (m_client) {
977        if (isAcceleratedCompositingActive()) {
978#if USE(ACCELERATED_COMPOSITING)
979            updateLayerRendererViewport();
980#endif
981        } else {
982            WebRect damagedRect(0, 0, m_size.width, m_size.height);
983            m_client->didInvalidateRect(damagedRect);
984        }
985    }
986
987#if USE(ACCELERATED_COMPOSITING)
988    if (m_layerRenderer && isAcceleratedCompositingActive()) {
989        m_layerRenderer->resizeOnscreenContent(IntSize(std::max(1, m_size.width),
990                                                       std::max(1, m_size.height)));
991    }
992#endif
993}
994
995void WebViewImpl::animate()
996{
997#if ENABLE(REQUEST_ANIMATION_FRAME)
998    WebFrameImpl* webframe = mainFrameImpl();
999    if (webframe) {
1000        FrameView* view = webframe->frameView();
1001        if (view)
1002            view->serviceScriptedAnimations(convertSecondsToDOMTimeStamp(currentTime()));
1003    }
1004#endif
1005}
1006
1007void WebViewImpl::layout()
1008{
1009
1010    WebFrameImpl* webframe = mainFrameImpl();
1011    if (webframe) {
1012        // In order for our child HWNDs (NativeWindowWidgets) to update properly,
1013        // they need to be told that we are updating the screen.  The problem is
1014        // that the native widgets need to recalculate their clip region and not
1015        // overlap any of our non-native widgets.  To force the resizing, call
1016        // setFrameRect().  This will be a quick operation for most frames, but
1017        // the NativeWindowWidgets will update a proper clipping region.
1018        FrameView* view = webframe->frameView();
1019        if (view)
1020            view->setFrameRect(view->frameRect());
1021
1022        // setFrameRect may have the side-effect of causing existing page
1023        // layout to be invalidated, so layout needs to be called last.
1024
1025        webframe->layout();
1026    }
1027}
1028
1029#if USE(ACCELERATED_COMPOSITING)
1030void WebViewImpl::doPixelReadbackToCanvas(WebCanvas* canvas, const IntRect& rect)
1031{
1032#if USE(SKIA)
1033    PlatformContextSkia context(canvas);
1034
1035    // PlatformGraphicsContext is actually a pointer to PlatformContextSkia
1036    GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context));
1037    int bitmapHeight = canvas->getDevice()->accessBitmap(false).height();
1038#elif USE(CG)
1039    GraphicsContext gc(canvas);
1040    int bitmapHeight = CGBitmapContextGetHeight(reinterpret_cast<CGContextRef>(canvas));
1041#else
1042    notImplemented();
1043#endif
1044    // Compute rect to sample from inverted GPU buffer.
1045    IntRect invertRect(rect.x(), bitmapHeight - rect.maxY(), rect.width(), rect.height());
1046
1047    OwnPtr<ImageBuffer> imageBuffer(ImageBuffer::create(rect.size()));
1048    RefPtr<ByteArray> pixelArray(ByteArray::create(rect.width() * rect.height() * 4));
1049    if (imageBuffer.get() && pixelArray.get()) {
1050        m_layerRenderer->getFramebufferPixels(pixelArray->data(), invertRect);
1051        imageBuffer->putPremultipliedImageData(pixelArray.get(), rect.size(), IntRect(IntPoint(), rect.size()), IntPoint());
1052        gc.save();
1053        gc.translate(IntSize(0, bitmapHeight));
1054        gc.scale(FloatSize(1.0f, -1.0f));
1055        // Use invertRect in next line, so that transform above inverts it back to
1056        // desired destination rect.
1057        gc.drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, invertRect.location());
1058        gc.restore();
1059    }
1060}
1061#endif
1062
1063void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect)
1064{
1065    if (isAcceleratedCompositingActive()) {
1066#if USE(ACCELERATED_COMPOSITING)
1067        doComposite();
1068
1069        // If a canvas was passed in, we use it to grab a copy of the
1070        // freshly-rendered pixels.
1071        if (canvas) {
1072            // Clip rect to the confines of the rootLayerTexture.
1073            IntRect resizeRect(rect);
1074            resizeRect.intersect(IntRect(IntPoint(), m_layerRenderer->viewportSize()));
1075            doPixelReadbackToCanvas(canvas, resizeRect);
1076        }
1077#endif
1078    } else {
1079        WebFrameImpl* webframe = mainFrameImpl();
1080        if (webframe)
1081            webframe->paint(canvas, rect);
1082    }
1083}
1084
1085void WebViewImpl::themeChanged()
1086{
1087    if (!page())
1088        return;
1089    FrameView* view = page()->mainFrame()->view();
1090
1091    WebRect damagedRect(0, 0, m_size.width, m_size.height);
1092    view->invalidateRect(damagedRect);
1093}
1094
1095void WebViewImpl::composite(bool finish)
1096{
1097#if USE(ACCELERATED_COMPOSITING)
1098    TRACE_EVENT("WebViewImpl::composite", this, 0);
1099    if (m_recreatingGraphicsContext) {
1100        // reallocateRenderer will request a repaint whether or not it succeeded
1101        // in creating a new context.
1102        reallocateRenderer();
1103        m_recreatingGraphicsContext = false;
1104        return;
1105    }
1106    doComposite();
1107
1108    // Finish if requested.
1109    if (finish)
1110        m_layerRenderer->finish();
1111
1112    // Put result onscreen.
1113    m_layerRenderer->present();
1114
1115    GraphicsContext3D* context = m_layerRenderer->context();
1116    if (context->getExtensions()->getGraphicsResetStatusARB() != GraphicsContext3D::NO_ERROR) {
1117        // Trying to recover the context right here will not work if GPU process
1118        // died. This is because GpuChannelHost::OnErrorMessage will only be
1119        // called at the next iteration of the message loop, reverting our
1120        // recovery attempts here. Instead, we detach the root layer from the
1121        // renderer, recreate the renderer at the next message loop iteration
1122        // and request a repaint yet again.
1123        m_recreatingGraphicsContext = true;
1124        setRootLayerNeedsDisplay();
1125    }
1126#endif
1127}
1128
1129const WebInputEvent* WebViewImpl::m_currentInputEvent = 0;
1130
1131bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
1132{
1133    UserGestureIndicator gestureIndicator(WebInputEvent::isUserGestureEventType(inputEvent.type) ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);
1134
1135    // If we've started a drag and drop operation, ignore input events until
1136    // we're done.
1137    if (m_doingDragAndDrop)
1138        return true;
1139
1140    if (m_ignoreInputEvents)
1141        return true;
1142
1143    m_currentInputEvent = &inputEvent;
1144
1145    if (m_mouseCaptureNode.get() && WebInputEvent::isMouseEventType(inputEvent.type)) {
1146        // Save m_mouseCaptureNode since mouseCaptureLost() will clear it.
1147        RefPtr<Node> node = m_mouseCaptureNode;
1148
1149        // Not all platforms call mouseCaptureLost() directly.
1150        if (inputEvent.type == WebInputEvent::MouseUp)
1151            mouseCaptureLost();
1152
1153        AtomicString eventType;
1154        switch (inputEvent.type) {
1155        case WebInputEvent::MouseMove:
1156            eventType = eventNames().mousemoveEvent;
1157            break;
1158        case WebInputEvent::MouseLeave:
1159            eventType = eventNames().mouseoutEvent;
1160            break;
1161        case WebInputEvent::MouseDown:
1162            eventType = eventNames().mousedownEvent;
1163            break;
1164        case WebInputEvent::MouseUp:
1165            eventType = eventNames().mouseupEvent;
1166            break;
1167        default:
1168            ASSERT_NOT_REACHED();
1169        }
1170
1171        node->dispatchMouseEvent(
1172              PlatformMouseEventBuilder(mainFrameImpl()->frameView(), *static_cast<const WebMouseEvent*>(&inputEvent)),
1173              eventType, static_cast<const WebMouseEvent*>(&inputEvent)->clickCount);
1174        m_currentInputEvent = 0;
1175        return true;
1176    }
1177
1178    bool handled = true;
1179
1180    // FIXME: WebKit seems to always return false on mouse events processing
1181    // methods. For now we'll assume it has processed them (as we are only
1182    // interested in whether keyboard events are processed).
1183    switch (inputEvent.type) {
1184    case WebInputEvent::MouseMove:
1185        mouseMove(*static_cast<const WebMouseEvent*>(&inputEvent));
1186        break;
1187
1188    case WebInputEvent::MouseLeave:
1189        mouseLeave(*static_cast<const WebMouseEvent*>(&inputEvent));
1190        break;
1191
1192    case WebInputEvent::MouseWheel:
1193        handled = mouseWheel(*static_cast<const WebMouseWheelEvent*>(&inputEvent));
1194        break;
1195
1196    case WebInputEvent::MouseDown:
1197        mouseDown(*static_cast<const WebMouseEvent*>(&inputEvent));
1198        break;
1199
1200    case WebInputEvent::MouseUp:
1201        mouseUp(*static_cast<const WebMouseEvent*>(&inputEvent));
1202        break;
1203
1204    case WebInputEvent::RawKeyDown:
1205    case WebInputEvent::KeyDown:
1206    case WebInputEvent::KeyUp:
1207        handled = keyEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent));
1208        break;
1209
1210    case WebInputEvent::Char:
1211        handled = charEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent));
1212        break;
1213
1214#if ENABLE(TOUCH_EVENTS)
1215    case WebInputEvent::TouchStart:
1216    case WebInputEvent::TouchMove:
1217    case WebInputEvent::TouchEnd:
1218    case WebInputEvent::TouchCancel:
1219        handled = touchEvent(*static_cast<const WebTouchEvent*>(&inputEvent));
1220        break;
1221#endif
1222
1223    default:
1224        handled = false;
1225    }
1226
1227    m_currentInputEvent = 0;
1228
1229    return handled;
1230}
1231
1232void WebViewImpl::mouseCaptureLost()
1233{
1234    m_mouseCaptureNode = 0;
1235}
1236
1237void WebViewImpl::setFocus(bool enable)
1238{
1239    m_page->focusController()->setFocused(enable);
1240    if (enable) {
1241        // Note that we don't call setActive() when disabled as this cause extra
1242        // focus/blur events to be dispatched.
1243        m_page->focusController()->setActive(true);
1244        RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
1245        if (focusedFrame) {
1246            Node* focusedNode = focusedFrame->document()->focusedNode();
1247            if (focusedNode && focusedNode->isElementNode()
1248                && focusedFrame->selection()->selection().isNone()) {
1249                // If the selection was cleared while the WebView was not
1250                // focused, then the focus element shows with a focus ring but
1251                // no caret and does respond to keyboard inputs.
1252                Element* element = static_cast<Element*>(focusedNode);
1253                if (element->isTextFormControl())
1254                    element->updateFocusAppearance(true);
1255                else if (focusedNode->isContentEditable()) {
1256                    // updateFocusAppearance() selects all the text of
1257                    // contentseditable DIVs. So we set the selection explicitly
1258                    // instead. Note that this has the side effect of moving the
1259                    // caret back to the beginning of the text.
1260                    Position position(focusedNode, 0,
1261                                      Position::PositionIsOffsetInAnchor);
1262                    focusedFrame->selection()->setSelection(
1263                        VisibleSelection(position, SEL_DEFAULT_AFFINITY));
1264                }
1265            }
1266        }
1267        m_imeAcceptEvents = true;
1268    } else {
1269        hideAutoFillPopup();
1270        hideSelectPopup();
1271
1272        // Clear focus on the currently focused frame if any.
1273        if (!m_page.get())
1274            return;
1275
1276        Frame* frame = m_page->mainFrame();
1277        if (!frame)
1278            return;
1279
1280        RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
1281        if (focusedFrame.get()) {
1282            // Finish an ongoing composition to delete the composition node.
1283            Editor* editor = focusedFrame->editor();
1284            if (editor && editor->hasComposition())
1285                editor->confirmComposition();
1286            m_imeAcceptEvents = false;
1287        }
1288    }
1289}
1290
1291bool WebViewImpl::setComposition(
1292    const WebString& text,
1293    const WebVector<WebCompositionUnderline>& underlines,
1294    int selectionStart,
1295    int selectionEnd)
1296{
1297    Frame* focused = focusedWebCoreFrame();
1298    if (!focused || !m_imeAcceptEvents)
1299        return false;
1300    Editor* editor = focused->editor();
1301    if (!editor)
1302        return false;
1303
1304    // The input focus has been moved to another WebWidget object.
1305    // We should use this |editor| object only to complete the ongoing
1306    // composition.
1307    if (!editor->canEdit() && !editor->hasComposition())
1308        return false;
1309
1310    // We should verify the parent node of this IME composition node are
1311    // editable because JavaScript may delete a parent node of the composition
1312    // node. In this case, WebKit crashes while deleting texts from the parent
1313    // node, which doesn't exist any longer.
1314    PassRefPtr<Range> range = editor->compositionRange();
1315    if (range) {
1316        const Node* node = range->startContainer();
1317        if (!node || !node->isContentEditable())
1318            return false;
1319    }
1320
1321    // If we're not going to fire a keypress event, then the keydown event was
1322    // canceled.  In that case, cancel any existing composition.
1323    if (text.isEmpty() || m_suppressNextKeypressEvent) {
1324        // A browser process sent an IPC message which does not contain a valid
1325        // string, which means an ongoing composition has been canceled.
1326        // If the ongoing composition has been canceled, replace the ongoing
1327        // composition string with an empty string and complete it.
1328        String emptyString;
1329        Vector<CompositionUnderline> emptyUnderlines;
1330        editor->setComposition(emptyString, emptyUnderlines, 0, 0);
1331        return text.isEmpty();
1332    }
1333
1334    // When the range of composition underlines overlap with the range between
1335    // selectionStart and selectionEnd, WebKit somehow won't paint the selection
1336    // at all (see InlineTextBox::paint() function in InlineTextBox.cpp).
1337    // But the selection range actually takes effect.
1338    editor->setComposition(String(text),
1339                           CompositionUnderlineVectorBuilder(underlines),
1340                           selectionStart, selectionEnd);
1341
1342    return editor->hasComposition();
1343}
1344
1345bool WebViewImpl::confirmComposition()
1346{
1347    return confirmComposition(WebString());
1348}
1349
1350bool WebViewImpl::confirmComposition(const WebString& text)
1351{
1352    Frame* focused = focusedWebCoreFrame();
1353    if (!focused || !m_imeAcceptEvents)
1354        return false;
1355    Editor* editor = focused->editor();
1356    if (!editor || (!editor->hasComposition() && !text.length()))
1357        return false;
1358
1359    // We should verify the parent node of this IME composition node are
1360    // editable because JavaScript may delete a parent node of the composition
1361    // node. In this case, WebKit crashes while deleting texts from the parent
1362    // node, which doesn't exist any longer.
1363    PassRefPtr<Range> range = editor->compositionRange();
1364    if (range) {
1365        const Node* node = range->startContainer();
1366        if (!node || !node->isContentEditable())
1367            return false;
1368    }
1369
1370    if (editor->hasComposition()) {
1371        if (text.length())
1372            editor->confirmComposition(String(text));
1373        else
1374            editor->confirmComposition();
1375    } else
1376        editor->insertText(String(text), 0);
1377
1378    return true;
1379}
1380
1381WebTextInputType WebViewImpl::textInputType()
1382{
1383    WebTextInputType type = WebTextInputTypeNone;
1384    const Frame* focused = focusedWebCoreFrame();
1385    if (!focused)
1386        return type;
1387
1388    const Editor* editor = focused->editor();
1389    if (!editor || !editor->canEdit())
1390        return type;
1391
1392    SelectionController* controller = focused->selection();
1393    if (!controller)
1394        return type;
1395
1396    const Node* node = controller->start().deprecatedNode();
1397    if (!node)
1398        return type;
1399
1400    // FIXME: Support more text input types when necessary, eg. Number,
1401    // Date, Email, URL, etc.
1402    if (controller->isInPasswordField())
1403        type = WebTextInputTypePassword;
1404    else if (node->shouldUseInputMethod())
1405        type = WebTextInputTypeText;
1406
1407    return type;
1408}
1409
1410WebRect WebViewImpl::caretOrSelectionBounds()
1411{
1412    WebRect rect;
1413    const Frame* focused = focusedWebCoreFrame();
1414    if (!focused)
1415        return rect;
1416
1417    SelectionController* controller = focused->selection();
1418    if (!controller)
1419        return rect;
1420
1421    const FrameView* view = focused->view();
1422    if (!view)
1423        return rect;
1424
1425    const Node* node = controller->base().containerNode();
1426    if (!node || !node->renderer())
1427        return rect;
1428
1429    if (controller->isCaret())
1430        rect = view->contentsToWindow(controller->absoluteCaretBounds());
1431    else if (controller->isRange()) {
1432        node = controller->extent().containerNode();
1433        RefPtr<Range> range = controller->toNormalizedRange();
1434        if (!node || !node->renderer() || !range)
1435            return rect;
1436        rect = view->contentsToWindow(focused->editor()->firstRectForRange(range.get()));
1437    }
1438    return rect;
1439}
1440
1441bool WebViewImpl::selectionRange(WebPoint& start, WebPoint& end) const
1442{
1443    const Frame* frame = focusedWebCoreFrame();
1444    if (!frame)
1445        return false;
1446    RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange();
1447    RefPtr<Range> range(Range::create(selectedRange->startContainer()->document(),
1448                                      selectedRange->startContainer(),
1449                                      selectedRange->startOffset(),
1450                                      selectedRange->startContainer(),
1451                                      selectedRange->startOffset()));
1452
1453    IntRect rect = frame->editor()->firstRectForRange(range.get());
1454    start.x = rect.x();
1455    start.y = rect.y() + rect.height() - 1;
1456
1457    range = Range::create(selectedRange->endContainer()->document(),
1458                          selectedRange->endContainer(),
1459                          selectedRange->endOffset(),
1460                          selectedRange->endContainer(),
1461                          selectedRange->endOffset());
1462
1463    rect = frame->editor()->firstRectForRange(range.get());
1464    end.x = rect.x() + rect.width() - 1;
1465    end.y = rect.y() + rect.height() - 1;
1466
1467    start = frame->view()->contentsToWindow(start);
1468    end = frame->view()->contentsToWindow(end);
1469    return true;
1470}
1471
1472void WebViewImpl::setTextDirection(WebTextDirection direction)
1473{
1474    // The Editor::setBaseWritingDirection() function checks if we can change
1475    // the text direction of the selected node and updates its DOM "dir"
1476    // attribute and its CSS "direction" property.
1477    // So, we just call the function as Safari does.
1478    const Frame* focused = focusedWebCoreFrame();
1479    if (!focused)
1480        return;
1481
1482    Editor* editor = focused->editor();
1483    if (!editor || !editor->canEdit())
1484        return;
1485
1486    switch (direction) {
1487    case WebTextDirectionDefault:
1488        editor->setBaseWritingDirection(NaturalWritingDirection);
1489        break;
1490
1491    case WebTextDirectionLeftToRight:
1492        editor->setBaseWritingDirection(LeftToRightWritingDirection);
1493        break;
1494
1495    case WebTextDirectionRightToLeft:
1496        editor->setBaseWritingDirection(RightToLeftWritingDirection);
1497        break;
1498
1499    default:
1500        notImplemented();
1501        break;
1502    }
1503}
1504
1505bool WebViewImpl::isAcceleratedCompositingActive() const
1506{
1507#if USE(ACCELERATED_COMPOSITING)
1508    return m_isAcceleratedCompositingActive;
1509#else
1510    return false;
1511#endif
1512}
1513
1514// WebView --------------------------------------------------------------------
1515
1516WebSettings* WebViewImpl::settings()
1517{
1518    if (!m_webSettings.get())
1519        m_webSettings.set(new WebSettingsImpl(m_page->settings()));
1520    ASSERT(m_webSettings.get());
1521    return m_webSettings.get();
1522}
1523
1524WebString WebViewImpl::pageEncoding() const
1525{
1526    if (!m_page.get())
1527        return WebString();
1528
1529    return m_page->mainFrame()->document()->loader()->writer()->encoding();
1530}
1531
1532void WebViewImpl::setPageEncoding(const WebString& encodingName)
1533{
1534    if (!m_page.get())
1535        return;
1536
1537    // Only change override encoding, don't change default encoding.
1538    // Note that the new encoding must be 0 if it isn't supposed to be set.
1539    String newEncodingName;
1540    if (!encodingName.isEmpty())
1541        newEncodingName = encodingName;
1542    m_page->mainFrame()->loader()->reloadWithOverrideEncoding(newEncodingName);
1543}
1544
1545bool WebViewImpl::dispatchBeforeUnloadEvent()
1546{
1547    // FIXME: This should really cause a recursive depth-first walk of all
1548    // frames in the tree, calling each frame's onbeforeunload.  At the moment,
1549    // we're consistent with Safari 3.1, not IE/FF.
1550    Frame* frame = m_page->mainFrame();
1551    if (!frame)
1552        return true;
1553
1554    return frame->loader()->shouldClose();
1555}
1556
1557void WebViewImpl::dispatchUnloadEvent()
1558{
1559    // Run unload handlers.
1560    m_page->mainFrame()->loader()->closeURL();
1561}
1562
1563WebFrame* WebViewImpl::mainFrame()
1564{
1565    return mainFrameImpl();
1566}
1567
1568WebFrame* WebViewImpl::findFrameByName(
1569    const WebString& name, WebFrame* relativeToFrame)
1570{
1571    if (!relativeToFrame)
1572        relativeToFrame = mainFrame();
1573    Frame* frame = static_cast<WebFrameImpl*>(relativeToFrame)->frame();
1574    frame = frame->tree()->find(name);
1575    return WebFrameImpl::fromFrame(frame);
1576}
1577
1578WebFrame* WebViewImpl::focusedFrame()
1579{
1580    return WebFrameImpl::fromFrame(focusedWebCoreFrame());
1581}
1582
1583void WebViewImpl::setFocusedFrame(WebFrame* frame)
1584{
1585    if (!frame) {
1586        // Clears the focused frame if any.
1587        Frame* frame = focusedWebCoreFrame();
1588        if (frame)
1589            frame->selection()->setFocused(false);
1590        return;
1591    }
1592    WebFrameImpl* frameImpl = static_cast<WebFrameImpl*>(frame);
1593    Frame* webcoreFrame = frameImpl->frame();
1594    webcoreFrame->page()->focusController()->setFocusedFrame(webcoreFrame);
1595}
1596
1597void WebViewImpl::setInitialFocus(bool reverse)
1598{
1599    if (!m_page.get())
1600        return;
1601
1602    // Since we don't have a keyboard event, we'll create one.
1603    WebKeyboardEvent keyboardEvent;
1604    keyboardEvent.type = WebInputEvent::RawKeyDown;
1605    if (reverse)
1606        keyboardEvent.modifiers = WebInputEvent::ShiftKey;
1607
1608    // VK_TAB which is only defined on Windows.
1609    keyboardEvent.windowsKeyCode = 0x09;
1610    PlatformKeyboardEventBuilder platformEvent(keyboardEvent);
1611    RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0);
1612
1613    Frame* frame = page()->focusController()->focusedOrMainFrame();
1614    if (Document* document = frame->document())
1615        document->setFocusedNode(0);
1616    page()->focusController()->setInitialFocus(
1617        reverse ? FocusDirectionBackward : FocusDirectionForward,
1618        webkitEvent.get());
1619}
1620
1621void WebViewImpl::clearFocusedNode()
1622{
1623    if (!m_page.get())
1624        return;
1625
1626    RefPtr<Frame> frame = m_page->mainFrame();
1627    if (!frame.get())
1628        return;
1629
1630    RefPtr<Document> document = frame->document();
1631    if (!document.get())
1632        return;
1633
1634    RefPtr<Node> oldFocusedNode = document->focusedNode();
1635
1636    // Clear the focused node.
1637    document->setFocusedNode(0);
1638
1639    if (!oldFocusedNode.get())
1640        return;
1641
1642    // If a text field has focus, we need to make sure the selection controller
1643    // knows to remove selection from it. Otherwise, the text field is still
1644    // processing keyboard events even though focus has been moved to the page and
1645    // keystrokes get eaten as a result.
1646    if (oldFocusedNode->hasTagName(HTMLNames::textareaTag)
1647        || (oldFocusedNode->hasTagName(HTMLNames::inputTag)
1648            && static_cast<HTMLInputElement*>(oldFocusedNode.get())->isTextField())) {
1649        // Clear the selection.
1650        SelectionController* selection = frame->selection();
1651        selection->clear();
1652    }
1653}
1654
1655void WebViewImpl::scrollFocusedNodeIntoView()
1656{
1657    Node* focusedNode = focusedWebCoreNode();
1658    if (focusedNode && focusedNode->isElementNode()) {
1659        Element* elementNode = static_cast<Element*>(focusedNode);
1660        elementNode->scrollIntoViewIfNeeded(true);
1661    }
1662}
1663
1664double WebViewImpl::zoomLevel()
1665{
1666    return m_zoomLevel;
1667}
1668
1669double WebViewImpl::setZoomLevel(bool textOnly, double zoomLevel)
1670{
1671    if (zoomLevel < m_minimumZoomLevel)
1672        m_zoomLevel = m_minimumZoomLevel;
1673    else if (zoomLevel > m_maximumZoomLevel)
1674        m_zoomLevel = m_maximumZoomLevel;
1675    else
1676        m_zoomLevel = zoomLevel;
1677
1678    Frame* frame = mainFrameImpl()->frame();
1679    WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
1680    if (pluginContainer)
1681        pluginContainer->plugin()->setZoomLevel(m_zoomLevel, textOnly);
1682    else {
1683        float zoomFactor = static_cast<float>(zoomLevelToZoomFactor(m_zoomLevel));
1684        if (textOnly)
1685            frame->setPageAndTextZoomFactors(1, zoomFactor);
1686        else
1687            frame->setPageAndTextZoomFactors(zoomFactor, 1);
1688    }
1689    return m_zoomLevel;
1690}
1691
1692void WebViewImpl::zoomLimitsChanged(double minimumZoomLevel,
1693                                    double maximumZoomLevel)
1694{
1695    m_minimumZoomLevel = minimumZoomLevel;
1696    m_maximumZoomLevel = maximumZoomLevel;
1697    m_client->zoomLimitsChanged(m_minimumZoomLevel, m_maximumZoomLevel);
1698}
1699
1700void WebViewImpl::fullFramePluginZoomLevelChanged(double zoomLevel)
1701{
1702    if (zoomLevel == m_zoomLevel)
1703        return;
1704
1705    m_zoomLevel = std::max(std::min(zoomLevel, m_maximumZoomLevel), m_minimumZoomLevel);
1706    m_client->zoomLevelChanged();
1707}
1708
1709double WebView::zoomLevelToZoomFactor(double zoomLevel)
1710{
1711    return std::pow(textSizeMultiplierRatio, zoomLevel);
1712}
1713
1714double WebView::zoomFactorToZoomLevel(double factor)
1715{
1716    // Since factor = 1.2^level, level = log(factor) / log(1.2)
1717    return log(factor) / log(textSizeMultiplierRatio);
1718}
1719
1720void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action,
1721                                           const WebPoint& location)
1722{
1723    HitTestResult result =
1724        hitTestResultForWindowPos(location);
1725    RefPtr<Node> node = result.innerNonSharedNode();
1726    if (!node->hasTagName(HTMLNames::videoTag) && !node->hasTagName(HTMLNames::audioTag))
1727      return;
1728
1729    RefPtr<HTMLMediaElement> mediaElement =
1730        static_pointer_cast<HTMLMediaElement>(node);
1731    switch (action.type) {
1732    case WebMediaPlayerAction::Play:
1733        if (action.enable)
1734            mediaElement->play(mediaElement->processingUserGesture());
1735        else
1736            mediaElement->pause(mediaElement->processingUserGesture());
1737        break;
1738    case WebMediaPlayerAction::Mute:
1739        mediaElement->setMuted(action.enable);
1740        break;
1741    case WebMediaPlayerAction::Loop:
1742        mediaElement->setLoop(action.enable);
1743        break;
1744    case WebMediaPlayerAction::Controls:
1745        mediaElement->setControls(action.enable);
1746        break;
1747    default:
1748        ASSERT_NOT_REACHED();
1749    }
1750}
1751
1752void WebViewImpl::copyImageAt(const WebPoint& point)
1753{
1754    if (!m_page.get())
1755        return;
1756
1757    HitTestResult result = hitTestResultForWindowPos(point);
1758
1759    if (result.absoluteImageURL().isEmpty()) {
1760        // There isn't actually an image at these coordinates.  Might be because
1761        // the window scrolled while the context menu was open or because the page
1762        // changed itself between when we thought there was an image here and when
1763        // we actually tried to retreive the image.
1764        //
1765        // FIXME: implement a cache of the most recent HitTestResult to avoid having
1766        //        to do two hit tests.
1767        return;
1768    }
1769
1770    m_page->mainFrame()->editor()->copyImage(result);
1771}
1772
1773void WebViewImpl::dragSourceEndedAt(
1774    const WebPoint& clientPoint,
1775    const WebPoint& screenPoint,
1776    WebDragOperation operation)
1777{
1778    PlatformMouseEvent pme(clientPoint,
1779                           screenPoint,
1780                           LeftButton, MouseEventMoved, 0, false, false, false,
1781                           false, 0);
1782    m_page->mainFrame()->eventHandler()->dragSourceEndedAt(pme,
1783        static_cast<DragOperation>(operation));
1784    m_dragScrollTimer->stop();
1785}
1786
1787void WebViewImpl::dragSourceMovedTo(
1788    const WebPoint& clientPoint,
1789    const WebPoint& screenPoint,
1790    WebDragOperation operation)
1791{
1792    m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint);
1793}
1794
1795void WebViewImpl::dragSourceSystemDragEnded()
1796{
1797    // It's possible for us to get this callback while not doing a drag if
1798    // it's from a previous page that got unloaded.
1799    if (m_doingDragAndDrop) {
1800        m_page->dragController()->dragEnded();
1801        m_doingDragAndDrop = false;
1802    }
1803}
1804
1805WebDragOperation WebViewImpl::dragTargetDragEnter(
1806    const WebDragData& webDragData,
1807    const WebPoint& clientPoint,
1808    const WebPoint& screenPoint,
1809    WebDragOperationsMask operationsAllowed)
1810{
1811    ASSERT(!m_currentDragData.get());
1812
1813    m_currentDragData = webDragData;
1814    m_operationsAllowed = operationsAllowed;
1815
1816    return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragEnter);
1817}
1818
1819WebDragOperation WebViewImpl::dragTargetDragOver(
1820    const WebPoint& clientPoint,
1821    const WebPoint& screenPoint,
1822    WebDragOperationsMask operationsAllowed)
1823{
1824    m_operationsAllowed = operationsAllowed;
1825
1826    return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragOver);
1827}
1828
1829void WebViewImpl::dragTargetDragLeave()
1830{
1831    ASSERT(m_currentDragData.get());
1832
1833    DragData dragData(
1834        m_currentDragData.get(),
1835        IntPoint(),
1836        IntPoint(),
1837        static_cast<DragOperation>(m_operationsAllowed));
1838
1839    m_page->dragController()->dragExited(&dragData);
1840
1841    // FIXME: why is the drag scroll timer not stopped here?
1842
1843    m_dragOperation = WebDragOperationNone;
1844    m_currentDragData = 0;
1845}
1846
1847void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint,
1848                                 const WebPoint& screenPoint)
1849{
1850    ASSERT(m_currentDragData.get());
1851
1852    // If this webview transitions from the "drop accepting" state to the "not
1853    // accepting" state, then our IPC message reply indicating that may be in-
1854    // flight, or else delayed by javascript processing in this webview.  If a
1855    // drop happens before our IPC reply has reached the browser process, then
1856    // the browser forwards the drop to this webview.  So only allow a drop to
1857    // proceed if our webview m_dragOperation state is not DragOperationNone.
1858
1859    if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop.
1860        dragTargetDragLeave();
1861        return;
1862    }
1863
1864    DragData dragData(
1865        m_currentDragData.get(),
1866        clientPoint,
1867        screenPoint,
1868        static_cast<DragOperation>(m_operationsAllowed));
1869
1870    m_page->dragController()->performDrag(&dragData);
1871
1872    m_dragOperation = WebDragOperationNone;
1873    m_currentDragData = 0;
1874
1875    m_dragScrollTimer->stop();
1876}
1877
1878WebDragOperation WebViewImpl::dragTargetDragEnterOrOver(const WebPoint& clientPoint, const WebPoint& screenPoint, DragAction dragAction)
1879{
1880    ASSERT(m_currentDragData.get());
1881
1882    DragData dragData(
1883        m_currentDragData.get(),
1884        clientPoint,
1885        screenPoint,
1886        static_cast<DragOperation>(m_operationsAllowed));
1887
1888    DragOperation dropEffect;
1889    if (dragAction == DragEnter)
1890        dropEffect = m_page->dragController()->dragEntered(&dragData);
1891    else
1892        dropEffect = m_page->dragController()->dragUpdated(&dragData);
1893
1894    // Mask the drop effect operation against the drag source's allowed operations.
1895    if (!(dropEffect & dragData.draggingSourceOperationMask()))
1896        dropEffect = DragOperationNone;
1897
1898     m_dragOperation = static_cast<WebDragOperation>(dropEffect);
1899
1900    if (dragAction == DragOver)
1901        m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint);
1902    else
1903        m_dragScrollTimer->stop();
1904
1905    return m_dragOperation;
1906}
1907
1908unsigned long WebViewImpl::createUniqueIdentifierForRequest()
1909{
1910    if (m_page)
1911        return m_page->progress()->createUniqueIdentifier();
1912    return 0;
1913}
1914
1915void WebViewImpl::inspectElementAt(const WebPoint& point)
1916{
1917    if (!m_page.get())
1918        return;
1919
1920    if (point.x == -1 || point.y == -1)
1921        m_page->inspectorController()->inspect(0);
1922    else {
1923        HitTestResult result = hitTestResultForWindowPos(point);
1924
1925        if (!result.innerNonSharedNode())
1926            return;
1927
1928        m_page->inspectorController()->inspect(result.innerNonSharedNode());
1929    }
1930}
1931
1932WebString WebViewImpl::inspectorSettings() const
1933{
1934    return m_inspectorSettings;
1935}
1936
1937void WebViewImpl::setInspectorSettings(const WebString& settings)
1938{
1939    m_inspectorSettings = settings;
1940}
1941
1942bool WebViewImpl::inspectorSetting(const WebString& key, WebString* value) const
1943{
1944    if (!m_inspectorSettingsMap->contains(key))
1945        return false;
1946    *value = m_inspectorSettingsMap->get(key);
1947    return true;
1948}
1949
1950void WebViewImpl::setInspectorSetting(const WebString& key,
1951                                      const WebString& value)
1952{
1953    m_inspectorSettingsMap->set(key, value);
1954    client()->didUpdateInspectorSetting(key, value);
1955}
1956
1957WebDevToolsAgent* WebViewImpl::devToolsAgent()
1958{
1959    return m_devToolsAgent.get();
1960}
1961
1962WebAccessibilityObject WebViewImpl::accessibilityObject()
1963{
1964    if (!mainFrameImpl())
1965        return WebAccessibilityObject();
1966
1967    Document* document = mainFrameImpl()->frame()->document();
1968    return WebAccessibilityObject(
1969        document->axObjectCache()->getOrCreate(document->renderer()));
1970}
1971
1972void WebViewImpl::applyAutoFillSuggestions(
1973    const WebNode& node,
1974    const WebVector<WebString>& names,
1975    const WebVector<WebString>& labels,
1976    const WebVector<WebString>& icons,
1977    const WebVector<int>& uniqueIDs,
1978    int separatorIndex)
1979{
1980    ASSERT(names.size() == labels.size());
1981    ASSERT(names.size() == uniqueIDs.size());
1982    ASSERT(separatorIndex < static_cast<int>(names.size()));
1983
1984    if (names.isEmpty()) {
1985        hideAutoFillPopup();
1986        return;
1987    }
1988
1989    RefPtr<Node> focusedNode = focusedWebCoreNode();
1990    // If the node for which we queried the AutoFill suggestions is not the
1991    // focused node, then we have nothing to do.  FIXME: also check the
1992    // caret is at the end and that the text has not changed.
1993    if (!focusedNode || focusedNode != PassRefPtr<Node>(node)) {
1994        hideAutoFillPopup();
1995        return;
1996    }
1997
1998    HTMLInputElement* inputElem =
1999        static_cast<HTMLInputElement*>(focusedNode.get());
2000
2001    // The first time the AutoFill popup is shown we'll create the client and
2002    // the popup.
2003    if (!m_autoFillPopupClient.get())
2004        m_autoFillPopupClient.set(new AutoFillPopupMenuClient);
2005
2006    m_autoFillPopupClient->initialize(
2007        inputElem, names, labels, icons, uniqueIDs, separatorIndex);
2008
2009    if (!m_autoFillPopup.get()) {
2010        m_autoFillPopup = PopupContainer::create(m_autoFillPopupClient.get(),
2011                                                 PopupContainer::Suggestion,
2012                                                 autoFillPopupSettings);
2013    }
2014
2015    if (m_autoFillPopupShowing) {
2016        refreshAutoFillPopup();
2017    } else {
2018        m_autoFillPopup->showInRect(focusedNode->getRect(), focusedNode->ownerDocument()->view(), 0);
2019        m_autoFillPopupShowing = true;
2020    }
2021}
2022
2023void WebViewImpl::hidePopups()
2024{
2025    hideSelectPopup();
2026    hideAutoFillPopup();
2027}
2028
2029void WebViewImpl::performCustomContextMenuAction(unsigned action)
2030{
2031    if (!m_page)
2032        return;
2033    ContextMenu* menu = m_page->contextMenuController()->contextMenu();
2034    if (!menu)
2035        return;
2036    ContextMenuItem* item = menu->itemWithAction(static_cast<ContextMenuAction>(ContextMenuItemBaseCustomTag + action));
2037    if (item)
2038        m_page->contextMenuController()->contextMenuItemSelected(item);
2039    m_page->contextMenuController()->clearContextMenu();
2040}
2041
2042// WebView --------------------------------------------------------------------
2043
2044void WebViewImpl::setIsTransparent(bool isTransparent)
2045{
2046    // Set any existing frames to be transparent.
2047    Frame* frame = m_page->mainFrame();
2048    while (frame) {
2049        frame->view()->setTransparent(isTransparent);
2050        frame = frame->tree()->traverseNext();
2051    }
2052
2053    // Future frames check this to know whether to be transparent.
2054    m_isTransparent = isTransparent;
2055}
2056
2057bool WebViewImpl::isTransparent() const
2058{
2059    return m_isTransparent;
2060}
2061
2062void WebViewImpl::setIsActive(bool active)
2063{
2064    if (page() && page()->focusController())
2065        page()->focusController()->setActive(active);
2066}
2067
2068bool WebViewImpl::isActive() const
2069{
2070    return (page() && page()->focusController()) ? page()->focusController()->isActive() : false;
2071}
2072
2073void WebViewImpl::setDomainRelaxationForbidden(bool forbidden, const WebString& scheme)
2074{
2075    SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(forbidden, String(scheme));
2076}
2077
2078void WebViewImpl::setScrollbarColors(unsigned inactiveColor,
2079                                     unsigned activeColor,
2080                                     unsigned trackColor) {
2081#if OS(LINUX) || OS(FREEBSD)
2082    PlatformThemeChromiumGtk::setScrollbarColors(inactiveColor,
2083                                                 activeColor,
2084                                                 trackColor);
2085#endif
2086}
2087
2088void WebViewImpl::setSelectionColors(unsigned activeBackgroundColor,
2089                                     unsigned activeForegroundColor,
2090                                     unsigned inactiveBackgroundColor,
2091                                     unsigned inactiveForegroundColor) {
2092#if OS(LINUX) || OS(FREEBSD)
2093    RenderThemeChromiumLinux::setSelectionColors(activeBackgroundColor,
2094                                                 activeForegroundColor,
2095                                                 inactiveBackgroundColor,
2096                                                 inactiveForegroundColor);
2097    theme()->platformColorsDidChange();
2098#endif
2099}
2100
2101void WebView::addUserScript(const WebString& sourceCode,
2102                            const WebVector<WebString>& patternsIn,
2103                            WebView::UserScriptInjectAt injectAt,
2104                            WebView::UserContentInjectIn injectIn)
2105{
2106    OwnPtr<Vector<String> > patterns(new Vector<String>);
2107    for (size_t i = 0; i < patternsIn.size(); ++i)
2108        patterns->append(patternsIn[i]);
2109
2110    PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
2111    RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create());
2112    pageGroup->addUserScriptToWorld(world.get(), sourceCode, WebURL(), patterns.release(), 0,
2113                                    static_cast<UserScriptInjectionTime>(injectAt),
2114                                    static_cast<UserContentInjectedFrames>(injectIn));
2115}
2116
2117void WebView::addUserStyleSheet(const WebString& sourceCode,
2118                                const WebVector<WebString>& patternsIn,
2119                                WebView::UserContentInjectIn injectIn,
2120                                WebView::UserStyleInjectionTime injectionTime)
2121{
2122    OwnPtr<Vector<String> > patterns(new Vector<String>);
2123    for (size_t i = 0; i < patternsIn.size(); ++i)
2124        patterns->append(patternsIn[i]);
2125
2126    PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
2127    RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create());
2128
2129    // FIXME: Current callers always want the level to be "author". It probably makes sense to let
2130    // callers specify this though, since in other cases the caller will probably want "user" level.
2131    //
2132    // FIXME: It would be nice to populate the URL correctly, instead of passing an empty URL.
2133    pageGroup->addUserStyleSheetToWorld(world.get(), sourceCode, WebURL(), patterns.release(), 0,
2134                                        static_cast<UserContentInjectedFrames>(injectIn),
2135                                        UserStyleAuthorLevel,
2136                                        static_cast<WebCore::UserStyleInjectionTime>(injectionTime));
2137}
2138
2139void WebView::removeAllUserContent()
2140{
2141    PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
2142    pageGroup->removeAllUserContent();
2143}
2144
2145void WebViewImpl::didCommitLoad(bool* isNewNavigation)
2146{
2147    if (isNewNavigation)
2148        *isNewNavigation = m_observedNewNavigation;
2149
2150#ifndef NDEBUG
2151    ASSERT(!m_observedNewNavigation
2152        || m_page->mainFrame()->loader()->documentLoader() == m_newNavigationLoader);
2153    m_newNavigationLoader = 0;
2154#endif
2155    m_observedNewNavigation = false;
2156}
2157
2158bool WebViewImpl::useExternalPopupMenus()
2159{
2160    return shouldUseExternalPopupMenus;
2161}
2162
2163bool WebViewImpl::navigationPolicyFromMouseEvent(unsigned short button,
2164                                                 bool ctrl, bool shift,
2165                                                 bool alt, bool meta,
2166                                                 WebNavigationPolicy* policy)
2167{
2168#if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD) || OS(SOLARIS)
2169    const bool newTabModifier = (button == 1) || ctrl;
2170#elif OS(DARWIN)
2171    const bool newTabModifier = (button == 1) || meta;
2172#endif
2173    if (!newTabModifier && !shift && !alt)
2174      return false;
2175
2176    ASSERT(policy);
2177    if (newTabModifier) {
2178        if (shift)
2179          *policy = WebNavigationPolicyNewForegroundTab;
2180        else
2181          *policy = WebNavigationPolicyNewBackgroundTab;
2182    } else {
2183        if (shift)
2184          *policy = WebNavigationPolicyNewWindow;
2185        else
2186          *policy = WebNavigationPolicyDownload;
2187    }
2188    return true;
2189}
2190
2191void WebViewImpl::startDragging(const WebDragData& dragData,
2192                                WebDragOperationsMask mask,
2193                                const WebImage& dragImage,
2194                                const WebPoint& dragImageOffset)
2195{
2196    if (!m_client)
2197        return;
2198    ASSERT(!m_doingDragAndDrop);
2199    m_doingDragAndDrop = true;
2200    m_client->startDragging(dragData, mask, dragImage, dragImageOffset);
2201}
2202
2203void WebViewImpl::observeNewNavigation()
2204{
2205    m_observedNewNavigation = true;
2206#ifndef NDEBUG
2207    m_newNavigationLoader = m_page->mainFrame()->loader()->documentLoader();
2208#endif
2209}
2210
2211void WebViewImpl::setIgnoreInputEvents(bool newValue)
2212{
2213    ASSERT(m_ignoreInputEvents != newValue);
2214    m_ignoreInputEvents = newValue;
2215}
2216
2217#if ENABLE(NOTIFICATIONS)
2218NotificationPresenterImpl* WebViewImpl::notificationPresenterImpl()
2219{
2220    if (!m_notificationPresenter.isInitialized() && m_client)
2221        m_notificationPresenter.initialize(m_client->notificationPresenter());
2222    return &m_notificationPresenter;
2223}
2224#endif
2225
2226void WebViewImpl::refreshAutoFillPopup()
2227{
2228    ASSERT(m_autoFillPopupShowing);
2229
2230    // Hide the popup if it has become empty.
2231    if (!m_autoFillPopupClient->listSize()) {
2232        hideAutoFillPopup();
2233        return;
2234    }
2235
2236    IntRect oldBounds = m_autoFillPopup->frameRect();
2237    m_autoFillPopup->refresh(focusedWebCoreNode()->getRect());
2238    IntRect newBounds = m_autoFillPopup->frameRect();
2239    // Let's resize the backing window if necessary.
2240    if (oldBounds != newBounds) {
2241        WebPopupMenuImpl* popupMenu =
2242            static_cast<WebPopupMenuImpl*>(m_autoFillPopup->client());
2243        if (popupMenu)
2244            popupMenu->client()->setWindowRect(newBounds);
2245    }
2246}
2247
2248Node* WebViewImpl::focusedWebCoreNode()
2249{
2250    Frame* frame = m_page->focusController()->focusedFrame();
2251    if (!frame)
2252        return 0;
2253
2254    Document* document = frame->document();
2255    if (!document)
2256        return 0;
2257
2258    return document->focusedNode();
2259}
2260
2261HitTestResult WebViewImpl::hitTestResultForWindowPos(const IntPoint& pos)
2262{
2263    IntPoint docPoint(m_page->mainFrame()->view()->windowToContents(pos));
2264    return m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(docPoint, false);
2265}
2266
2267void WebViewImpl::setTabsToLinks(bool enable)
2268{
2269    m_tabsToLinks = enable;
2270}
2271
2272bool WebViewImpl::tabsToLinks() const
2273{
2274    return m_tabsToLinks;
2275}
2276
2277#if USE(ACCELERATED_COMPOSITING)
2278bool WebViewImpl::allowsAcceleratedCompositing()
2279{
2280    return !m_compositorCreationFailed;
2281}
2282
2283bool WebViewImpl::pageHasRTLStyle() const
2284{
2285    if (!page())
2286        return false;
2287    Document* document = page()->mainFrame()->document();
2288    if (!document)
2289        return false;
2290    RenderView* renderView = document->renderView();
2291    if (!renderView)
2292        return false;
2293    RenderStyle* style = renderView->style();
2294    if (!style)
2295        return false;
2296    return (style->direction() == RTL);
2297}
2298
2299void WebViewImpl::setRootGraphicsLayer(WebCore::PlatformLayer* layer)
2300{
2301    setIsAcceleratedCompositingActive(layer);
2302    if (m_layerRenderer)
2303        m_layerRenderer->setRootLayer(layer);
2304
2305    IntRect damagedRect(0, 0, m_size.width, m_size.height);
2306    if (m_isAcceleratedCompositingActive)
2307        invalidateRootLayerRect(damagedRect);
2308    else
2309        m_client->didInvalidateRect(damagedRect);
2310}
2311
2312void WebViewImpl::setRootLayerNeedsDisplay()
2313{
2314    m_client->scheduleComposite();
2315}
2316
2317
2318void WebViewImpl::scrollRootLayerRect(const IntSize& scrollDelta, const IntRect& clipRect)
2319{
2320    updateLayerRendererViewport();
2321    setRootLayerNeedsDisplay();
2322}
2323
2324void WebViewImpl::invalidateRootLayerRect(const IntRect& rect)
2325{
2326    ASSERT(m_layerRenderer);
2327
2328    if (!page())
2329        return;
2330
2331    FrameView* view = page()->mainFrame()->view();
2332    IntRect dirtyRect = view->windowToContents(rect);
2333    updateLayerRendererViewport();
2334    m_layerRenderer->invalidateRootLayerRect(dirtyRect);
2335    setRootLayerNeedsDisplay();
2336}
2337
2338class WebViewImplContentPainter : public TilePaintInterface {
2339    WTF_MAKE_NONCOPYABLE(WebViewImplContentPainter);
2340public:
2341    static PassOwnPtr<WebViewImplContentPainter*> create(WebViewImpl* webViewImpl)
2342    {
2343        return adoptPtr(new WebViewImplContentPainter(webViewImpl));
2344    }
2345
2346    virtual void paint(GraphicsContext& context, const IntRect& contentRect)
2347    {
2348        Page* page = m_webViewImpl->page();
2349        if (!page)
2350            return;
2351        FrameView* view = page->mainFrame()->view();
2352        view->paintContents(&context, contentRect);
2353    }
2354
2355private:
2356    explicit WebViewImplContentPainter(WebViewImpl* webViewImpl)
2357        : m_webViewImpl(webViewImpl)
2358    {
2359    }
2360
2361    WebViewImpl* m_webViewImpl;
2362};
2363
2364void WebViewImpl::setIsAcceleratedCompositingActive(bool active)
2365{
2366    PlatformBridge::histogramEnumeration("GPU.setIsAcceleratedCompositingActive", active * 2 + m_isAcceleratedCompositingActive, 4);
2367
2368    if (m_isAcceleratedCompositingActive == active)
2369        return;
2370
2371    if (!active) {
2372        m_isAcceleratedCompositingActive = false;
2373        // We need to finish all GL rendering before sending
2374        // didActivateAcceleratedCompositing(false) to prevent
2375        // flickering when compositing turns off.
2376        if (m_layerRenderer)
2377            m_layerRenderer->finish();
2378        m_client->didActivateAcceleratedCompositing(false);
2379    } else if (m_layerRenderer) {
2380        m_isAcceleratedCompositingActive = true;
2381        m_layerRenderer->resizeOnscreenContent(WebCore::IntSize(std::max(1, m_size.width),
2382                                                                std::max(1, m_size.height)));
2383
2384        m_client->didActivateAcceleratedCompositing(true);
2385    } else {
2386        RefPtr<GraphicsContext3D> context = m_temporaryOnscreenGraphicsContext3D.release();
2387        if (!context) {
2388            context = GraphicsContext3D::create(getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow);
2389            if (context)
2390                context->reshape(std::max(1, m_size.width), std::max(1, m_size.height));
2391        }
2392
2393
2394        m_layerRenderer = LayerRendererChromium::create(context.release(), WebViewImplContentPainter::create(this));
2395        if (m_layerRenderer) {
2396            m_client->didActivateAcceleratedCompositing(true);
2397            m_isAcceleratedCompositingActive = true;
2398            m_compositorCreationFailed = false;
2399        } else {
2400            m_isAcceleratedCompositingActive = false;
2401            m_client->didActivateAcceleratedCompositing(false);
2402            m_compositorCreationFailed = true;
2403        }
2404    }
2405    if (page())
2406        page()->mainFrame()->view()->setClipsRepaints(!m_isAcceleratedCompositingActive);
2407}
2408
2409void WebViewImpl::doComposite()
2410{
2411    ASSERT(m_layerRenderer);
2412    if (!m_layerRenderer) {
2413        setIsAcceleratedCompositingActive(false);
2414        return;
2415    }
2416
2417    ASSERT(isAcceleratedCompositingActive());
2418    if (!page())
2419        return;
2420
2421    m_layerRenderer->setCompositeOffscreen(settings()->compositeToTextureEnabled());
2422
2423    CCHeadsUpDisplay* hud = m_layerRenderer->headsUpDisplay();
2424    hud->setShowFPSCounter(settings()->showFPSCounter());
2425    hud->setShowPlatformLayerTree(settings()->showPlatformLayerTree());
2426
2427    m_layerRenderer->updateAndDrawLayers();
2428}
2429
2430void WebViewImpl::reallocateRenderer()
2431{
2432    RefPtr<GraphicsContext3D> newContext = m_temporaryOnscreenGraphicsContext3D.get();
2433    WebGraphicsContext3D* webContext = GraphicsContext3DInternal::extractWebGraphicsContext3D(newContext.get());
2434    if (!newContext || !webContext || webContext->isContextLost())
2435        newContext = GraphicsContext3D::create(
2436            getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow);
2437    // GraphicsContext3D::create might fail and return 0, in that case LayerRendererChromium::create will also return 0.
2438    RefPtr<LayerRendererChromium> layerRenderer = LayerRendererChromium::create(newContext, WebViewImplContentPainter::create(this));
2439
2440    // Reattach the root layer.  Child layers will get reattached as a side effect of updateLayersRecursive.
2441    if (layerRenderer) {
2442        m_layerRenderer->transferRootLayer(layerRenderer.get());
2443        m_layerRenderer = layerRenderer;
2444        // FIXME: In MacOS newContext->reshape method needs to be called to
2445        // allocate IOSurfaces. All calls to create a context followed by
2446        // reshape should really be extracted into one function; it is not
2447        // immediately obvious that GraphicsContext3D object will not
2448        // function properly until its reshape method is called.
2449        newContext->reshape(std::max(1, m_size.width), std::max(1, m_size.height));
2450        setRootGraphicsLayer(m_layerRenderer->rootLayer());
2451        // Forces ViewHostMsg_DidActivateAcceleratedCompositing to be sent so
2452        // that the browser process can reacquire surfaces.
2453        m_client->didActivateAcceleratedCompositing(true);
2454    } else
2455        setRootGraphicsLayer(0);
2456}
2457#endif
2458
2459void WebViewImpl::updateLayerRendererViewport()
2460{
2461    ASSERT(m_layerRenderer);
2462
2463    if (!page())
2464        return;
2465
2466    FrameView* view = page()->mainFrame()->view();
2467    IntRect contentRect = view->visibleContentRect(false);
2468    IntRect visibleRect = view->visibleContentRect(true);
2469    IntPoint scroll(view->scrollX(), view->scrollY());
2470
2471    m_layerRenderer->setViewport(visibleRect, contentRect, scroll);
2472}
2473
2474WebGraphicsContext3D* WebViewImpl::graphicsContext3D()
2475{
2476#if USE(ACCELERATED_COMPOSITING)
2477    if (m_page->settings()->acceleratedCompositingEnabled() && allowsAcceleratedCompositing()) {
2478        if (m_layerRenderer) {
2479            WebGraphicsContext3D* webContext = GraphicsContext3DInternal::extractWebGraphicsContext3D(m_layerRenderer->context());
2480            if (webContext && !webContext->isContextLost())
2481                return webContext;
2482        }
2483        if (m_temporaryOnscreenGraphicsContext3D) {
2484            WebGraphicsContext3D* webContext = GraphicsContext3DInternal::extractWebGraphicsContext3D(m_temporaryOnscreenGraphicsContext3D.get());
2485            if (webContext && !webContext->isContextLost())
2486                return webContext;
2487        }
2488        m_temporaryOnscreenGraphicsContext3D = GraphicsContext3D::create(getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow);
2489        if (m_temporaryOnscreenGraphicsContext3D)
2490            m_temporaryOnscreenGraphicsContext3D->reshape(std::max(1, m_size.width), std::max(1, m_size.height));
2491        return GraphicsContext3DInternal::extractWebGraphicsContext3D(m_temporaryOnscreenGraphicsContext3D.get());
2492    }
2493#endif
2494    return 0;
2495}
2496
2497} // namespace WebKit
2498