2 * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
32 #include "WebViewImpl.h"
34 #include "AXObjectCache.h"
35 #include "ActivePlatformGestureAnimation.h"
36 #include "AutofillPopupMenuClient.h"
37 #include "BackForwardListChromium.h"
38 #include "BatteryClientImpl.h"
39 #include "CSSValueKeywords.h"
42 #include "ColorSpace.h"
43 #include "CompositionUnderlineVectorBuilder.h"
44 #include "ContextMenu.h"
45 #include "ContextMenuController.h"
46 #include "ContextMenuItem.h"
48 #include "DOMUtilitiesPrivate.h"
49 #include "DeviceOrientationClientProxy.h"
51 #include "DocumentLoader.h"
52 #include "DragController.h"
54 #include "DragScrollTimer.h"
55 #include "DragSession.h"
57 #include "EventHandler.h"
58 #include "Extensions3D.h"
59 #include "FocusController.h"
60 #include "FontDescription.h"
62 #include "FrameLoader.h"
63 #include "FrameSelection.h"
64 #include "FrameTree.h"
65 #include "FrameView.h"
66 #include "GeolocationClientProxy.h"
67 #include "GeolocationController.h"
68 #include "GraphicsContext.h"
69 #include "GraphicsContext3D.h"
70 #include "GraphicsContext3DPrivate.h"
71 #include "HTMLInputElement.h"
72 #include "HTMLMediaElement.h"
73 #include "HTMLNames.h"
74 #include "HTMLTextAreaElement.h"
75 #include "HitTestResult.h"
77 #include "ImageBuffer.h"
78 #include "InspectorController.h"
79 #include "InspectorInstrumentation.h"
80 #include "KeyboardCodes.h"
81 #include "KeyboardEvent.h"
82 #include "LayerChromium.h"
83 #include "LayerPainterChromium.h"
84 #include "MIMETypeRegistry.h"
85 #include "NodeRenderStyle.h"
86 #include "NonCompositedContentHost.h"
88 #include "PageGroup.h"
89 #include "PageGroupLoadDeferrer.h"
90 #include "PagePopupClient.h"
91 #include "PageWidgetDelegate.h"
92 #include "Pasteboard.h"
93 #include "PlatformContextSkia.h"
94 #include "PlatformKeyboardEvent.h"
95 #include "PlatformMouseEvent.h"
96 #include "PlatformThemeChromiumLinux.h"
97 #include "PlatformWheelEvent.h"
98 #include "PointerLock.h"
99 #include "PointerLockController.h"
100 #include "PopupContainer.h"
101 #include "PopupMenuClient.h"
102 #include "PrerendererClientImpl.h"
103 #include "ProgressTracker.h"
104 #include "RenderLayerCompositor.h"
105 #include "RenderView.h"
106 #include "RenderWidget.h"
107 #include "ResourceHandle.h"
108 #include "SchemeRegistry.h"
109 #include "SecurityOrigin.h"
110 #include "SecurityPolicy.h"
111 #include "Settings.h"
112 #include "SharedGraphicsContext3D.h"
113 #include "SpeechInputClientImpl.h"
114 #include "SpeechRecognitionClientProxy.h"
115 #include "StyleResolver.h"
116 #include "TextFieldDecoratorImpl.h"
117 #include "TextIterator.h"
119 #include "TouchpadFlingPlatformGestureCurve.h"
120 #include "TraceEvent.h"
121 #include "UserGestureIndicator.h"
122 #include "WebAccessibilityObject.h"
123 #include "WebActiveWheelFlingParameters.h"
124 #include "WebAutofillClient.h"
125 #include "WebCompositorImpl.h"
126 #include "WebDevToolsAgentImpl.h"
127 #include "WebDevToolsAgentPrivate.h"
128 #include "WebFrameImpl.h"
129 #include "WebInputElement.h"
130 #include "WebInputEvent.h"
131 #include "WebInputEventConversion.h"
133 #include "WebMediaPlayerAction.h"
135 #include "WebPagePopupImpl.h"
136 #include "WebPlugin.h"
137 #include "WebPluginAction.h"
138 #include "WebPluginContainerImpl.h"
139 #include "WebPopupMenuImpl.h"
140 #include "WebRange.h"
141 #include "WebRuntimeFeatures.h"
142 #include "WebSettingsImpl.h"
143 #include "WebViewClient.h"
144 #include "WheelEvent.h"
145 #include "cc/CCProxy.h"
146 #include "painting/GraphicsContextBuilder.h"
147 #include "platform/WebKitPlatformSupport.h"
148 #include "platform/WebString.h"
149 #include "platform/WebVector.h"
150 #include <public/Platform.h>
151 #include <public/WebDragData.h>
152 #include <public/WebFloatPoint.h>
153 #include <public/WebGraphicsContext3D.h>
154 #include <public/WebImage.h>
155 #include <public/WebLayer.h>
156 #include <public/WebLayerTreeView.h>
157 #include <public/WebPoint.h>
158 #include <public/WebRect.h>
159 #include <wtf/CurrentTime.h>
160 #include <wtf/MainThread.h>
161 #include <wtf/RefPtr.h>
162 #include <wtf/Uint8ClampedArray.h>
164 #if ENABLE(GESTURE_EVENTS)
165 #include "PlatformGestureEvent.h"
169 #include "RenderThemeChromiumWin.h"
171 #if OS(UNIX) && !OS(DARWIN)
172 #include "RenderThemeChromiumLinux.h"
174 #include "RenderTheme.h"
177 // Get rid of WTF's pow define so we can use std::pow.
179 #include <cmath> // for std::pow
181 using namespace WebCore;
184 // The following constants control parameters for automated scaling of webpages
185 // (such as due to a double tap gesture or find in page etc.). These are
186 // experimentally determined.
187 static const int touchPointPadding = 32;
188 static const float minScaleDifference = 0.01f;
189 static const float doubleTapZoomContentDefaultMargin = 5;
190 static const float doubleTapZoomContentMinimumMargin = 2;
194 // Change the text zoom level by kTextSizeMultiplierRatio each time the user
195 // zooms text in or out (ie., change by 20%). The min and max values limit
196 // text zoom to half and 3x the original text size. These three values match
197 // those in Apple's port in WebKit/WebKit/WebView/WebView.mm
198 const double WebView::textSizeMultiplierRatio = 1.2;
199 const double WebView::minTextSizeMultiplier = 0.5;
200 const double WebView::maxTextSizeMultiplier = 3.0;
201 const float WebView::minPageScaleFactor = 0.25;
202 const float WebView::maxPageScaleFactor = 4.0;
205 // The group name identifies a namespace of pages. Page group is used on OSX
206 // for some programs that use HTML views to display things that don't seem like
207 // web pages to the user (so shouldn't have visited link coloring). We only use
209 const char* pageGroupName = "default";
211 // Used to defer all page activity in cases where the embedder wishes to run
212 // a nested event loop. Using a stack enables nesting of message loop invocations.
213 static Vector<PageGroupLoadDeferrer*>& pageGroupLoadDeferrerStack()
215 DEFINE_STATIC_LOCAL(Vector<PageGroupLoadDeferrer*>, deferrerStack, ());
216 return deferrerStack;
219 // Ensure that the WebDragOperation enum values stay in sync with the original
220 // DragOperation constants.
221 #define COMPILE_ASSERT_MATCHING_ENUM(coreName) \
222 COMPILE_ASSERT(int(coreName) == int(Web##coreName), dummy##coreName)
223 COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone);
224 COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy);
225 COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink);
226 COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric);
227 COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate);
228 COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove);
229 COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete);
230 COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery);
232 static const PopupContainerSettings autofillPopupSettings = {
233 false, // setTextOnIndexChange
234 false, // acceptOnAbandon
235 true, // loopSelectionNavigation
236 false // restrictWidthOfListBox (For security reasons show the entire entry
237 // so the user doesn't enter information he did not intend to.)
240 static bool shouldUseExternalPopupMenus = false;
242 // WebView ----------------------------------------------------------------
244 WebView* WebView::create(WebViewClient* client)
246 // Keep runtime flag for device motion turned off until it's implemented.
247 WebRuntimeFeatures::enableDeviceMotion(false);
249 // Pass the WebViewImpl's self-reference to the caller.
250 return adoptRef(new WebViewImpl(client)).leakRef();
253 void WebView::setUseExternalPopupMenus(bool useExternalPopupMenus)
255 shouldUseExternalPopupMenus = useExternalPopupMenus;
258 void WebView::updateVisitedLinkState(unsigned long long linkHash)
260 Page::visitedStateChanged(PageGroup::pageGroup(pageGroupName), linkHash);
263 void WebView::resetVisitedLinkState()
265 Page::allVisitedStateChanged(PageGroup::pageGroup(pageGroupName));
268 void WebView::willEnterModalLoop()
270 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
273 if (pageGroup->pages().isEmpty())
274 pageGroupLoadDeferrerStack().append(static_cast<PageGroupLoadDeferrer*>(0));
276 // Pick any page in the page group since we are deferring all pages.
277 pageGroupLoadDeferrerStack().append(new PageGroupLoadDeferrer(*pageGroup->pages().begin(), true));
281 void WebView::didExitModalLoop()
283 ASSERT(pageGroupLoadDeferrerStack().size());
285 delete pageGroupLoadDeferrerStack().last();
286 pageGroupLoadDeferrerStack().removeLast();
289 void WebViewImpl::initializeMainFrame(WebFrameClient* frameClient)
291 // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame
292 // and releases that reference once the corresponding Frame is destroyed.
293 RefPtr<WebFrameImpl> frame = WebFrameImpl::create(frameClient);
295 frame->initializeAsMainFrame(this);
297 // Restrict the access to the local file system
298 // (see WebView.mm WebView::_commonInitializationWithFrameName).
299 SecurityPolicy::setLocalLoadPolicy(SecurityPolicy::AllowLocalLoadsForLocalOnly);
302 void WebViewImpl::setAutofillClient(WebAutofillClient* autofillClient)
304 m_autofillClient = autofillClient;
307 void WebViewImpl::setDevToolsAgentClient(WebDevToolsAgentClient* devToolsClient)
310 m_devToolsAgent = adoptPtr(new WebDevToolsAgentImpl(this, devToolsClient));
312 m_devToolsAgent.clear();
315 void WebViewImpl::setPermissionClient(WebPermissionClient* permissionClient)
317 m_permissionClient = permissionClient;
320 void WebViewImpl::setPrerendererClient(WebPrerendererClient* prerendererClient)
322 providePrerendererClientTo(m_page.get(), new PrerendererClientImpl(prerendererClient));
325 void WebViewImpl::setSpellCheckClient(WebSpellCheckClient* spellCheckClient)
327 m_spellCheckClient = spellCheckClient;
330 void WebViewImpl::addTextFieldDecoratorClient(WebTextFieldDecoratorClient* client)
333 // We limit the number of decorators because it affects performance of text
334 // field creation. If you'd like to add more decorators, consider moving
335 // your decorator or existing decorators to WebCore.
336 const unsigned maximumNumberOfDecorators = 8;
337 if (m_textFieldDecorators.size() >= maximumNumberOfDecorators)
339 m_textFieldDecorators.append(TextFieldDecoratorImpl::create(client));
342 WebViewImpl::WebViewImpl(WebViewClient* client)
344 , m_autofillClient(0)
345 , m_permissionClient(0)
346 , m_spellCheckClient(0)
347 , m_chromeClientImpl(this)
348 , m_contextMenuClientImpl(this)
349 , m_dragClientImpl(this)
350 , m_editorClientImpl(this)
351 , m_inspectorClientImpl(this)
352 , m_shouldAutoResize(false)
353 , m_observedNewNavigation(false)
355 , m_newNavigationLoader(0)
358 , m_minimumZoomLevel(zoomFactorToZoomLevel(minTextSizeMultiplier))
359 , m_maximumZoomLevel(zoomFactorToZoomLevel(maxTextSizeMultiplier))
360 , m_pageDefinedMinimumPageScaleFactor(-1)
361 , m_pageDefinedMaximumPageScaleFactor(-1)
362 , m_minimumPageScaleFactor(minPageScaleFactor)
363 , m_maximumPageScaleFactor(maxPageScaleFactor)
364 , m_pageScaleFactorIsSet(false)
365 , m_contextMenuAllowed(false)
366 , m_doingDragAndDrop(false)
367 , m_ignoreInputEvents(false)
368 , m_suppressNextKeypressEvent(false)
369 , m_initialNavigationPolicy(WebNavigationPolicyIgnore)
370 , m_imeAcceptEvents(true)
371 , m_operationsAllowed(WebDragOperationNone)
372 , m_dragOperation(WebDragOperationNone)
373 , m_autofillPopupShowing(false)
375 , m_isTransparent(false)
376 , m_tabsToLinks(false)
377 , m_dragScrollTimer(adoptPtr(new DragScrollTimer))
378 , m_isCancelingFullScreen(false)
379 #if USE(ACCELERATED_COMPOSITING)
380 , m_rootGraphicsLayer(0)
381 , m_isAcceleratedCompositingActive(false)
382 , m_compositorCreationFailed(false)
383 , m_recreatingGraphicsContext(false)
384 , m_compositorSurfaceReady(false)
386 #if ENABLE(INPUT_SPEECH)
387 , m_speechInputClient(SpeechInputClientImpl::create(client))
389 #if ENABLE(SCRIPTED_SPEECH)
390 , m_speechRecognitionClient(SpeechRecognitionClientProxy::create(client ? client->speechRecognizer() : 0))
392 , m_deviceOrientationClientProxy(adoptPtr(new DeviceOrientationClientProxy(client ? client->deviceOrientationClient() : 0)))
393 , m_geolocationClientProxy(adoptPtr(new GeolocationClientProxy(client ? client->geolocationClient() : 0)))
394 #if ENABLE(BATTERY_STATUS)
395 , m_batteryClient(adoptPtr(new BatteryClientImpl(client ? client->batteryStatusClient() : 0)))
397 , m_emulatedTextZoomFactor(1)
398 #if ENABLE(MEDIA_STREAM)
399 , m_userMediaClientImpl(this)
403 // WebKit/win/WebView.cpp does the same thing, except they call the
404 // KJS specific wrapper around this method. We need to have threading
405 // initialized because CollatorICU requires it.
406 WTF::initializeThreading();
407 WTF::initializeMainThread();
409 Page::PageClients pageClients;
410 pageClients.chromeClient = &m_chromeClientImpl;
411 pageClients.contextMenuClient = &m_contextMenuClientImpl;
412 pageClients.editorClient = &m_editorClientImpl;
413 pageClients.dragClient = &m_dragClientImpl;
414 pageClients.inspectorClient = &m_inspectorClientImpl;
415 pageClients.backForwardClient = BackForwardListChromium::create(this);
417 m_page = adoptPtr(new Page(pageClients));
418 #if ENABLE(MEDIA_STREAM)
419 provideUserMediaTo(m_page.get(), &m_userMediaClientImpl);
421 #if ENABLE(INPUT_SPEECH)
422 provideSpeechInputTo(m_page.get(), m_speechInputClient.get());
424 #if ENABLE(SCRIPTED_SPEECH)
425 provideSpeechRecognitionTo(m_page.get(), m_speechRecognitionClient.get());
427 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
428 provideNotification(m_page.get(), notificationPresenterImpl());
431 provideDeviceOrientationTo(m_page.get(), m_deviceOrientationClientProxy.get());
432 provideGeolocationTo(m_page.get(), m_geolocationClientProxy.get());
433 m_geolocationClientProxy->setController(GeolocationController::from(m_page.get()));
435 #if ENABLE(BATTERY_STATUS)
436 provideBatteryTo(m_page.get(), m_batteryClient.get());
439 m_page->setGroupName(pageGroupName);
441 #if ENABLE(PAGE_VISIBILITY_API)
443 setVisibilityState(m_client->visibilityState(), true);
446 m_inspectorSettingsMap = adoptPtr(new SettingsMap);
449 WebViewImpl::~WebViewImpl()
454 RenderTheme* WebViewImpl::theme() const
456 return m_page ? m_page->theme() : RenderTheme::defaultTheme().get();
459 WebFrameImpl* WebViewImpl::mainFrameImpl()
461 return m_page ? WebFrameImpl::fromFrame(m_page->mainFrame()) : 0;
464 bool WebViewImpl::tabKeyCyclesThroughElements() const
467 return m_page->tabKeyCyclesThroughElements();
470 void WebViewImpl::setTabKeyCyclesThroughElements(bool value)
473 m_page->setTabKeyCyclesThroughElements(value);
476 void WebViewImpl::handleMouseLeave(Frame& mainFrame, const WebMouseEvent& event)
478 m_client->setMouseOverURL(WebURL());
479 PageWidgetEventHandler::handleMouseLeave(mainFrame, event);
482 void WebViewImpl::handleMouseDown(Frame& mainFrame, const WebMouseEvent& event)
484 // If there is a select popup open, close it as the user is clicking on
485 // the page (outside of the popup). We also save it so we can prevent a
486 // click on the select element from immediately reopening the popup.
487 RefPtr<WebCore::PopupContainer> selectPopup;
488 if (event.button == WebMouseEvent::ButtonLeft) {
489 selectPopup = m_selectPopup;
491 ASSERT(!m_selectPopup);
494 m_lastMouseDownPoint = WebPoint(event.x, event.y);
496 if (event.button == WebMouseEvent::ButtonLeft) {
497 IntPoint point(event.x, event.y);
498 point = m_page->mainFrame()->view()->windowToContents(point);
499 HitTestResult result(m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, false));
500 Node* hitNode = result.innerNonSharedNode();
502 // Take capture on a mouse down on a plugin so we can send it mouse events.
503 if (hitNode && hitNode->renderer() && hitNode->renderer()->isEmbeddedObject())
504 m_mouseCaptureNode = hitNode;
507 PageWidgetEventHandler::handleMouseDown(mainFrame, event);
509 if (m_selectPopup && m_selectPopup == selectPopup) {
510 // That click triggered a select popup which is the same as the one that
511 // was showing before the click. It means the user clicked the select
512 // while the popup was showing, and as a result we first closed then
513 // immediately reopened the select popup. It needs to be closed.
517 // Dispatch the contextmenu event regardless of if the click was swallowed.
518 // On Windows, we handle it on mouse up, not down.
520 if (event.button == WebMouseEvent::ButtonRight
521 || (event.button == WebMouseEvent::ButtonLeft
522 && event.modifiers & WebMouseEvent::ControlKey))
523 mouseContextMenu(event);
524 #elif OS(UNIX) || OS(ANDROID)
525 if (event.button == WebMouseEvent::ButtonRight)
526 mouseContextMenu(event);
530 void WebViewImpl::mouseContextMenu(const WebMouseEvent& event)
532 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
535 m_page->contextMenuController()->clearContextMenu();
537 PlatformMouseEventBuilder pme(mainFrameImpl()->frameView(), event);
539 // Find the right target frame. See issue 1186900.
540 HitTestResult result = hitTestResultForWindowPos(pme.position());
542 if (result.innerNonSharedNode())
543 targetFrame = result.innerNonSharedNode()->document()->frame();
545 targetFrame = m_page->focusController()->focusedOrMainFrame();
548 targetFrame->view()->setCursor(pointerCursor());
551 m_contextMenuAllowed = true;
552 targetFrame->eventHandler()->sendContextMenuEvent(pme);
553 m_contextMenuAllowed = false;
554 // Actually showing the context menu is handled by the ContextMenuClient
558 void WebViewImpl::handleMouseUp(Frame& mainFrame, const WebMouseEvent& event)
560 #if OS(UNIX) && !OS(DARWIN)
561 // If the event was a middle click, attempt to copy text into the focused
562 // frame. We execute this before we let the page have a go at the event
563 // because the page may change what is focused during in its event handler.
565 // This code is in the mouse up handler. There is some debate about putting
566 // this here, as opposed to the mouse down handler.
567 // xterm: pastes on up.
568 // GTK: pastes on down.
569 // Firefox: pastes on up.
570 // Midori: couldn't paste at all with 0.1.2
572 // There is something of a webcompat angle to this well, as highlighted by
573 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
574 // down then the text is pasted just before the onclick handler runs and
575 // clears the text box. So it's important this happens after the
576 // handleMouseReleaseEvent() earlier in this function
577 if (event.button == WebMouseEvent::ButtonMiddle) {
578 Frame* focused = focusedWebCoreFrame();
579 FrameView* view = m_page->mainFrame()->view();
580 IntPoint clickPoint(m_lastMouseDownPoint.x, m_lastMouseDownPoint.y);
581 IntPoint contentPoint = view->windowToContents(clickPoint);
582 HitTestResult hitTestResult = focused->eventHandler()->hitTestResultAtPoint(contentPoint, false, false, ShouldHitTestScrollbars);
583 // We don't want to send a paste when middle clicking a scroll bar or a
584 // link (which will navigate later in the code). The main scrollbars
585 // have to be handled separately.
586 if (!hitTestResult.scrollbar() && !hitTestResult.isLiveLink() && focused && !view->scrollbarAtPoint(clickPoint)) {
587 Editor* editor = focused->editor();
588 Pasteboard* pasteboard = Pasteboard::generalPasteboard();
589 bool oldSelectionMode = pasteboard->isSelectionMode();
590 pasteboard->setSelectionMode(true);
591 editor->command(AtomicString("Paste")).execute();
592 pasteboard->setSelectionMode(oldSelectionMode);
597 PageWidgetEventHandler::handleMouseUp(mainFrame, event);
600 // Dispatch the contextmenu event regardless of if the click was swallowed.
601 // On Mac/Linux, we handle it on mouse down, not up.
602 if (event.button == WebMouseEvent::ButtonRight)
603 mouseContextMenu(event);
607 void WebViewImpl::scrollBy(const WebCore::IntPoint& delta)
609 WebMouseWheelEvent syntheticWheel;
610 const float tickDivisor = WebCore::WheelEvent::tickMultiplier;
612 syntheticWheel.deltaX = delta.x();
613 syntheticWheel.deltaY = delta.y();
614 syntheticWheel.wheelTicksX = delta.x() / tickDivisor;
615 syntheticWheel.wheelTicksY = delta.y() / tickDivisor;
616 syntheticWheel.hasPreciseScrollingDeltas = true;
617 syntheticWheel.x = m_lastWheelPosition.x;
618 syntheticWheel.y = m_lastWheelPosition.y;
619 syntheticWheel.globalX = m_lastWheelGlobalPosition.x;
620 syntheticWheel.globalY = m_lastWheelGlobalPosition.y;
621 syntheticWheel.modifiers = m_flingModifier;
623 if (m_page && m_page->mainFrame() && m_page->mainFrame()->view())
624 handleMouseWheel(*m_page->mainFrame(), syntheticWheel);
627 #if ENABLE(GESTURE_EVENTS)
628 bool WebViewImpl::handleGestureEvent(const WebGestureEvent& event)
630 switch (event.type) {
631 case WebInputEvent::GestureFlingStart: {
632 m_lastWheelPosition = WebPoint(event.x, event.y);
633 m_lastWheelGlobalPosition = WebPoint(event.globalX, event.globalY);
634 m_flingModifier = event.modifiers;
635 // FIXME: Make the curve parametrizable from the browser.
636 m_gestureAnimation = ActivePlatformGestureAnimation::create(TouchpadFlingPlatformGestureCurve::create(FloatPoint(event.deltaX, event.deltaY)), this);
640 case WebInputEvent::GestureFlingCancel:
641 if (m_gestureAnimation) {
642 m_gestureAnimation.clear();
646 case WebInputEvent::GestureTap: {
647 PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
648 RefPtr<WebCore::PopupContainer> selectPopup;
649 selectPopup = m_selectPopup;
651 ASSERT(!m_selectPopup);
652 bool gestureHandled = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
653 if (m_selectPopup && m_selectPopup == selectPopup) {
654 // That tap triggered a select popup which is the same as the one that
655 // was showing before the tap. It means the user tapped the select
656 // while the popup was showing, and as a result we first closed then
657 // immediately reopened the select popup. It needs to be closed.
660 return gestureHandled;
662 case WebInputEvent::GestureLongPress: {
663 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
666 m_page->contextMenuController()->clearContextMenu();
667 m_contextMenuAllowed = true;
668 PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
669 bool handled = mainFrameImpl()->frame()->eventHandler()->sendContextMenuEventForGesture(platformEvent);
670 m_contextMenuAllowed = false;
673 case WebInputEvent::GestureScrollBegin:
674 case WebInputEvent::GestureScrollEnd:
675 case WebInputEvent::GestureScrollUpdate:
676 case WebInputEvent::GestureTapDown:
677 case WebInputEvent::GestureDoubleTap:
678 case WebInputEvent::GesturePinchBegin:
679 case WebInputEvent::GesturePinchEnd:
680 case WebInputEvent::GesturePinchUpdate: {
681 PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
682 return mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
685 ASSERT_NOT_REACHED();
690 void WebViewImpl::transferActiveWheelFlingAnimation(const WebActiveWheelFlingParameters& parameters)
692 TRACE_EVENT0("webkit", "WebViewImpl::transferActiveWheelFlingAnimation");
693 ASSERT(!m_gestureAnimation);
694 m_lastWheelPosition = parameters.point;
695 m_lastWheelGlobalPosition = parameters.globalPoint;
696 m_flingModifier = parameters.modifiers;
697 OwnPtr<PlatformGestureCurve> curve = TouchpadFlingPlatformGestureCurve::create(parameters.delta, IntPoint(parameters.cumulativeScroll));
698 m_gestureAnimation = ActivePlatformGestureAnimation::create(curve.release(), this, parameters.startTime);
702 void WebViewImpl::startPageScaleAnimation(const IntPoint& scroll, bool useAnchor, float newScale, double durationSec)
704 if (!m_layerTreeView.isNull())
705 m_layerTreeView.startPageScaleAnimation(scroll, useAnchor, newScale, durationSec);
709 bool WebViewImpl::handleKeyEvent(const WebKeyboardEvent& event)
711 ASSERT((event.type == WebInputEvent::RawKeyDown)
712 || (event.type == WebInputEvent::KeyDown)
713 || (event.type == WebInputEvent::KeyUp));
715 // Halt an in-progress fling on a key event.
716 if (m_gestureAnimation)
717 m_gestureAnimation.clear();
719 // Please refer to the comments explaining the m_suppressNextKeypressEvent
721 // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
722 // Webkit. A keyDown event is typically associated with a keyPress(char)
723 // event and a keyUp event. We reset this flag here as this is a new keyDown
725 m_suppressNextKeypressEvent = false;
727 // If there is a select popup, it should be the one processing the event,
730 return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
731 #if ENABLE(PAGE_POPUP)
733 m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
734 // We need to ignore the next Char event after this otherwise pressing
735 // enter when selecting an item in the popup will go to the page.
736 if (WebInputEvent::RawKeyDown == event.type)
737 m_suppressNextKeypressEvent = true;
742 // Give Autocomplete a chance to consume the key events it is interested in.
743 if (autocompleteHandleKeyEvent(event))
746 RefPtr<Frame> frame = focusedWebCoreFrame();
750 EventHandler* handler = frame->eventHandler();
752 return keyEventDefault(event);
755 const WebInputEvent::Type contextMenuTriggeringEventType =
757 WebInputEvent::KeyUp;
759 WebInputEvent::RawKeyDown;
762 bool isUnmodifiedMenuKey = !(event.modifiers & WebInputEvent::InputModifiers) && event.windowsKeyCode == VKEY_APPS;
763 bool isShiftF10 = event.modifiers == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10;
764 if ((isUnmodifiedMenuKey || isShiftF10) && event.type == contextMenuTriggeringEventType) {
765 sendContextMenuEvent(event);
768 #endif // !OS(DARWIN)
770 PlatformKeyboardEventBuilder evt(event);
772 if (handler->keyEvent(evt)) {
773 if (WebInputEvent::RawKeyDown == event.type) {
774 // Suppress the next keypress event unless the focused node is a plug-in node.
775 // (Flash needs these keypress events to handle non-US keyboards.)
776 Node* node = focusedWebCoreNode();
777 if (!node || !node->renderer() || !node->renderer()->isEmbeddedObject())
778 m_suppressNextKeypressEvent = true;
783 return keyEventDefault(event);
786 bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event)
788 if (!m_autofillPopupShowing
789 // Home and End should be left to the text field to process.
790 || event.windowsKeyCode == VKEY_HOME
791 || event.windowsKeyCode == VKEY_END)
794 // Pressing delete triggers the removal of the selected suggestion from the DB.
795 if (event.windowsKeyCode == VKEY_DELETE
796 && m_autofillPopup->selectedIndex() != -1) {
797 Node* node = focusedWebCoreNode();
798 if (!node || (node->nodeType() != Node::ELEMENT_NODE)) {
799 ASSERT_NOT_REACHED();
802 Element* element = static_cast<Element*>(node);
803 if (!element->hasLocalName(HTMLNames::inputTag)) {
804 ASSERT_NOT_REACHED();
808 int selectedIndex = m_autofillPopup->selectedIndex();
810 if (!m_autofillPopupClient->canRemoveSuggestionAtIndex(selectedIndex))
813 WebString name = WebInputElement(static_cast<HTMLInputElement*>(element)).nameForAutofill();
814 WebString value = m_autofillPopupClient->itemText(selectedIndex);
815 m_autofillClient->removeAutocompleteSuggestion(name, value);
816 // Update the entries in the currently showing popup to reflect the
818 m_autofillPopupClient->removeSuggestionAtIndex(selectedIndex);
819 refreshAutofillPopup();
823 if (!m_autofillPopup->isInterestedInEventForKey(event.windowsKeyCode))
826 if (m_autofillPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) {
827 // We need to ignore the next Char event after this otherwise pressing
828 // enter when selecting an item in the menu will go to the page.
829 if (WebInputEvent::RawKeyDown == event.type)
830 m_suppressNextKeypressEvent = true;
837 bool WebViewImpl::handleCharEvent(const WebKeyboardEvent& event)
839 ASSERT(event.type == WebInputEvent::Char);
841 // Please refer to the comments explaining the m_suppressNextKeypressEvent
842 // member. The m_suppressNextKeypressEvent is set if the KeyDown is
843 // handled by Webkit. A keyDown event is typically associated with a
844 // keyPress(char) event and a keyUp event. We reset this flag here as it
845 // only applies to the current keyPress event.
846 bool suppress = m_suppressNextKeypressEvent;
847 m_suppressNextKeypressEvent = false;
849 // If there is a select popup, it should be the one processing the event,
852 return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
853 #if ENABLE(PAGE_POPUP)
855 return m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
858 Frame* frame = focusedWebCoreFrame();
862 EventHandler* handler = frame->eventHandler();
864 return suppress || keyEventDefault(event);
866 PlatformKeyboardEventBuilder evt(event);
867 if (!evt.isCharacterKey())
870 // Accesskeys are triggered by char events and can't be suppressed.
871 if (handler->handleAccessKey(evt))
874 // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
875 // the eventHandler::keyEvent. We mimic this behavior on all platforms since
876 // for now we are converting other platform's key events to windows key
878 if (evt.isSystemKey())
881 if (!suppress && !handler->keyEvent(evt))
882 return keyEventDefault(event);
887 #if ENABLE(GESTURE_EVENTS)
888 WebRect WebViewImpl::computeBlockBounds(const WebRect& rect, AutoZoomType zoomType)
890 if (!mainFrameImpl())
893 // Use the rect-based hit test to find the node.
894 IntPoint point = mainFrameImpl()->frameView()->windowToContents(IntPoint(rect.x, rect.y));
895 HitTestResult result = mainFrameImpl()->frame()->eventHandler()->hitTestResultAtPoint(point,
896 false, zoomType == FindInPage, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly,
897 IntSize(rect.width, rect.height));
899 Node* node = result.innerNonSharedNode();
903 // Find the block type node based on the hit node.
904 while (node && (!node->renderer() || node->renderer()->isInline()))
905 node = node->parentNode();
907 // Return the bounding box in the window coordinate system.
909 IntRect rect = node->Node::getPixelSnappedRect();
910 Frame* frame = node->document()->frame();
911 return frame->view()->contentsToWindow(rect);
916 WebRect WebViewImpl::widenRectWithinPageBounds(const WebRect& source, int targetMargin, int minimumMargin)
920 maxSize = mainFrame()->contentsSize();
921 IntSize scrollOffset;
923 scrollOffset = mainFrame()->scrollOffset();
924 int leftMargin = targetMargin;
925 int rightMargin = targetMargin;
927 const int absoluteSourceX = source.x + scrollOffset.width();
928 if (leftMargin > absoluteSourceX) {
929 leftMargin = absoluteSourceX;
930 rightMargin = max(leftMargin, minimumMargin);
933 const int maximumRightMargin = maxSize.width - (source.width + absoluteSourceX);
934 if (rightMargin > maximumRightMargin) {
935 rightMargin = maximumRightMargin;
936 leftMargin = min(leftMargin, max(rightMargin, minimumMargin));
939 const int newWidth = source.width + leftMargin + rightMargin;
940 const int newX = source.x - leftMargin;
942 ASSERT(newWidth >= 0);
943 ASSERT(scrollOffset.width() + newX + newWidth <= maxSize.width);
945 return WebRect(newX, source.y, newWidth, source.height);
948 void WebViewImpl::computeScaleAndScrollForHitRect(const WebRect& hitRect, AutoZoomType zoomType, float& scale, WebPoint& scroll)
950 scale = pageScaleFactor();
951 scroll.x = scroll.y = 0;
952 WebRect targetRect = hitRect;
953 if (targetRect.isEmpty())
954 targetRect.width = targetRect.height = touchPointPadding;
956 WebRect rect = computeBlockBounds(targetRect, zoomType);
958 const float overviewScale = m_minimumPageScaleFactor;
959 bool scaleUnchanged = true;
960 if (!rect.isEmpty()) {
961 // Pages should be as legible as on desktop when at dpi scale, so no
962 // need to zoom in further when automatically determining zoom level
963 // (after double tap, find in page, etc), though the user should still
964 // be allowed to manually pinch zoom in further if they desire.
965 const float maxScale = deviceScaleFactor();
967 const float defaultMargin = doubleTapZoomContentDefaultMargin * deviceScaleFactor();
968 const float minimumMargin = doubleTapZoomContentMinimumMargin * deviceScaleFactor();
969 // We want the margins to have the same physical size, which means we
970 // need to express them in post-scale size. To do that we'd need to know
971 // the scale we're scaling to, but that depends on the margins. Instead
972 // we express them as a fraction of the target rectangle: this will be
973 // correct if we end up fully zooming to it, and won't matter if we
975 rect = widenRectWithinPageBounds(rect,
976 static_cast<int>(defaultMargin * rect.width / m_size.width),
977 static_cast<int>(minimumMargin * rect.width / m_size.width));
979 // Fit block to screen, respecting limits.
980 scale *= static_cast<float>(m_size.width) / rect.width;
981 scale = min(scale, maxScale);
982 scale = clampPageScaleFactorToLimits(scale);
984 scaleUnchanged = fabs(pageScaleFactor() - scale) < minScaleDifference;
987 if (zoomType == DoubleTap) {
988 if (rect.isEmpty() || scaleUnchanged) {
989 // Zoom out to overview mode.
991 scale = overviewScale;
994 } else if (rect.isEmpty()) {
995 // Keep current scale (no need to scroll as x,y will normally already
996 // be visible). FIXME: Revisit this if it isn't always true.
1000 // FIXME: If this is being called for auto zoom during find in page,
1001 // then if the user manually zooms in it'd be nice to preserve the relative
1002 // increase in zoom they caused (if they zoom out then it's ok to zoom
1003 // them back in again). This isn't compatible with our current double-tap
1004 // zoom strategy (fitting the containing block to the screen) though.
1006 float screenHeight = m_size.height / scale * pageScaleFactor();
1007 float screenWidth = m_size.width / scale * pageScaleFactor();
1009 // Scroll to vertically align the block.
1010 if (rect.height < screenHeight) {
1011 // Vertically center short blocks.
1012 rect.y -= 0.5 * (screenHeight - rect.height);
1014 // Ensure position we're zooming to (+ padding) isn't off the bottom of
1016 rect.y = max<float>(rect.y, hitRect.y + touchPointPadding - screenHeight);
1017 } // Otherwise top align the block.
1019 // Do the same thing for horizontal alignment.
1020 if (rect.width < screenWidth)
1021 rect.x -= 0.5 * (screenWidth - rect.width);
1023 rect.x = max<float>(rect.x, hitRect.x + touchPointPadding - screenWidth);
1030 void WebViewImpl::numberOfWheelEventHandlersChanged(unsigned numberOfWheelHandlers)
1033 m_client->numberOfWheelEventHandlersChanged(numberOfWheelHandlers);
1036 void WebViewImpl::numberOfTouchEventHandlersChanged(unsigned numberOfTouchHandlers)
1039 m_client->numberOfTouchEventHandlersChanged(numberOfTouchHandlers);
1043 // Mac has no way to open a context menu based on a keyboard event.
1044 bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event)
1046 // The contextMenuController() holds onto the last context menu that was
1047 // popped up on the page until a new one is created. We need to clear
1048 // this menu before propagating the event through the DOM so that we can
1049 // detect if we create a new menu for this event, since we won't create
1050 // a new menu if the DOM swallows the event and the defaultEventHandler does
1052 page()->contextMenuController()->clearContextMenu();
1054 m_contextMenuAllowed = true;
1055 Frame* focusedFrame = page()->focusController()->focusedOrMainFrame();
1056 bool handled = focusedFrame->eventHandler()->sendContextMenuEventForKey();
1057 m_contextMenuAllowed = false;
1062 bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event)
1064 Frame* frame = focusedWebCoreFrame();
1068 switch (event.type) {
1069 case WebInputEvent::Char:
1070 if (event.windowsKeyCode == VKEY_SPACE) {
1071 int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT);
1072 return scrollViewWithKeyboard(keyCode, event.modifiers);
1075 case WebInputEvent::RawKeyDown:
1076 if (event.modifiers == WebInputEvent::ControlKey) {
1077 switch (event.windowsKeyCode) {
1080 focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll"));
1084 focusedFrame()->executeCommand(WebString::fromUTF8("Copy"));
1087 // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
1088 // key combinations which affect scrolling. Safari is buggy in the
1089 // sense that it scrolls the page for all Ctrl+scrolling key
1090 // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
1098 if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey))
1099 return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers);
1107 bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers)
1109 ScrollDirection scrollDirection;
1110 ScrollGranularity scrollGranularity;
1112 // Control-Up/Down should be PageUp/Down on Mac.
1113 if (modifiers & WebMouseEvent::ControlKey) {
1114 if (keyCode == VKEY_UP)
1115 keyCode = VKEY_PRIOR;
1116 else if (keyCode == VKEY_DOWN)
1117 keyCode = VKEY_NEXT;
1120 if (!mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity))
1122 return propagateScroll(scrollDirection, scrollGranularity);
1125 bool WebViewImpl::mapKeyCodeForScroll(int keyCode,
1126 WebCore::ScrollDirection* scrollDirection,
1127 WebCore::ScrollGranularity* scrollGranularity)
1131 *scrollDirection = ScrollLeft;
1132 *scrollGranularity = ScrollByLine;
1135 *scrollDirection = ScrollRight;
1136 *scrollGranularity = ScrollByLine;
1139 *scrollDirection = ScrollUp;
1140 *scrollGranularity = ScrollByLine;
1143 *scrollDirection = ScrollDown;
1144 *scrollGranularity = ScrollByLine;
1147 *scrollDirection = ScrollUp;
1148 *scrollGranularity = ScrollByDocument;
1151 *scrollDirection = ScrollDown;
1152 *scrollGranularity = ScrollByDocument;
1154 case VKEY_PRIOR: // page up
1155 *scrollDirection = ScrollUp;
1156 *scrollGranularity = ScrollByPage;
1158 case VKEY_NEXT: // page down
1159 *scrollDirection = ScrollDown;
1160 *scrollGranularity = ScrollByPage;
1169 void WebViewImpl::hideSelectPopup()
1172 m_selectPopup->hidePopup();
1175 bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection,
1176 ScrollGranularity scrollGranularity)
1178 Frame* frame = focusedWebCoreFrame();
1182 bool scrollHandled = frame->eventHandler()->scrollOverflow(scrollDirection, scrollGranularity);
1183 Frame* currentFrame = frame;
1184 while (!scrollHandled && currentFrame) {
1185 scrollHandled = currentFrame->view()->scroll(scrollDirection, scrollGranularity);
1186 currentFrame = currentFrame->tree()->parent();
1188 return scrollHandled;
1191 void WebViewImpl::popupOpened(WebCore::PopupContainer* popupContainer)
1193 if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
1194 ASSERT(!m_selectPopup);
1195 m_selectPopup = popupContainer;
1199 void WebViewImpl::popupClosed(WebCore::PopupContainer* popupContainer)
1201 if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
1202 ASSERT(m_selectPopup);
1207 #if ENABLE(PAGE_POPUP)
1208 PagePopup* WebViewImpl::openPagePopup(PagePopupClient* client, const IntRect& originBoundsInRootView)
1211 if (hasOpenedPopup())
1213 ASSERT(!m_pagePopup);
1215 WebWidget* popupWidget = m_client->createPopupMenu(WebPopupTypePage);
1216 ASSERT(popupWidget);
1217 m_pagePopup = static_cast<WebPagePopupImpl*>(popupWidget);
1218 if (!m_pagePopup->init(this, client, originBoundsInRootView)) {
1219 m_pagePopup->closePopup();
1223 if (Frame* frame = focusedWebCoreFrame())
1224 frame->selection()->setCaretVisible(false);
1225 return m_pagePopup.get();
1228 void WebViewImpl::closePagePopup(PagePopup* popup)
1231 WebPagePopupImpl* popupImpl = static_cast<WebPagePopupImpl*>(popup);
1232 ASSERT(m_pagePopup.get() == popupImpl);
1233 if (m_pagePopup.get() != popupImpl)
1235 m_pagePopup->closePopup();
1238 if (Frame* frame = focusedWebCoreFrame())
1239 frame->selection()->pageActivationChanged();
1243 void WebViewImpl::hideAutofillPopup()
1245 if (m_autofillPopupShowing) {
1246 m_autofillPopup->hidePopup();
1247 m_autofillPopupShowing = false;
1251 Frame* WebViewImpl::focusedWebCoreFrame() const
1253 return m_page ? m_page->focusController()->focusedOrMainFrame() : 0;
1256 WebViewImpl* WebViewImpl::fromPage(Page* page)
1261 ChromeClientImpl* chromeClient = static_cast<ChromeClientImpl*>(page->chrome()->client());
1262 return static_cast<WebViewImpl*>(chromeClient->webView());
1265 // WebWidget ------------------------------------------------------------------
1267 void WebViewImpl::close()
1269 RefPtr<WebFrameImpl> mainFrameImpl;
1272 // Initiate shutdown for the entire frameset. This will cause a lot of
1273 // notifications to be sent.
1274 if (m_page->mainFrame()) {
1275 mainFrameImpl = WebFrameImpl::fromFrame(m_page->mainFrame());
1276 m_page->mainFrame()->loader()->frameDetached();
1281 // Should happen after m_page.clear().
1282 if (m_devToolsAgent)
1283 m_devToolsAgent.clear();
1285 // Reset the delegate to prevent notifications being sent as we're being
1289 deref(); // Balances ref() acquired in WebView::create
1292 void WebViewImpl::willStartLiveResize()
1294 if (mainFrameImpl() && mainFrameImpl()->frameView())
1295 mainFrameImpl()->frameView()->willStartLiveResize();
1297 Frame* frame = mainFrameImpl()->frame();
1298 WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
1299 if (pluginContainer)
1300 pluginContainer->willStartLiveResize();
1303 void WebViewImpl::resize(const WebSize& newSize)
1305 if (m_shouldAutoResize || m_size == newSize)
1309 #if ENABLE(VIEWPORT)
1310 if (settings()->viewportEnabled()) {
1311 ViewportArguments viewportArguments = mainFrameImpl()->frame()->document()->viewportArguments();
1312 m_page->chrome()->client()->dispatchViewportPropertiesDidChange(viewportArguments);
1316 WebDevToolsAgentPrivate* agentPrivate = devToolsAgentPrivate();
1317 if (agentPrivate && agentPrivate->metricsOverridden())
1318 agentPrivate->webViewResized();
1320 WebFrameImpl* webFrame = mainFrameImpl();
1321 if (webFrame->frameView())
1322 webFrame->frameView()->resize(newSize.width, newSize.height);
1325 sendResizeEventAndRepaint();
1328 void WebViewImpl::willEndLiveResize()
1330 if (mainFrameImpl() && mainFrameImpl()->frameView())
1331 mainFrameImpl()->frameView()->willEndLiveResize();
1333 Frame* frame = mainFrameImpl()->frame();
1334 WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
1335 if (pluginContainer)
1336 pluginContainer->willEndLiveResize();
1339 void WebViewImpl::willEnterFullScreen()
1341 #if ENABLE(FULLSCREEN_API)
1342 if (!m_provisionalFullScreenElement)
1345 // Ensure that this element's document is still attached.
1346 Document* doc = m_provisionalFullScreenElement->document();
1348 doc->webkitWillEnterFullScreenForElement(m_provisionalFullScreenElement.get());
1349 m_fullScreenFrame = doc->frame();
1351 m_provisionalFullScreenElement.clear();
1355 void WebViewImpl::didEnterFullScreen()
1357 #if ENABLE(FULLSCREEN_API)
1358 if (!m_fullScreenFrame)
1361 if (Document* doc = m_fullScreenFrame->document()) {
1362 if (doc->webkitIsFullScreen())
1363 doc->webkitDidEnterFullScreenForElement(0);
1368 void WebViewImpl::willExitFullScreen()
1370 #if ENABLE(FULLSCREEN_API)
1371 if (!m_fullScreenFrame)
1374 if (Document* doc = m_fullScreenFrame->document()) {
1375 if (doc->webkitIsFullScreen()) {
1376 // When the client exits from full screen we have to call webkitCancelFullScreen to
1377 // notify the document. While doing that, suppress notifications back to the client.
1378 m_isCancelingFullScreen = true;
1379 doc->webkitCancelFullScreen();
1380 m_isCancelingFullScreen = false;
1381 doc->webkitWillExitFullScreenForElement(0);
1387 void WebViewImpl::didExitFullScreen()
1389 #if ENABLE(FULLSCREEN_API)
1390 if (!m_fullScreenFrame)
1393 if (Document* doc = m_fullScreenFrame->document()) {
1394 if (doc->webkitIsFullScreen())
1395 doc->webkitDidExitFullScreenForElement(0);
1398 m_fullScreenFrame.clear();
1402 void WebViewImpl::instrumentBeginFrame()
1404 InspectorInstrumentation::didBeginFrame(m_page.get());
1407 void WebViewImpl::instrumentCancelFrame()
1409 InspectorInstrumentation::didCancelFrame(m_page.get());
1412 #if ENABLE(BATTERY_STATUS)
1413 void WebViewImpl::updateBatteryStatus(const WebBatteryStatus& status)
1415 m_batteryClient->updateBatteryStatus(status);
1419 void WebViewImpl::setCompositorSurfaceReady()
1421 m_compositorSurfaceReady = true;
1422 if (!m_layerTreeView.isNull())
1423 m_layerTreeView.setSurfaceReady();
1426 void WebViewImpl::animate(double)
1428 #if ENABLE(REQUEST_ANIMATION_FRAME)
1429 double monotonicFrameBeginTime = monotonicallyIncreasingTime();
1431 #if USE(ACCELERATED_COMPOSITING)
1432 // In composited mode, we always go through the compositor so it can apply
1433 // appropriate flow-control mechanisms.
1434 if (isAcceleratedCompositingActive())
1435 m_layerTreeView.updateAnimations(monotonicFrameBeginTime);
1438 updateAnimations(monotonicFrameBeginTime);
1442 void WebViewImpl::willBeginFrame()
1444 instrumentBeginFrame();
1445 m_client->willBeginCompositorFrame();
1448 void WebViewImpl::updateAnimations(double monotonicFrameBeginTime)
1450 #if ENABLE(REQUEST_ANIMATION_FRAME)
1451 TRACE_EVENT("WebViewImpl::updateAnimations", this, 0);
1453 WebFrameImpl* webframe = mainFrameImpl();
1456 FrameView* view = webframe->frameView();
1460 // Create synthetic wheel events as necessary for fling.
1461 if (m_gestureAnimation) {
1462 if (m_gestureAnimation->animate(monotonicFrameBeginTime))
1463 scheduleAnimation();
1465 m_gestureAnimation.clear();
1468 PageWidgetDelegate::animate(m_page.get(), monotonicFrameBeginTime);
1472 void WebViewImpl::layout()
1474 TRACE_EVENT("WebViewImpl::layout", this, 0);
1475 PageWidgetDelegate::layout(m_page.get());
1478 #if USE(ACCELERATED_COMPOSITING)
1479 void WebViewImpl::doPixelReadbackToCanvas(WebCanvas* canvas, const IntRect& rect)
1481 ASSERT(!m_layerTreeView.isNull());
1483 PlatformContextSkia context(canvas);
1485 // PlatformGraphicsContext is actually a pointer to PlatformContextSkia
1486 GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context));
1487 int bitmapHeight = canvas->getDevice()->accessBitmap(false).height();
1489 // Compute rect to sample from inverted GPU buffer.
1490 IntRect invertRect(rect.x(), bitmapHeight - rect.maxY(), rect.width(), rect.height());
1492 OwnPtr<ImageBuffer> imageBuffer(ImageBuffer::create(rect.size()));
1493 RefPtr<Uint8ClampedArray> pixelArray(Uint8ClampedArray::createUninitialized(rect.width() * rect.height() * 4));
1494 if (imageBuffer && pixelArray) {
1495 m_layerTreeView.compositeAndReadback(pixelArray->data(), invertRect);
1496 imageBuffer->putByteArray(Premultiplied, pixelArray.get(), rect.size(), IntRect(IntPoint(), rect.size()), IntPoint());
1498 gc.translate(IntSize(0, bitmapHeight));
1499 gc.scale(FloatSize(1.0f, -1.0f));
1500 // Use invertRect in next line, so that transform above inverts it back to
1501 // desired destination rect.
1502 gc.drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, invertRect.location());
1508 void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect)
1510 if (isAcceleratedCompositingActive()) {
1511 #if USE(ACCELERATED_COMPOSITING)
1512 // If a canvas was passed in, we use it to grab a copy of the
1513 // freshly-rendered pixels.
1515 // Clip rect to the confines of the rootLayerTexture.
1516 IntRect resizeRect(rect);
1517 resizeRect.intersect(IntRect(IntPoint(0, 0), m_layerTreeView.viewportSize()));
1518 doPixelReadbackToCanvas(canvas, resizeRect);
1522 double paintStart = currentTime();
1523 PageWidgetDelegate::paint(m_page.get(), pageOverlays(), canvas, rect);
1524 double paintEnd = currentTime();
1525 double pixelsPerSec = (rect.width * rect.height) / (paintEnd - paintStart);
1526 WebKit::Platform::current()->histogramCustomCounts("Renderer4.SoftwarePaintDurationMS", (paintEnd - paintStart) * 1000, 0, 120, 30);
1527 WebKit::Platform::current()->histogramCustomCounts("Renderer4.SoftwarePaintMegapixPerSecond", pixelsPerSec / 1000000, 10, 210, 30);
1531 void WebViewImpl::themeChanged()
1535 FrameView* view = page()->mainFrame()->view();
1537 WebRect damagedRect(0, 0, m_size.width, m_size.height);
1538 view->invalidateRect(damagedRect);
1541 void WebViewImpl::composite(bool)
1543 #if USE(ACCELERATED_COMPOSITING)
1544 if (CCProxy::hasImplThread())
1545 m_layerTreeView.setNeedsRedraw();
1547 ASSERT(isAcceleratedCompositingActive());
1552 m_pageOverlays->update();
1554 m_layerTreeView.composite();
1559 void WebViewImpl::setNeedsRedraw()
1561 #if USE(ACCELERATED_COMPOSITING)
1562 if (!m_layerTreeView.isNull() && isAcceleratedCompositingActive())
1563 m_layerTreeView.setNeedsRedraw();
1567 bool WebViewImpl::isInputThrottled() const
1569 #if USE(ACCELERATED_COMPOSITING)
1570 if (!m_layerTreeView.isNull() && isAcceleratedCompositingActive())
1571 return m_layerTreeView.commitRequested();
1576 void WebViewImpl::loseCompositorContext(int numTimes)
1578 #if USE(ACCELERATED_COMPOSITING)
1579 if (!m_layerTreeView.isNull())
1580 m_layerTreeView.loseCompositorContext(numTimes);
1584 void WebViewImpl::enterFullScreenForElement(WebCore::Element* element)
1586 // We are already transitioning to fullscreen for a different element.
1587 if (m_provisionalFullScreenElement) {
1588 m_provisionalFullScreenElement = element;
1592 // We are already in fullscreen mode.
1593 if (m_fullScreenFrame) {
1594 m_provisionalFullScreenElement = element;
1595 willEnterFullScreen();
1596 didEnterFullScreen();
1600 #if USE(NATIVE_FULLSCREEN_VIDEO)
1601 if (element && element->isMediaElement()) {
1602 HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(element);
1603 if (mediaElement->player() && mediaElement->player()->canEnterFullscreen()) {
1604 mediaElement->player()->enterFullscreen();
1605 m_provisionalFullScreenElement = element;
1611 // We need to transition to fullscreen mode.
1612 if (m_client && m_client->enterFullScreen())
1613 m_provisionalFullScreenElement = element;
1616 void WebViewImpl::exitFullScreenForElement(WebCore::Element* element)
1618 // The client is exiting full screen, so don't send a notification.
1619 if (m_isCancelingFullScreen)
1621 #if USE(NATIVE_FULLSCREEN_VIDEO)
1622 if (element && element->isMediaElement()) {
1623 HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(element);
1624 if (mediaElement->player())
1625 mediaElement->player()->exitFullscreen();
1630 m_client->exitFullScreen();
1633 bool WebViewImpl::hasHorizontalScrollbar()
1635 return mainFrameImpl()->frameView()->horizontalScrollbar();
1638 bool WebViewImpl::hasVerticalScrollbar()
1640 return mainFrameImpl()->frameView()->verticalScrollbar();
1643 const WebInputEvent* WebViewImpl::m_currentInputEvent = 0;
1645 bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
1647 UserGestureIndicator gestureIndicator(WebInputEvent::isUserGestureEventType(inputEvent.type) ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);
1649 // If we've started a drag and drop operation, ignore input events until
1651 if (m_doingDragAndDrop)
1654 if (m_ignoreInputEvents)
1657 m_currentInputEvent = &inputEvent;
1659 #if ENABLE(POINTER_LOCK)
1660 if (isPointerLocked() && WebInputEvent::isMouseEventType(inputEvent.type)) {
1661 pointerLockMouseEvent(inputEvent);
1666 if (m_mouseCaptureNode && WebInputEvent::isMouseEventType(inputEvent.type)) {
1667 // Save m_mouseCaptureNode since mouseCaptureLost() will clear it.
1668 RefPtr<Node> node = m_mouseCaptureNode;
1670 // Not all platforms call mouseCaptureLost() directly.
1671 if (inputEvent.type == WebInputEvent::MouseUp)
1674 AtomicString eventType;
1675 switch (inputEvent.type) {
1676 case WebInputEvent::MouseMove:
1677 eventType = eventNames().mousemoveEvent;
1679 case WebInputEvent::MouseLeave:
1680 eventType = eventNames().mouseoutEvent;
1682 case WebInputEvent::MouseDown:
1683 eventType = eventNames().mousedownEvent;
1685 case WebInputEvent::MouseUp:
1686 eventType = eventNames().mouseupEvent;
1689 ASSERT_NOT_REACHED();
1692 node->dispatchMouseEvent(
1693 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), *static_cast<const WebMouseEvent*>(&inputEvent)),
1694 eventType, static_cast<const WebMouseEvent*>(&inputEvent)->clickCount);
1695 m_currentInputEvent = 0;
1699 bool handled = PageWidgetDelegate::handleInputEvent(m_page.get(), *this, inputEvent);
1700 m_currentInputEvent = 0;
1704 void WebViewImpl::mouseCaptureLost()
1706 m_mouseCaptureNode = 0;
1709 void WebViewImpl::setFocus(bool enable)
1711 m_page->focusController()->setFocused(enable);
1713 m_page->focusController()->setActive(true);
1714 RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
1716 Node* focusedNode = focusedFrame->document()->focusedNode();
1717 if (focusedNode && focusedNode->isElementNode()
1718 && focusedFrame->selection()->selection().isNone()) {
1719 // If the selection was cleared while the WebView was not
1720 // focused, then the focus element shows with a focus ring but
1721 // no caret and does respond to keyboard inputs.
1722 Element* element = static_cast<Element*>(focusedNode);
1723 if (element->isTextFormControl())
1724 element->updateFocusAppearance(true);
1725 else if (focusedNode->isContentEditable()) {
1726 // updateFocusAppearance() selects all the text of
1727 // contentseditable DIVs. So we set the selection explicitly
1728 // instead. Note that this has the side effect of moving the
1729 // caret back to the beginning of the text.
1730 Position position(focusedNode, 0,
1731 Position::PositionIsOffsetInAnchor);
1732 focusedFrame->selection()->setSelection(
1733 VisibleSelection(position, SEL_DEFAULT_AFFINITY));
1737 m_imeAcceptEvents = true;
1741 // Clear focus on the currently focused frame if any.
1745 Frame* frame = m_page->mainFrame();
1749 RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
1751 // Finish an ongoing composition to delete the composition node.
1752 Editor* editor = focusedFrame->editor();
1753 if (editor && editor->hasComposition())
1754 editor->confirmComposition();
1755 m_imeAcceptEvents = false;
1760 bool WebViewImpl::setComposition(
1761 const WebString& text,
1762 const WebVector<WebCompositionUnderline>& underlines,
1766 Frame* focused = focusedWebCoreFrame();
1767 if (!focused || !m_imeAcceptEvents)
1769 Editor* editor = focused->editor();
1773 // The input focus has been moved to another WebWidget object.
1774 // We should use this |editor| object only to complete the ongoing
1776 if (!editor->canEdit() && !editor->hasComposition())
1779 // We should verify the parent node of this IME composition node are
1780 // editable because JavaScript may delete a parent node of the composition
1781 // node. In this case, WebKit crashes while deleting texts from the parent
1782 // node, which doesn't exist any longer.
1783 PassRefPtr<Range> range = editor->compositionRange();
1785 Node* node = range->startContainer();
1786 if (!node || !node->isContentEditable())
1790 // If we're not going to fire a keypress event, then the keydown event was
1791 // canceled. In that case, cancel any existing composition.
1792 if (text.isEmpty() || m_suppressNextKeypressEvent) {
1793 // A browser process sent an IPC message which does not contain a valid
1794 // string, which means an ongoing composition has been canceled.
1795 // If the ongoing composition has been canceled, replace the ongoing
1796 // composition string with an empty string and complete it.
1798 Vector<CompositionUnderline> emptyUnderlines;
1799 editor->setComposition(emptyString, emptyUnderlines, 0, 0);
1800 return text.isEmpty();
1803 // When the range of composition underlines overlap with the range between
1804 // selectionStart and selectionEnd, WebKit somehow won't paint the selection
1805 // at all (see InlineTextBox::paint() function in InlineTextBox.cpp).
1806 // But the selection range actually takes effect.
1807 editor->setComposition(String(text),
1808 CompositionUnderlineVectorBuilder(underlines),
1809 selectionStart, selectionEnd);
1811 return editor->hasComposition();
1814 bool WebViewImpl::confirmComposition()
1816 return confirmComposition(WebString());
1819 bool WebViewImpl::confirmComposition(const WebString& text)
1821 Frame* focused = focusedWebCoreFrame();
1822 if (!focused || !m_imeAcceptEvents)
1824 Editor* editor = focused->editor();
1825 if (!editor || (!editor->hasComposition() && !text.length()))
1828 // We should verify the parent node of this IME composition node are
1829 // editable because JavaScript may delete a parent node of the composition
1830 // node. In this case, WebKit crashes while deleting texts from the parent
1831 // node, which doesn't exist any longer.
1832 PassRefPtr<Range> range = editor->compositionRange();
1834 Node* node = range->startContainer();
1835 if (!node || !node->isContentEditable())
1839 if (editor->hasComposition()) {
1841 editor->confirmComposition(String(text));
1843 editor->confirmComposition();
1845 editor->insertText(String(text), 0);
1850 bool WebViewImpl::compositionRange(size_t* location, size_t* length)
1852 Frame* focused = focusedWebCoreFrame();
1853 if (!focused || !focused->selection() || !m_imeAcceptEvents)
1855 Editor* editor = focused->editor();
1856 if (!editor || !editor->hasComposition())
1859 RefPtr<Range> range = editor->compositionRange();
1863 if (TextIterator::getLocationAndLengthFromRange(focused->selection()->rootEditableElementOrDocumentElement(), range.get(), *location, *length))
1868 WebTextInputType WebViewImpl::textInputType()
1870 Node* node = focusedWebCoreNode();
1872 return WebTextInputTypeNone;
1874 if (node->nodeType() == Node::ELEMENT_NODE) {
1875 Element* element = static_cast<Element*>(node);
1876 if (element->hasLocalName(HTMLNames::inputTag)) {
1877 HTMLInputElement* input = static_cast<HTMLInputElement*>(element);
1879 if (input->readOnly() || input->disabled())
1880 return WebTextInputTypeNone;
1882 if (input->isPasswordField())
1883 return WebTextInputTypePassword;
1884 if (input->isSearchField())
1885 return WebTextInputTypeSearch;
1886 if (input->isEmailField())
1887 return WebTextInputTypeEmail;
1888 if (input->isNumberField())
1889 return WebTextInputTypeNumber;
1890 if (input->isTelephoneField())
1891 return WebTextInputTypeTelephone;
1892 if (input->isURLField())
1893 return WebTextInputTypeURL;
1894 if (input->isDateField())
1895 return WebTextInputTypeDate;
1896 if (input->isDateTimeField())
1897 return WebTextInputTypeDateTime;
1898 if (input->isDateTimeLocalField())
1899 return WebTextInputTypeDateTimeLocal;
1900 if (input->isMonthField())
1901 return WebTextInputTypeMonth;
1902 if (input->isTimeField())
1903 return WebTextInputTypeTime;
1904 if (input->isWeekField())
1905 return WebTextInputTypeWeek;
1906 if (input->isTextField())
1907 return WebTextInputTypeText;
1909 return WebTextInputTypeNone;
1912 if (element->hasLocalName(HTMLNames::textareaTag)) {
1913 HTMLTextAreaElement* textarea = static_cast<HTMLTextAreaElement*>(element);
1915 if (textarea->readOnly() || textarea->disabled())
1916 return WebTextInputTypeNone;
1917 return WebTextInputTypeText;
1921 // For other situations.
1922 if (node->shouldUseInputMethod())
1923 return WebTextInputTypeText;
1925 return WebTextInputTypeNone;
1928 bool WebViewImpl::selectionBounds(WebRect& start, WebRect& end) const
1930 const Frame* frame = focusedWebCoreFrame();
1933 FrameSelection* selection = frame->selection();
1937 if (selection->isCaret()) {
1938 start = end = frame->view()->contentsToWindow(selection->absoluteCaretBounds());
1942 RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange();
1946 RefPtr<Range> range(Range::create(selectedRange->startContainer()->document(),
1947 selectedRange->startContainer(),
1948 selectedRange->startOffset(),
1949 selectedRange->startContainer(),
1950 selectedRange->startOffset()));
1951 start = frame->editor()->firstRectForRange(range.get());
1953 range = Range::create(selectedRange->endContainer()->document(),
1954 selectedRange->endContainer(),
1955 selectedRange->endOffset(),
1956 selectedRange->endContainer(),
1957 selectedRange->endOffset());
1958 end = frame->editor()->firstRectForRange(range.get());
1960 start = frame->view()->contentsToWindow(start);
1961 end = frame->view()->contentsToWindow(end);
1963 if (!frame->selection()->selection().isBaseFirst())
1964 std::swap(start, end);
1968 bool WebViewImpl::caretOrSelectionRange(size_t* location, size_t* length)
1970 const Frame* focused = focusedWebCoreFrame();
1974 FrameSelection* selection = focused->selection();
1978 RefPtr<Range> range = selection->selection().firstRange();
1982 if (TextIterator::getLocationAndLengthFromRange(selection->rootEditableElementOrDocumentElement(), range.get(), *location, *length))
1987 void WebViewImpl::setTextDirection(WebTextDirection direction)
1989 // The Editor::setBaseWritingDirection() function checks if we can change
1990 // the text direction of the selected node and updates its DOM "dir"
1991 // attribute and its CSS "direction" property.
1992 // So, we just call the function as Safari does.
1993 const Frame* focused = focusedWebCoreFrame();
1997 Editor* editor = focused->editor();
1998 if (!editor || !editor->canEdit())
2001 switch (direction) {
2002 case WebTextDirectionDefault:
2003 editor->setBaseWritingDirection(NaturalWritingDirection);
2006 case WebTextDirectionLeftToRight:
2007 editor->setBaseWritingDirection(LeftToRightWritingDirection);
2010 case WebTextDirectionRightToLeft:
2011 editor->setBaseWritingDirection(RightToLeftWritingDirection);
2020 bool WebViewImpl::isAcceleratedCompositingActive() const
2022 #if USE(ACCELERATED_COMPOSITING)
2023 return m_isAcceleratedCompositingActive;
2029 void WebViewImpl::didAcquirePointerLock()
2031 #if ENABLE(POINTER_LOCK)
2033 page()->pointerLockController()->didAcquirePointerLock();
2037 void WebViewImpl::didNotAcquirePointerLock()
2039 #if ENABLE(POINTER_LOCK)
2041 page()->pointerLockController()->didNotAcquirePointerLock();
2045 void WebViewImpl::didLosePointerLock()
2047 #if ENABLE(POINTER_LOCK)
2049 page()->pointerLockController()->didLosePointerLock();
2053 void WebViewImpl::didChangeWindowResizerRect()
2055 if (mainFrameImpl()->frameView())
2056 mainFrameImpl()->frameView()->windowResizerRectChanged();
2059 // WebView --------------------------------------------------------------------
2061 WebSettingsImpl* WebViewImpl::settingsImpl()
2064 m_webSettings = adoptPtr(new WebSettingsImpl(m_page->settings()));
2065 ASSERT(m_webSettings);
2066 return m_webSettings.get();
2069 WebSettings* WebViewImpl::settings()
2071 return settingsImpl();
2074 WebString WebViewImpl::pageEncoding() const
2079 // FIXME: Is this check needed?
2080 if (!m_page->mainFrame()->document()->loader())
2083 return m_page->mainFrame()->document()->encoding();
2086 void WebViewImpl::setPageEncoding(const WebString& encodingName)
2091 // Only change override encoding, don't change default encoding.
2092 // Note that the new encoding must be 0 if it isn't supposed to be set.
2093 String newEncodingName;
2094 if (!encodingName.isEmpty())
2095 newEncodingName = encodingName;
2096 m_page->mainFrame()->loader()->reloadWithOverrideEncoding(newEncodingName);
2099 bool WebViewImpl::dispatchBeforeUnloadEvent()
2101 // FIXME: This should really cause a recursive depth-first walk of all
2102 // frames in the tree, calling each frame's onbeforeunload. At the moment,
2103 // we're consistent with Safari 3.1, not IE/FF.
2104 Frame* frame = m_page->mainFrame();
2108 return frame->loader()->shouldClose();
2111 void WebViewImpl::dispatchUnloadEvent()
2113 // Run unload handlers.
2114 m_page->mainFrame()->loader()->closeURL();
2117 WebFrame* WebViewImpl::mainFrame()
2119 return mainFrameImpl();
2122 WebFrame* WebViewImpl::findFrameByName(
2123 const WebString& name, WebFrame* relativeToFrame)
2125 if (!relativeToFrame)
2126 relativeToFrame = mainFrame();
2127 Frame* frame = static_cast<WebFrameImpl*>(relativeToFrame)->frame();
2128 frame = frame->tree()->find(name);
2129 return WebFrameImpl::fromFrame(frame);
2132 WebFrame* WebViewImpl::focusedFrame()
2134 return WebFrameImpl::fromFrame(focusedWebCoreFrame());
2137 void WebViewImpl::setFocusedFrame(WebFrame* frame)
2140 // Clears the focused frame if any.
2141 Frame* frame = focusedWebCoreFrame();
2143 frame->selection()->setFocused(false);
2146 WebFrameImpl* frameImpl = static_cast<WebFrameImpl*>(frame);
2147 Frame* webcoreFrame = frameImpl->frame();
2148 webcoreFrame->page()->focusController()->setFocusedFrame(webcoreFrame);
2151 void WebViewImpl::setInitialFocus(bool reverse)
2156 // Since we don't have a keyboard event, we'll create one.
2157 WebKeyboardEvent keyboardEvent;
2158 keyboardEvent.type = WebInputEvent::RawKeyDown;
2160 keyboardEvent.modifiers = WebInputEvent::ShiftKey;
2162 // VK_TAB which is only defined on Windows.
2163 keyboardEvent.windowsKeyCode = 0x09;
2164 PlatformKeyboardEventBuilder platformEvent(keyboardEvent);
2165 RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0);
2167 Frame* frame = page()->focusController()->focusedOrMainFrame();
2168 if (Document* document = frame->document())
2169 document->setFocusedNode(0);
2170 page()->focusController()->setInitialFocus(
2171 reverse ? FocusDirectionBackward : FocusDirectionForward,
2175 void WebViewImpl::clearFocusedNode()
2177 RefPtr<Frame> frame = focusedWebCoreFrame();
2181 RefPtr<Document> document = frame->document();
2185 RefPtr<Node> oldFocusedNode = document->focusedNode();
2187 // Clear the focused node.
2188 document->setFocusedNode(0);
2190 if (!oldFocusedNode)
2193 // If a text field has focus, we need to make sure the selection controller
2194 // knows to remove selection from it. Otherwise, the text field is still
2195 // processing keyboard events even though focus has been moved to the page and
2196 // keystrokes get eaten as a result.
2197 if (oldFocusedNode->isContentEditable()
2198 || (oldFocusedNode->isElementNode()
2199 && static_cast<Element*>(oldFocusedNode.get())->isTextFormControl())) {
2200 frame->selection()->clear();
2204 void WebViewImpl::scrollFocusedNodeIntoView()
2206 Node* focusedNode = focusedWebCoreNode();
2207 if (focusedNode && focusedNode->isElementNode()) {
2208 Element* elementNode = static_cast<Element*>(focusedNode);
2209 elementNode->scrollIntoViewIfNeeded(true);
2213 void WebViewImpl::scrollFocusedNodeIntoRect(const WebRect& rect)
2215 Frame* frame = page()->mainFrame();
2216 Node* focusedNode = focusedWebCoreNode();
2217 if (!frame || !frame->view() || !focusedNode || !focusedNode->isElementNode())
2219 Element* elementNode = static_cast<Element*>(focusedNode);
2220 frame->view()->scrollElementToRect(elementNode, IntRect(rect.x, rect.y, rect.width, rect.height));
2223 double WebViewImpl::zoomLevel()
2228 double WebViewImpl::setZoomLevel(bool textOnly, double zoomLevel)
2230 if (zoomLevel < m_minimumZoomLevel)
2231 m_zoomLevel = m_minimumZoomLevel;
2232 else if (zoomLevel > m_maximumZoomLevel)
2233 m_zoomLevel = m_maximumZoomLevel;
2235 m_zoomLevel = zoomLevel;
2237 Frame* frame = mainFrameImpl()->frame();
2238 WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
2239 if (pluginContainer)
2240 pluginContainer->plugin()->setZoomLevel(m_zoomLevel, textOnly);
2242 float zoomFactor = static_cast<float>(zoomLevelToZoomFactor(m_zoomLevel));
2244 frame->setPageAndTextZoomFactors(1, zoomFactor * m_emulatedTextZoomFactor);
2246 frame->setPageAndTextZoomFactors(zoomFactor, m_emulatedTextZoomFactor);
2251 void WebViewImpl::zoomLimitsChanged(double minimumZoomLevel,
2252 double maximumZoomLevel)
2254 m_minimumZoomLevel = minimumZoomLevel;
2255 m_maximumZoomLevel = maximumZoomLevel;
2256 m_client->zoomLimitsChanged(m_minimumZoomLevel, m_maximumZoomLevel);
2259 void WebViewImpl::fullFramePluginZoomLevelChanged(double zoomLevel)
2261 if (zoomLevel == m_zoomLevel)
2264 m_zoomLevel = max(min(zoomLevel, m_maximumZoomLevel), m_minimumZoomLevel);
2265 m_client->zoomLevelChanged();
2268 double WebView::zoomLevelToZoomFactor(double zoomLevel)
2270 return pow(textSizeMultiplierRatio, zoomLevel);
2273 double WebView::zoomFactorToZoomLevel(double factor)
2275 // Since factor = 1.2^level, level = log(factor) / log(1.2)
2276 return log(factor) / log(textSizeMultiplierRatio);
2279 float WebViewImpl::pageScaleFactor() const
2284 return page()->pageScaleFactor();
2287 bool WebViewImpl::isPageScaleFactorSet() const
2289 return m_pageScaleFactorIsSet;
2292 float WebViewImpl::clampPageScaleFactorToLimits(float scaleFactor)
2294 return min(max(scaleFactor, m_minimumPageScaleFactor), m_maximumPageScaleFactor);
2297 WebPoint WebViewImpl::clampOffsetAtScale(const WebPoint& offset, float scale)
2299 // This is the scaled content size. We need to convert it to the new scale factor.
2300 WebSize contentSize = mainFrame()->contentsSize();
2301 float deltaScale = scale / pageScaleFactor();
2302 int docWidthAtNewScale = contentSize.width * deltaScale;
2303 int docHeightAtNewScale = contentSize.height * deltaScale;
2304 int viewWidth = m_size.width;
2305 int viewHeight = m_size.height;
2307 // Enforce the maximum and minimum scroll positions at the new scale.
2308 IntPoint clampedOffset = offset;
2309 clampedOffset = clampedOffset.shrunkTo(IntPoint(docWidthAtNewScale - viewWidth, docHeightAtNewScale - viewHeight));
2310 clampedOffset.clampNegativeToZero();
2311 return clampedOffset;
2314 void WebViewImpl::setPageScaleFactorPreservingScrollOffset(float scaleFactor)
2316 // Pick a scale factor that is within the expected limits
2317 scaleFactor = clampPageScaleFactorToLimits(scaleFactor);
2319 IntPoint scrollOffsetAtNewScale(mainFrame()->scrollOffset().width, mainFrame()->scrollOffset().height);
2320 float deltaScale = scaleFactor / pageScaleFactor();
2321 scrollOffsetAtNewScale.scale(deltaScale, deltaScale);
2323 WebPoint clampedOffsetAtNewScale = clampOffsetAtScale(scrollOffsetAtNewScale, scaleFactor);
2324 setPageScaleFactor(scaleFactor, clampedOffsetAtNewScale);
2327 void WebViewImpl::setPageScaleFactor(float scaleFactor, const WebPoint& origin)
2335 scaleFactor = clampPageScaleFactorToLimits(scaleFactor);
2336 WebPoint clampedOrigin = clampOffsetAtScale(origin, scaleFactor);
2337 page()->setPageScaleFactor(scaleFactor, clampedOrigin);
2338 m_pageScaleFactorIsSet = true;
2341 float WebViewImpl::deviceScaleFactor() const
2346 return page()->deviceScaleFactor();
2349 void WebViewImpl::setDeviceScaleFactor(float scaleFactor)
2354 page()->setDeviceScaleFactor(scaleFactor);
2357 bool WebViewImpl::isFixedLayoutModeEnabled() const
2362 Frame* frame = page()->mainFrame();
2363 if (!frame || !frame->view())
2366 return frame->view()->useFixedLayout();
2369 void WebViewImpl::enableFixedLayoutMode(bool enable)
2374 Frame* frame = page()->mainFrame();
2375 if (!frame || !frame->view())
2378 frame->view()->setUseFixedLayout(enable);
2380 #if USE(ACCELERATED_COMPOSITING)
2381 // Also notify the base layer, which RenderLayerCompositor does not see.
2382 if (m_nonCompositedContentHost) {
2383 m_nonCompositedContentHost->topLevelRootLayer()->deviceOrPageScaleFactorChanged();
2384 updateLayerTreeViewport();
2390 void WebViewImpl::enableAutoResizeMode(const WebSize& minSize, const WebSize& maxSize)
2392 m_shouldAutoResize = true;
2393 m_minAutoSize = minSize;
2394 m_maxAutoSize = maxSize;
2395 configureAutoResizeMode();
2398 void WebViewImpl::disableAutoResizeMode()
2400 m_shouldAutoResize = false;
2401 configureAutoResizeMode();
2404 void WebViewImpl::setPageScaleFactorLimits(float minPageScale, float maxPageScale)
2406 m_pageDefinedMinimumPageScaleFactor = minPageScale;
2407 m_pageDefinedMaximumPageScaleFactor = maxPageScale;
2408 computePageScaleFactorLimits();
2411 bool WebViewImpl::computePageScaleFactorLimits()
2413 if (m_pageDefinedMinimumPageScaleFactor == -1 || m_pageDefinedMaximumPageScaleFactor == -1)
2416 if (!mainFrame() || !page() || !page()->mainFrame() || !page()->mainFrame()->view())
2419 m_minimumPageScaleFactor = min(max(m_pageDefinedMinimumPageScaleFactor, minPageScaleFactor), maxPageScaleFactor) * deviceScaleFactor();
2420 m_maximumPageScaleFactor = max(min(m_pageDefinedMaximumPageScaleFactor, maxPageScaleFactor), minPageScaleFactor) * deviceScaleFactor();
2422 int viewWidthNotIncludingScrollbars = page()->mainFrame()->view()->visibleContentRect(false).width();
2423 int contentsWidth = mainFrame()->contentsSize().width;
2424 if (viewWidthNotIncludingScrollbars && contentsWidth) {
2425 // Limit page scaling down to the document width.
2426 int unscaledContentWidth = contentsWidth / pageScaleFactor();
2427 m_minimumPageScaleFactor = max(m_minimumPageScaleFactor, static_cast<float>(viewWidthNotIncludingScrollbars) / unscaledContentWidth);
2428 m_maximumPageScaleFactor = max(m_minimumPageScaleFactor, m_maximumPageScaleFactor);
2430 ASSERT(m_minimumPageScaleFactor <= m_maximumPageScaleFactor);
2432 float clampedScale = clampPageScaleFactorToLimits(pageScaleFactor());
2433 #if USE(ACCELERATED_COMPOSITING)
2434 if (!m_layerTreeView.isNull())
2435 m_layerTreeView.setPageScaleFactorAndLimits(clampedScale, m_minimumPageScaleFactor, m_maximumPageScaleFactor);
2437 if (clampedScale != pageScaleFactor()) {
2438 setPageScaleFactorPreservingScrollOffset(clampedScale);
2445 float WebViewImpl::minimumPageScaleFactor() const
2447 return m_minimumPageScaleFactor;
2450 float WebViewImpl::maximumPageScaleFactor() const
2452 return m_maximumPageScaleFactor;
2455 WebSize WebViewImpl::fixedLayoutSize() const
2460 Frame* frame = page()->mainFrame();
2461 if (!frame || !frame->view())
2464 return frame->view()->fixedLayoutSize();
2467 void WebViewImpl::setFixedLayoutSize(const WebSize& layoutSize)
2472 Frame* frame = page()->mainFrame();
2473 if (!frame || !frame->view())
2476 frame->view()->setFixedLayoutSize(layoutSize);
2479 void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action,
2480 const WebPoint& location)
2482 HitTestResult result = hitTestResultForWindowPos(location);
2483 RefPtr<Node> node = result.innerNonSharedNode();
2484 if (!node->hasTagName(HTMLNames::videoTag) && !node->hasTagName(HTMLNames::audioTag))
2487 RefPtr<HTMLMediaElement> mediaElement =
2488 static_pointer_cast<HTMLMediaElement>(node);
2489 switch (action.type) {
2490 case WebMediaPlayerAction::Play:
2492 mediaElement->play();
2494 mediaElement->pause();
2496 case WebMediaPlayerAction::Mute:
2497 mediaElement->setMuted(action.enable);
2499 case WebMediaPlayerAction::Loop:
2500 mediaElement->setLoop(action.enable);
2502 case WebMediaPlayerAction::Controls:
2503 mediaElement->setControls(action.enable);
2506 ASSERT_NOT_REACHED();
2510 void WebViewImpl::performPluginAction(const WebPluginAction& action,
2511 const WebPoint& location)
2513 HitTestResult result = hitTestResultForWindowPos(location);
2514 RefPtr<Node> node = result.innerNonSharedNode();
2515 if (!node->hasTagName(HTMLNames::objectTag) && !node->hasTagName(HTMLNames::embedTag))
2518 RenderObject* object = node->renderer();
2519 if (object && object->isWidget()) {
2520 Widget* widget = toRenderWidget(object)->widget();
2521 if (widget && widget->isPluginContainer()) {
2522 WebPluginContainerImpl* plugin = static_cast<WebPluginContainerImpl*>(widget);
2523 switch (action.type) {
2524 case WebPluginAction::Rotate90Clockwise:
2525 plugin->plugin()->rotateView(WebPlugin::RotationType90Clockwise);
2527 case WebPluginAction::Rotate90Counterclockwise:
2528 plugin->plugin()->rotateView(WebPlugin::RotationType90Counterclockwise);
2531 ASSERT_NOT_REACHED();
2537 void WebViewImpl::copyImageAt(const WebPoint& point)
2542 HitTestResult result = hitTestResultForWindowPos(point);
2544 if (result.absoluteImageURL().isEmpty()) {
2545 // There isn't actually an image at these coordinates. Might be because
2546 // the window scrolled while the context menu was open or because the page
2547 // changed itself between when we thought there was an image here and when
2548 // we actually tried to retreive the image.
2550 // FIXME: implement a cache of the most recent HitTestResult to avoid having
2551 // to do two hit tests.
2555 m_page->mainFrame()->editor()->copyImage(result);
2558 void WebViewImpl::dragSourceEndedAt(
2559 const WebPoint& clientPoint,
2560 const WebPoint& screenPoint,
2561 WebDragOperation operation)
2563 PlatformMouseEvent pme(clientPoint,
2565 LeftButton, PlatformEvent::MouseMoved, 0, false, false, false,
2567 m_page->mainFrame()->eventHandler()->dragSourceEndedAt(pme,
2568 static_cast<DragOperation>(operation));
2569 m_dragScrollTimer->stop();
2572 void WebViewImpl::dragSourceMovedTo(
2573 const WebPoint& clientPoint,
2574 const WebPoint& screenPoint,
2575 WebDragOperation operation)
2577 m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint);
2580 void WebViewImpl::dragSourceSystemDragEnded()
2582 // It's possible for us to get this callback while not doing a drag if
2583 // it's from a previous page that got unloaded.
2584 if (m_doingDragAndDrop) {
2585 m_page->dragController()->dragEnded();
2586 m_doingDragAndDrop = false;
2590 WebDragOperation WebViewImpl::dragTargetDragEnter(
2591 const WebDragData& webDragData,
2592 const WebPoint& clientPoint,
2593 const WebPoint& screenPoint,
2594 WebDragOperationsMask operationsAllowed)
2596 ASSERT(!m_currentDragData);
2598 m_currentDragData = webDragData;
2599 m_operationsAllowed = operationsAllowed;
2601 return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragEnter);
2604 WebDragOperation WebViewImpl::dragTargetDragOver(
2605 const WebPoint& clientPoint,
2606 const WebPoint& screenPoint,
2607 WebDragOperationsMask operationsAllowed)
2609 m_operationsAllowed = operationsAllowed;
2611 return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragOver);
2614 void WebViewImpl::dragTargetDragLeave()
2616 ASSERT(m_currentDragData);
2619 m_currentDragData.get(),
2622 static_cast<DragOperation>(m_operationsAllowed));
2624 m_page->dragController()->dragExited(&dragData);
2626 // FIXME: why is the drag scroll timer not stopped here?
2628 m_dragOperation = WebDragOperationNone;
2629 m_currentDragData = 0;
2632 void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint,
2633 const WebPoint& screenPoint)
2635 ASSERT(m_currentDragData);
2637 // If this webview transitions from the "drop accepting" state to the "not
2638 // accepting" state, then our IPC message reply indicating that may be in-
2639 // flight, or else delayed by javascript processing in this webview. If a
2640 // drop happens before our IPC reply has reached the browser process, then
2641 // the browser forwards the drop to this webview. So only allow a drop to
2642 // proceed if our webview m_dragOperation state is not DragOperationNone.
2644 if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop.
2645 dragTargetDragLeave();
2650 m_currentDragData.get(),
2653 static_cast<DragOperation>(m_operationsAllowed));
2655 m_page->dragController()->performDrag(&dragData);
2657 m_dragOperation = WebDragOperationNone;
2658 m_currentDragData = 0;
2660 m_dragScrollTimer->stop();
2663 WebDragOperation WebViewImpl::dragTargetDragEnterOrOver(const WebPoint& clientPoint, const WebPoint& screenPoint, DragAction dragAction)
2665 ASSERT(m_currentDragData);
2668 m_currentDragData.get(),
2671 static_cast<DragOperation>(m_operationsAllowed));
2673 DragSession dragSession;
2674 if (dragAction == DragEnter)
2675 dragSession = m_page->dragController()->dragEntered(&dragData);
2677 dragSession = m_page->dragController()->dragUpdated(&dragData);
2679 DragOperation dropEffect = dragSession.operation;
2681 // Mask the drop effect operation against the drag source's allowed operations.
2682 if (!(dropEffect & dragData.draggingSourceOperationMask()))
2683 dropEffect = DragOperationNone;
2685 m_dragOperation = static_cast<WebDragOperation>(dropEffect);
2687 if (dragAction == DragOver)
2688 m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint);
2690 m_dragScrollTimer->stop();
2692 return m_dragOperation;
2695 void WebViewImpl::sendResizeEventAndRepaint()
2697 if (mainFrameImpl()->frameView()) {
2698 // Enqueues the resize event.
2699 mainFrameImpl()->frame()->eventHandler()->sendResizeEvent();
2703 if (isAcceleratedCompositingActive()) {
2704 #if USE(ACCELERATED_COMPOSITING)
2705 updateLayerTreeViewport();
2708 WebRect damagedRect(0, 0, m_size.width, m_size.height);
2709 m_client->didInvalidateRect(damagedRect);
2714 void WebViewImpl::configureAutoResizeMode()
2716 if (!mainFrameImpl() || !mainFrameImpl()->frame() || !mainFrameImpl()->frame()->view())
2719 mainFrameImpl()->frame()->view()->enableAutoSizeMode(m_shouldAutoResize, m_minAutoSize, m_maxAutoSize);
2722 unsigned long WebViewImpl::createUniqueIdentifierForRequest()
2725 return m_page->progress()->createUniqueIdentifier();
2729 void WebViewImpl::inspectElementAt(const WebPoint& point)
2734 if (point.x == -1 || point.y == -1)
2735 m_page->inspectorController()->inspect(0);
2737 HitTestResult result = hitTestResultForWindowPos(point);
2739 if (!result.innerNonSharedNode())
2742 m_page->inspectorController()->inspect(result.innerNonSharedNode());
2746 WebString WebViewImpl::inspectorSettings() const
2748 return m_inspectorSettings;
2751 void WebViewImpl::setInspectorSettings(const WebString& settings)
2753 m_inspectorSettings = settings;
2756 bool WebViewImpl::inspectorSetting(const WebString& key, WebString* value) const
2758 if (!m_inspectorSettingsMap->contains(key))
2760 *value = m_inspectorSettingsMap->get(key);
2764 void WebViewImpl::setInspectorSetting(const WebString& key,
2765 const WebString& value)
2767 m_inspectorSettingsMap->set(key, value);
2768 client()->didUpdateInspectorSetting(key, value);
2771 WebDevToolsAgent* WebViewImpl::devToolsAgent()
2773 return m_devToolsAgent.get();
2776 WebAccessibilityObject WebViewImpl::accessibilityObject()
2778 if (!mainFrameImpl())
2779 return WebAccessibilityObject();
2781 Document* document = mainFrameImpl()->frame()->document();
2782 return WebAccessibilityObject(
2783 document->axObjectCache()->getOrCreate(document->renderer()));
2786 void WebViewImpl::applyAutofillSuggestions(
2787 const WebNode& node,
2788 const WebVector<WebString>& names,
2789 const WebVector<WebString>& labels,
2790 const WebVector<WebString>& icons,
2791 const WebVector<int>& itemIDs,
2794 ASSERT(names.size() == labels.size());
2795 ASSERT(names.size() == itemIDs.size());
2797 if (names.isEmpty()) {
2798 hideAutofillPopup();
2802 RefPtr<Node> focusedNode = focusedWebCoreNode();
2803 // If the node for which we queried the Autofill suggestions is not the
2804 // focused node, then we have nothing to do. FIXME: also check the
2805 // caret is at the end and that the text has not changed.
2806 if (!focusedNode || focusedNode != PassRefPtr<Node>(node)) {
2807 hideAutofillPopup();
2811 HTMLInputElement* inputElem = focusedNode->toInputElement();
2814 // The first time the Autofill popup is shown we'll create the client and
2816 if (!m_autofillPopupClient)
2817 m_autofillPopupClient = adoptPtr(new AutofillPopupMenuClient);
2819 m_autofillPopupClient->initialize(
2820 inputElem, names, labels, icons, itemIDs, separatorIndex);
2822 if (!m_autofillPopup) {
2823 PopupContainerSettings popupSettings = autofillPopupSettings;
2824 popupSettings.defaultDeviceScaleFactor =
2825 m_page->settings()->defaultDeviceScaleFactor();
2826 if (!popupSettings.defaultDeviceScaleFactor)
2827 popupSettings.defaultDeviceScaleFactor = 1;
2828 m_autofillPopup = PopupContainer::create(m_autofillPopupClient.get(),
2829 PopupContainer::Suggestion,
2833 if (m_autofillPopupShowing) {
2834 refreshAutofillPopup();
2836 m_autofillPopupShowing = true;
2837 m_autofillPopup->showInRect(focusedNode->getPixelSnappedRect(), focusedNode->ownerDocument()->view(), 0);
2841 void WebViewImpl::hidePopups()
2844 hideAutofillPopup();
2845 #if ENABLE(PAGE_POPUP)
2847 closePagePopup(m_pagePopup.get());
2851 void WebViewImpl::performCustomContextMenuAction(unsigned action)
2855 ContextMenu* menu = m_page->contextMenuController()->contextMenu();
2858 ContextMenuItem* item = menu->itemWithAction(static_cast<ContextMenuAction>(ContextMenuItemBaseCustomTag + action));
2860 m_page->contextMenuController()->contextMenuItemSelected(item);
2861 m_page->contextMenuController()->clearContextMenu();
2864 // WebView --------------------------------------------------------------------
2866 void WebViewImpl::setIsTransparent(bool isTransparent)
2868 // Set any existing frames to be transparent.
2869 Frame* frame = m_page->mainFrame();
2871 frame->view()->setTransparent(isTransparent);
2872 frame = frame->tree()->traverseNext();
2875 // Future frames check this to know whether to be transparent.
2876 m_isTransparent = isTransparent;
2879 bool WebViewImpl::isTransparent() const
2881 return m_isTransparent;
2884 void WebViewImpl::setIsActive(bool active)
2886 if (page() && page()->focusController())
2887 page()->focusController()->setActive(active);
2890 bool WebViewImpl::isActive() const
2892 return (page() && page()->focusController()) ? page()->focusController()->isActive() : false;
2895 void WebViewImpl::setDomainRelaxationForbidden(bool forbidden, const WebString& scheme)
2897 SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(forbidden, String(scheme));
2900 void WebViewImpl::setScrollbarColors(unsigned inactiveColor,
2901 unsigned activeColor,
2902 unsigned trackColor) {
2903 #if OS(UNIX) && !OS(DARWIN) && !OS(ANDROID)
2904 PlatformThemeChromiumLinux::setScrollbarColors(inactiveColor, activeColor, trackColor);
2908 void WebViewImpl::setSelectionColors(unsigned activeBackgroundColor,
2909 unsigned activeForegroundColor,
2910 unsigned inactiveBackgroundColor,
2911 unsigned inactiveForegroundColor) {
2912 #if OS(UNIX) && !OS(DARWIN) && !OS(ANDROID)
2913 RenderThemeChromiumLinux::setSelectionColors(activeBackgroundColor,
2914 activeForegroundColor,
2915 inactiveBackgroundColor,
2916 inactiveForegroundColor);
2917 theme()->platformColorsDidChange();
2921 void WebView::addUserScript(const WebString& sourceCode,
2922 const WebVector<WebString>& patternsIn,
2923 WebView::UserScriptInjectAt injectAt,
2924 WebView::UserContentInjectIn injectIn)
2926 OwnPtr<Vector<String> > patterns = adoptPtr(new Vector<String>);
2927 for (size_t i = 0; i < patternsIn.size(); ++i)
2928 patterns->append(patternsIn[i]);
2930 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
2931 RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create());
2932 pageGroup->addUserScriptToWorld(world.get(), sourceCode, WebURL(), patterns.release(), nullptr,
2933 static_cast<UserScriptInjectionTime>(injectAt),
2934 static_cast<UserContentInjectedFrames>(injectIn));
2937 void WebView::addUserStyleSheet(const WebString& sourceCode,
2938 const WebVector<WebString>& patternsIn,
2939 WebView::UserContentInjectIn injectIn,
2940 WebView::UserStyleInjectionTime injectionTime)
2942 OwnPtr<Vector<String> > patterns = adoptPtr(new Vector<String>);
2943 for (size_t i = 0; i < patternsIn.size(); ++i)
2944 patterns->append(patternsIn[i]);
2946 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
2947 RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create());
2949 // FIXME: Current callers always want the level to be "author". It probably makes sense to let
2950 // callers specify this though, since in other cases the caller will probably want "user" level.
2952 // FIXME: It would be nice to populate the URL correctly, instead of passing an empty URL.
2953 pageGroup->addUserStyleSheetToWorld(world.get(), sourceCode, WebURL(), patterns.release(), nullptr,
2954 static_cast<UserContentInjectedFrames>(injectIn),
2955 UserStyleAuthorLevel,
2956 static_cast<WebCore::UserStyleInjectionTime>(injectionTime));
2959 void WebView::removeAllUserContent()
2961 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
2962 pageGroup->removeAllUserContent();
2965 void WebViewImpl::didCommitLoad(bool* isNewNavigation, bool isNavigationWithinPage)
2967 if (isNewNavigation)
2968 *isNewNavigation = m_observedNewNavigation;
2971 ASSERT(!m_observedNewNavigation
2972 || m_page->mainFrame()->loader()->documentLoader() == m_newNavigationLoader);
2973 m_newNavigationLoader = 0;
2975 m_observedNewNavigation = false;
2976 if (!isNavigationWithinPage)
2977 m_pageScaleFactorIsSet = false;
2979 m_gestureAnimation.clear();
2982 void WebViewImpl::layoutUpdated(WebFrameImpl* webframe)
2984 if (!m_client || webframe != mainFrameImpl())
2987 if (m_shouldAutoResize && mainFrameImpl()->frame() && mainFrameImpl()->frame()->view()) {
2988 WebSize frameSize = mainFrameImpl()->frame()->view()->frameRect().size();
2989 if (frameSize != m_size) {
2991 m_client->didAutoResize(m_size);
2992 sendResizeEventAndRepaint();
2996 m_client->didUpdateLayout();
2999 void WebViewImpl::didChangeContentsSize()
3001 #if ENABLE(VIEWPORT)
3002 if (!settings()->viewportEnabled())
3005 bool didChangeScale = false;
3006 if (!isPageScaleFactorSet()) {
3007 // If the viewport tag failed to be processed earlier, we need
3008 // to recompute it now.
3009 ViewportArguments viewportArguments = mainFrameImpl()->frame()->document()->viewportArguments();
3010 m_page->chrome()->client()->dispatchViewportPropertiesDidChange(viewportArguments);
3011 didChangeScale = true;
3013 didChangeScale = computePageScaleFactorLimits();
3015 if (!didChangeScale)
3018 if (!mainFrameImpl())
3021 FrameView* view = mainFrameImpl()->frameView();
3022 if (view && view->needsLayout())
3027 bool WebViewImpl::useExternalPopupMenus()
3029 return shouldUseExternalPopupMenus;
3032 void WebViewImpl::setEmulatedTextZoomFactor(float textZoomFactor)
3034 m_emulatedTextZoomFactor = textZoomFactor;
3035 Frame* frame = mainFrameImpl()->frame();
3037 frame->setPageAndTextZoomFactors(frame->pageZoomFactor(), m_emulatedTextZoomFactor);
3040 bool WebViewImpl::navigationPolicyFromMouseEvent(unsigned short button,
3041 bool ctrl, bool shift,
3042 bool alt, bool meta,
3043 WebNavigationPolicy* policy)
3046 const bool newTabModifier = (button == 1) || meta;
3048 const bool newTabModifier = (button == 1) || ctrl;
3050 if (!newTabModifier && !shift && !alt)
3054 if (newTabModifier) {
3056 *policy = WebNavigationPolicyNewForegroundTab;
3058 *policy = WebNavigationPolicyNewBackgroundTab;
3061 *policy = WebNavigationPolicyNewWindow;
3063 *policy = WebNavigationPolicyDownload;
3068 void WebViewImpl::startDragging(const WebDragData& dragData,
3069 WebDragOperationsMask mask,
3070 const WebImage& dragImage,
3071 const WebPoint& dragImageOffset)
3075 ASSERT(!m_doingDragAndDrop);
3076 m_doingDragAndDrop = true;
3077 m_client->startDragging(dragData, mask, dragImage, dragImageOffset);
3080 void WebViewImpl::observeNewNavigation()
3082 m_observedNewNavigation = true;
3084 m_newNavigationLoader = m_page->mainFrame()->loader()->documentLoader();
3088 void WebViewImpl::setIgnoreInputEvents(bool newValue)
3090 ASSERT(m_ignoreInputEvents != newValue);
3091 m_ignoreInputEvents = newValue;
3094 void WebViewImpl::addPageOverlay(WebPageOverlay* overlay, int zOrder)
3096 if (!m_pageOverlays)
3097 m_pageOverlays = PageOverlayList::create(this);
3099 m_pageOverlays->add(overlay, zOrder);
3102 void WebViewImpl::removePageOverlay(WebPageOverlay* overlay)
3104 if (m_pageOverlays && m_pageOverlays->remove(overlay) && m_pageOverlays->empty())
3105 m_pageOverlays = nullptr;
3108 void WebViewImpl::setOverlayLayer(WebCore::GraphicsLayer* layer)
3110 if (m_rootGraphicsLayer) {
3111 if (layer->parent() != m_rootGraphicsLayer)
3112 m_rootGraphicsLayer->addChild(layer);
3116 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
3117 NotificationPresenterImpl* WebViewImpl::notificationPresenterImpl()
3119 if (!m_notificationPresenter.isInitialized() && m_client)
3120 m_notificationPresenter.initialize(m_client->notificationPresenter());
3121 return &m_notificationPresenter;
3125 void WebViewImpl::refreshAutofillPopup()
3127 ASSERT(m_autofillPopupShowing);
3129 // Hide the popup if it has become empty.
3130 if (!m_autofillPopupClient->listSize()) {
3131 hideAutofillPopup();
3135 WebRect newWidgetRect = m_autofillPopup->refresh(focusedWebCoreNode()->getPixelSnappedRect());
3136 // Let's resize the backing window if necessary.
3137 WebPopupMenuImpl* popupMenu = static_cast<WebPopupMenuImpl*>(m_autofillPopup->client());
3138 if (popupMenu && popupMenu->client()->windowRect() != newWidgetRect)
3139 popupMenu->client()->setWindowRect(newWidgetRect);
3142 Node* WebViewImpl::focusedWebCoreNode()
3144 Frame* frame = m_page->focusController()->focusedFrame();
3148 Document* document = frame->document();
3152 return document->focusedNode();
3155 HitTestResult WebViewImpl::hitTestResultForWindowPos(const IntPoint& pos)
3157 IntPoint docPoint(m_page->mainFrame()->view()->windowToContents(pos));
3158 return m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(docPoint, false);
3161 void WebViewImpl::setTabsToLinks(bool enable)
3163 m_tabsToLinks = enable;
3166 bool WebViewImpl::tabsToLinks() const
3168 return m_tabsToLinks;
3171 #if USE(ACCELERATED_COMPOSITING)
3172 bool WebViewImpl::allowsAcceleratedCompositing()
3174 return !m_compositorCreationFailed;
3177 bool WebViewImpl::pageHasRTLStyle() const
3181 Document* document = page()->mainFrame()->document();
3184 RenderView* renderView = document->renderView();
3187 RenderStyle* style = renderView->style();
3190 return (style->direction() == RTL);
3193 void WebViewImpl::setRootGraphicsLayer(GraphicsLayer* layer)
3195 m_rootGraphicsLayer = layer;
3197 setIsAcceleratedCompositingActive(layer);
3198 if (m_nonCompositedContentHost) {
3199 GraphicsLayer* scrollLayer = 0;
3201 Document* document = page()->mainFrame()->document();
3202 RenderView* renderView = document->renderView();
3203 RenderLayerCompositor* compositor = renderView->compositor();
3204 scrollLayer = compositor->scrollLayer();
3206 m_nonCompositedContentHost->setScrollLayer(scrollLayer);
3210 m_rootLayer = WebLayer(layer->platformLayer());
3212 if (!m_layerTreeView.isNull())
3213 m_layerTreeView.setRootLayer(layer ? &m_rootLayer : 0);
3215 IntRect damagedRect(0, 0, m_size.width, m_size.height);
3216 if (!m_isAcceleratedCompositingActive)
3217 m_client->didInvalidateRect(damagedRect);
3220 void WebViewImpl::scheduleCompositingLayerSync()
3222 m_layerTreeView.setNeedsRedraw();
3225 void WebViewImpl::scrollRootLayerRect(const IntSize&, const IntRect&)
3227 updateLayerTreeViewport();
3230 void WebViewImpl::invalidateRootLayerRect(const IntRect& rect)
3232 ASSERT(!m_layerTreeView.isNull());
3237 FrameView* view = page()->mainFrame()->view();
3238 IntRect dirtyRect = view->windowToContents(rect);
3239 updateLayerTreeViewport();
3240 m_nonCompositedContentHost->invalidateRect(dirtyRect);
3243 NonCompositedContentHost* WebViewImpl::nonCompositedContentHost()
3245 return m_nonCompositedContentHost.get();
3248 void WebViewImpl::setBackgroundColor(const WebCore::Color& color)
3250 WebCore::Color documentBackgroundColor = color.isValid() ? color : WebCore::Color::white;
3251 WebColor webDocumentBackgroundColor = documentBackgroundColor.rgb();
3252 m_nonCompositedContentHost->setBackgroundColor(documentBackgroundColor);
3253 m_layerTreeView.setBackgroundColor(webDocumentBackgroundColor);
3256 #if ENABLE(REQUEST_ANIMATION_FRAME)
3257 void WebViewImpl::scheduleAnimation()
3259 if (isAcceleratedCompositingActive()) {
3260 if (CCProxy::hasImplThread()) {
3261 ASSERT(!m_layerTreeView.isNull());
3262 m_layerTreeView.setNeedsAnimate();
3264 m_client->scheduleAnimation();
3266 m_client->scheduleAnimation();
3270 class WebViewImplContentPainter : public LayerPainterChromium {
3271 WTF_MAKE_NONCOPYABLE(WebViewImplContentPainter);
3273 static PassOwnPtr<WebViewImplContentPainter*> create(WebViewImpl* webViewImpl)
3275 return adoptPtr(new WebViewImplContentPainter(webViewImpl));
3278 virtual void paint(GraphicsContext& context, const IntRect& contentRect)
3280 double paintStart = currentTime();
3281 Page* page = m_webViewImpl->page();
3284 FrameView* view = page->mainFrame()->view();
3285 view->paintContents(&context, contentRect);
3286 double paintEnd = currentTime();
3287 double pixelsPerSec = (contentRect.width() * contentRect.height()) / (paintEnd - paintStart);
3288 WebKit::Platform::current()->histogramCustomCounts("Renderer4.AccelRootPaintDurationMS", (paintEnd - paintStart) * 1000, 0, 120, 30);
3289 WebKit::Platform::current()->histogramCustomCounts("Renderer4.AccelRootPaintMegapixPerSecond", pixelsPerSec / 1000000, 10, 210, 30);
3291 m_webViewImpl->setBackgroundColor(view->documentBackgroundColor());
3295 explicit WebViewImplContentPainter(WebViewImpl* webViewImpl)
3296 : m_webViewImpl(webViewImpl)
3300 WebViewImpl* m_webViewImpl;
3303 void WebViewImpl::setIsAcceleratedCompositingActive(bool active)
3305 WebKit::Platform::current()->histogramEnumeration("GPU.setIsAcceleratedCompositingActive", active * 2 + m_isAcceleratedCompositingActive, 4);
3307 if (m_isAcceleratedCompositingActive == active)
3311 m_isAcceleratedCompositingActive = false;
3312 // We need to finish all GL rendering before sending didDeactivateCompositor() to prevent
3313 // flickering when compositing turns off.
3314 if (!m_layerTreeView.isNull())
3315 m_layerTreeView.finishAllRendering();
3316 m_client->didDeactivateCompositor();
3317 } else if (!m_layerTreeView.isNull()) {
3318 m_isAcceleratedCompositingActive = true;
3319 updateLayerTreeViewport();
3321 m_client->didActivateCompositor(m_layerTreeView.compositorIdentifier());
3323 TRACE_EVENT("WebViewImpl::setIsAcceleratedCompositingActive(true)", this, 0);
3325 WebLayerTreeView::Settings layerTreeViewSettings;
3326 layerTreeViewSettings.acceleratePainting = page()->settings()->acceleratedDrawingEnabled();
3327 layerTreeViewSettings.showFPSCounter = settingsImpl()->showFPSCounter();
3328 layerTreeViewSettings.showPlatformLayerTree = settingsImpl()->showPlatformLayerTree();
3329 layerTreeViewSettings.showPaintRects = settingsImpl()->showPaintRects();
3331 layerTreeViewSettings.perTilePainting = page()->settings()->perTileDrawingEnabled();
3332 layerTreeViewSettings.partialSwapEnabled = page()->settings()->partialSwapEnabled();
3333 layerTreeViewSettings.threadedAnimationEnabled = page()->settings()->threadedAnimationEnabled();
3335 m_nonCompositedContentHost = NonCompositedContentHost::create(WebViewImplContentPainter::create(this));
3336 m_nonCompositedContentHost->setShowDebugBorders(page()->settings()->showDebugBorders());
3338 m_layerTreeView.initialize(this, m_rootLayer, layerTreeViewSettings);
3339 if (!m_layerTreeView.isNull()) {
3340 m_layerTreeView.setPageScaleFactorAndLimits(pageScaleFactor(), m_minimumPageScaleFactor, m_maximumPageScaleFactor);
3341 if (m_compositorSurfaceReady)
3342 m_layerTreeView.setSurfaceReady();
3343 updateLayerTreeViewport();
3344 m_client->didActivateCompositor(m_layerTreeView.compositorIdentifier());
3345 m_isAcceleratedCompositingActive = true;
3346 m_compositorCreationFailed = false;
3348 m_pageOverlays->update();
3350 m_nonCompositedContentHost.clear();
3351 m_isAcceleratedCompositingActive = false;
3352 m_client->didDeactivateCompositor();
3353 m_compositorCreationFailed = true;
3357 page()->mainFrame()->view()->setClipsRepaints(!m_isAcceleratedCompositingActive);
3362 PassOwnPtr<WebKit::WebGraphicsContext3D> WebViewImpl::createCompositorGraphicsContext3D()
3364 // Explicitly disable antialiasing for the compositor. As of the time of
3365 // this writing, the only platform that supported antialiasing for the
3366 // compositor was Mac OS X, because the on-screen OpenGL context creation
3367 // code paths on Windows and Linux didn't yet have multisampling support.
3368 // Mac OS X essentially always behaves as though it's rendering offscreen.
3369 // Multisampling has a heavy cost especially on devices with relatively low
3370 // fill rate like most notebooks, and the Mac implementation would need to
3371 // be optimized to resolve directly into the IOSurface shared between the
3372 // GPU and browser processes. For these reasons and to avoid platform
3373 // disparities we explicitly disable antialiasing.
3374 WebKit::WebGraphicsContext3D::Attributes attributes;
3375 attributes.antialias = false;
3376 attributes.shareResources = true;
3378 OwnPtr<WebGraphicsContext3D> webContext = adoptPtr(client()->createGraphicsContext3D(attributes));
3382 return webContext.release();
3385 WebKit::WebGraphicsContext3D* WebViewImpl::createContext3D()
3387 OwnPtr<WebKit::WebGraphicsContext3D> webContext;
3389 // If we've already created an onscreen context for this view, return that.
3390 if (m_temporaryOnscreenGraphicsContext3D)
3391 webContext = m_temporaryOnscreenGraphicsContext3D.release();
3392 else // Otherwise make a new one.
3393 webContext = createCompositorGraphicsContext3D();
3394 // The caller takes ownership of this object, but since there's no equivalent of PassOwnPtr<> in the WebKit API
3395 // we return a raw pointer.
3396 return webContext.leakPtr();
3399 void WebViewImpl::applyScrollAndScale(const WebSize& scrollDelta, float pageScaleDelta)
3401 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
3404 if (pageScaleDelta == 1) {
3405 TRACE_EVENT_INSTANT2("webkit", "WebViewImpl::applyScrollAndScale::scrollBy", "x", scrollDelta.width, "y", scrollDelta.height);
3406 mainFrameImpl()->frameView()->scrollBy(scrollDelta);
3408 // The page scale changed, so apply a scale and scroll in a single
3409 // operation. The old scroll offset (and passed-in delta) are
3410 // in the old coordinate space, so we first need to multiply them
3411 // by the page scale delta.
3412 WebSize scrollOffset = mainFrame()->scrollOffset();
3413 scrollOffset.width += scrollDelta.width;
3414 scrollOffset.height += scrollDelta.height;
3415 WebPoint scaledScrollOffset(scrollOffset.width * pageScaleDelta,
3416 scrollOffset.height * pageScaleDelta);
3417 setPageScaleFactor(pageScaleFactor() * pageScaleDelta, scaledScrollOffset);
3421 void WebViewImpl::didCommit()
3424 m_client->didBecomeReadyForAdditionalInput();
3427 void WebViewImpl::didCommitAndDrawFrame()
3430 m_client->didCommitAndDrawCompositorFrame();
3433 void WebViewImpl::didCompleteSwapBuffers()
3436 m_client->didCompleteSwapBuffers();
3439 void WebViewImpl::didRebindGraphicsContext(bool success)
3442 // Switch back to software rendering mode, if necessary
3444 ASSERT(m_isAcceleratedCompositingActive);
3445 setIsAcceleratedCompositingActive(false);
3446 m_compositorCreationFailed = true;
3447 m_client->didInvalidateRect(IntRect(0, 0, m_size.width, m_size.height));
3449 // Force a style recalc to remove all the composited layers.
3450 m_page->mainFrame()->document()->scheduleForcedStyleRecalc();
3455 m_pageOverlays->update();
3458 void WebViewImpl::scheduleComposite()
3460 ASSERT(!CCProxy::hasImplThread());
3461 m_client->scheduleComposite();
3464 void WebViewImpl::updateLayerTreeViewport()
3466 if (!page() || !m_nonCompositedContentHost || m_layerTreeView.isNull())
3469 FrameView* view = page()->mainFrame()->view();
3470 IntRect visibleRect = view->visibleContentRect(true /* include scrollbars */);
3471 IntPoint scroll(view->scrollX(), view->scrollY());
3473 int layerAdjustX = 0;
3474 if (pageHasRTLStyle()) {
3475 // The origin of the initial containing block for RTL root layers is not
3476 // at the far left side of the layer bounds. Instead, it's one viewport
3477 // width (not including scrollbars) to the left of the right side of the
3479 layerAdjustX = -view->contentsSize().width() + view->visibleContentRect(false).width();
3481 m_nonCompositedContentHost->setViewport(visibleRect.size(), view->contentsSize(), scroll, pageScaleFactor(), layerAdjustX);
3482 m_layerTreeView.setViewportSize(size());
3483 m_layerTreeView.setPageScaleFactorAndLimits(pageScaleFactor(), m_minimumPageScaleFactor, m_maximumPageScaleFactor);
3486 WebGraphicsContext3D* WebViewImpl::graphicsContext3D()
3488 #if USE(ACCELERATED_COMPOSITING)
3489 if (m_page->settings()->acceleratedCompositingEnabled() && allowsAcceleratedCompositing()) {
3490 if (!m_layerTreeView.isNull()) {
3491 WebGraphicsContext3D* context = m_layerTreeView.context();
3492 if (context && !context->isContextLost())
3495 // If we get here it means that some system needs access to the context the compositor will use but the compositor itself
3496 // hasn't requested a context or it was unable to successfully instantiate a context.
3497 // We need to return the context that the compositor will later use so we allocate a new context (if needed) and stash it
3498 // until the compositor requests and takes ownership of the context via createLayerTreeHost3D().
3499 if (!m_temporaryOnscreenGraphicsContext3D)
3500 m_temporaryOnscreenGraphicsContext3D = createCompositorGraphicsContext3D();
3502 WebGraphicsContext3D* webContext = m_temporaryOnscreenGraphicsContext3D.get();
3503 if (webContext && !webContext->isContextLost())
3510 WebGraphicsContext3D* WebViewImpl::sharedGraphicsContext3D()
3512 if (!m_page->settings()->acceleratedCompositingEnabled() || !allowsAcceleratedCompositing())
3515 return GraphicsContext3DPrivate::extractWebGraphicsContext3D(SharedGraphicsContext3D::get().get());
3518 void WebViewImpl::setVisibilityState(WebPageVisibilityState visibilityState,
3519 bool isInitialState) {
3523 #if ENABLE(PAGE_VISIBILITY_API)
3524 ASSERT(visibilityState == WebPageVisibilityStateVisible
3525 || visibilityState == WebPageVisibilityStateHidden
3526 || visibilityState == WebPageVisibilityStatePrerender
3527 || visibilityState == WebPageVisibilityStatePreview);
3528 m_page->setVisibilityState(static_cast<PageVisibilityState>(static_cast<int>(visibilityState)), isInitialState);
3531 #if USE(ACCELERATED_COMPOSITING)
3532 if (!m_layerTreeView.isNull()) {
3533 bool visible = visibilityState == WebPageVisibilityStateVisible;
3534 if (!visible && isAcceleratedCompositingActive())
3535 m_nonCompositedContentHost->protectVisibleTileTextures();
3536 m_layerTreeView.setVisible(visible);
3541 #if ENABLE(POINTER_LOCK)
3542 bool WebViewImpl::requestPointerLock()
3544 return m_client && m_client->requestPointerLock();
3547 void WebViewImpl::requestPointerUnlock()
3550 m_client->requestPointerUnlock();
3553 bool WebViewImpl::isPointerLocked()
3555 return m_client && m_client->isPointerLocked();
3558 void WebViewImpl::pointerLockMouseEvent(const WebInputEvent& event)
3560 AtomicString eventType;
3561 switch (event.type) {
3562 case WebInputEvent::MouseDown:
3563 eventType = eventNames().mousedownEvent;
3565 case WebInputEvent::MouseUp:
3566 eventType = eventNames().mouseupEvent;
3568 case WebInputEvent::MouseMove:
3569 eventType = eventNames().mousemoveEvent;
3572 ASSERT_NOT_REACHED();
3575 const WebMouseEvent& mouseEvent = static_cast<const WebMouseEvent&>(event);
3578 page()->pointerLockController()->dispatchLockedMouseEvent(
3579 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), mouseEvent),
3584 } // namespace WebKit