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