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 "BatteryController.h"
40 #include "CSSValueKeywords.h"
43 #include "ColorSpace.h"
44 #include "CompositionUnderlineVectorBuilder.h"
45 #include "CompositorHUDFontAtlas.h"
46 #include "ContextFeaturesClientImpl.h"
47 #include "ContextMenu.h"
48 #include "ContextMenuController.h"
49 #include "ContextMenuItem.h"
51 #include "DOMUtilitiesPrivate.h"
52 #include "DeviceOrientationClientProxy.h"
54 #include "DocumentLoader.h"
55 #include "DragController.h"
57 #include "DragScrollTimer.h"
58 #include "DragSession.h"
60 #include "EventHandler.h"
61 #include "Extensions3D.h"
62 #include "FocusController.h"
63 #include "FontDescription.h"
65 #include "FrameLoader.h"
66 #include "FrameSelection.h"
67 #include "FrameTree.h"
68 #include "FrameView.h"
69 #include "GeolocationClientProxy.h"
70 #include "GeolocationController.h"
71 #include "GraphicsContext.h"
72 #include "GraphicsContext3D.h"
73 #include "GraphicsContext3DPrivate.h"
74 #include "HTMLInputElement.h"
75 #include "HTMLMediaElement.h"
76 #include "HTMLNames.h"
77 #include "HTMLTextAreaElement.h"
78 #include "HitTestResult.h"
80 #include "ImageBuffer.h"
81 #include "InspectorController.h"
82 #include "InspectorInstrumentation.h"
83 #include "KeyboardCodes.h"
84 #include "KeyboardEvent.h"
85 #include "LayerPainterChromium.h"
86 #include "MIMETypeRegistry.h"
87 #include "NodeRenderStyle.h"
88 #include "NonCompositedContentHost.h"
90 #include "PageGroup.h"
91 #include "PageGroupLoadDeferrer.h"
92 #include "PagePopupClient.h"
93 #include "PageWidgetDelegate.h"
94 #include "Pasteboard.h"
95 #include "PlatformContextSkia.h"
96 #include "PlatformKeyboardEvent.h"
97 #include "PlatformMouseEvent.h"
98 #include "PlatformThemeChromiumLinux.h"
99 #include "PlatformWheelEvent.h"
100 #include "PointerLockController.h"
101 #include "PopupContainer.h"
102 #include "PopupMenuClient.h"
103 #include "PrerendererClientImpl.h"
104 #include "ProgressTracker.h"
105 #include "RenderLayerCompositor.h"
106 #include "RenderView.h"
107 #include "RenderWidget.h"
108 #include "ResourceHandle.h"
109 #include "SchemeRegistry.h"
110 #include "SecurityOrigin.h"
111 #include "SecurityPolicy.h"
112 #include "Settings.h"
113 #include "SharedGraphicsContext3D.h"
114 #include "SpeechInputClientImpl.h"
115 #include "SpeechRecognitionClientProxy.h"
116 #include "StyleResolver.h"
118 #include "TextFieldDecoratorImpl.h"
119 #include "TextIterator.h"
121 #include "TouchpadFlingPlatformGestureCurve.h"
122 #include "TraceEvent.h"
123 #include "UserGestureIndicator.h"
124 #include "WebAccessibilityObject.h"
125 #include "WebActiveWheelFlingParameters.h"
126 #include "WebAutofillClient.h"
127 #include "WebCompositorImpl.h"
128 #include "WebDevToolsAgentImpl.h"
129 #include "WebDevToolsAgentPrivate.h"
130 #include "WebFrameImpl.h"
131 #include "WebHelperPluginImpl.h"
132 #include "WebHitTestResult.h"
133 #include "WebInputElement.h"
134 #include "WebInputEvent.h"
135 #include "WebInputEventConversion.h"
136 #include "WebMediaPlayerAction.h"
138 #include "WebPagePopupImpl.h"
139 #include "WebPlugin.h"
140 #include "WebPluginAction.h"
141 #include "WebPluginContainerImpl.h"
142 #include "WebPopupMenuImpl.h"
143 #include "WebRange.h"
144 #include "WebRuntimeFeatures.h"
145 #include "WebSettingsImpl.h"
146 #include "WebTextInputInfo.h"
147 #include "WebTouchCandidatesInfo.h"
148 #include "WebViewClient.h"
149 #include "WheelEvent.h"
150 #include "painting/GraphicsContextBuilder.h"
151 #include <public/Platform.h>
152 #include <public/WebCompositor.h>
153 #include <public/WebCompositorOutputSurface.h>
154 #include <public/WebDragData.h>
155 #include <public/WebFloatPoint.h>
156 #include <public/WebGraphicsContext3D.h>
157 #include <public/WebImage.h>
158 #include <public/WebLayer.h>
159 #include <public/WebLayerTreeView.h>
160 #include <public/WebPoint.h>
161 #include <public/WebRect.h>
162 #include <public/WebString.h>
163 #include <public/WebVector.h>
164 #include <wtf/CurrentTime.h>
165 #include <wtf/MainThread.h>
166 #include <wtf/RefPtr.h>
167 #include <wtf/TemporaryChange.h>
168 #include <wtf/Uint8ClampedArray.h>
170 #if ENABLE(GESTURE_EVENTS)
171 #include "PlatformGestureEvent.h"
175 #include "RenderThemeChromiumWin.h"
177 #if OS(UNIX) && !OS(DARWIN)
178 #include "RenderThemeChromiumLinux.h"
180 #include "RenderTheme.h"
183 // Get rid of WTF's pow define so we can use std::pow.
185 #include <cmath> // for std::pow
187 using namespace WebCore;
190 // The following constants control parameters for automated scaling of webpages
191 // (such as due to a double tap gesture or find in page etc.). These are
192 // experimentally determined.
193 static const int touchPointPadding = 32;
194 static const float minScaleDifference = 0.01f;
195 static const float doubleTapZoomContentDefaultMargin = 5;
196 static const float doubleTapZoomContentMinimumMargin = 2;
197 static const double doubleTapZoomAnimationDurationInSeconds = 0.25;
199 // Constants for zooming in on a focused text field.
200 static const double scrollAndScaleAnimationDurationInSeconds = 0.2;
204 // Change the text zoom level by kTextSizeMultiplierRatio each time the user
205 // zooms text in or out (ie., change by 20%). The min and max values limit
206 // text zoom to half and 3x the original text size. These three values match
207 // those in Apple's port in WebKit/WebKit/WebView/WebView.mm
208 const double WebView::textSizeMultiplierRatio = 1.2;
209 const double WebView::minTextSizeMultiplier = 0.5;
210 const double WebView::maxTextSizeMultiplier = 3.0;
211 const float WebView::minPageScaleFactor = 0.25;
212 const float WebView::maxPageScaleFactor = 4.0;
215 // The group name identifies a namespace of pages. Page group is used on PLATFORM(MAC)
216 // for some programs that use HTML views to display things that don't seem like
217 // web pages to the user (so shouldn't have visited link coloring). We only use
219 const char* pageGroupName = "default";
221 // Used to defer all page activity in cases where the embedder wishes to run
222 // a nested event loop. Using a stack enables nesting of message loop invocations.
223 static Vector<PageGroupLoadDeferrer*>& pageGroupLoadDeferrerStack()
225 DEFINE_STATIC_LOCAL(Vector<PageGroupLoadDeferrer*>, deferrerStack, ());
226 return deferrerStack;
229 // Ensure that the WebDragOperation enum values stay in sync with the original
230 // DragOperation constants.
231 #define COMPILE_ASSERT_MATCHING_ENUM(coreName) \
232 COMPILE_ASSERT(int(coreName) == int(Web##coreName), dummy##coreName)
233 COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone);
234 COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy);
235 COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink);
236 COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric);
237 COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate);
238 COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove);
239 COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete);
240 COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery);
242 static const PopupContainerSettings autofillPopupSettings = {
243 false, // setTextOnIndexChange
244 false, // acceptOnAbandon
245 true, // loopSelectionNavigation
246 false // restrictWidthOfListBox (For security reasons show the entire entry
247 // so the user doesn't enter information he did not intend to.)
250 static bool shouldUseExternalPopupMenus = false;
252 static int webInputEventKeyStateToPlatformEventKeyState(int webInputEventKeyState)
254 int platformEventKeyState = 0;
255 if (webInputEventKeyState & WebInputEvent::ShiftKey)
256 platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::ShiftKey;
257 if (webInputEventKeyState & WebInputEvent::ControlKey)
258 platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::CtrlKey;
259 if (webInputEventKeyState & WebInputEvent::AltKey)
260 platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::AltKey;
261 if (webInputEventKeyState & WebInputEvent::MetaKey)
262 platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::MetaKey;
263 return platformEventKeyState;
266 // WebView ----------------------------------------------------------------
268 WebView* WebView::create(WebViewClient* client)
270 // Pass the WebViewImpl's self-reference to the caller.
271 return adoptRef(new WebViewImpl(client)).leakRef();
274 void WebView::setUseExternalPopupMenus(bool useExternalPopupMenus)
276 shouldUseExternalPopupMenus = useExternalPopupMenus;
279 void WebView::updateVisitedLinkState(unsigned long long linkHash)
281 Page::visitedStateChanged(PageGroup::pageGroup(pageGroupName), linkHash);
284 void WebView::resetVisitedLinkState()
286 Page::allVisitedStateChanged(PageGroup::pageGroup(pageGroupName));
289 void WebView::willEnterModalLoop()
291 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
294 if (pageGroup->pages().isEmpty())
295 pageGroupLoadDeferrerStack().append(static_cast<PageGroupLoadDeferrer*>(0));
297 // Pick any page in the page group since we are deferring all pages.
298 pageGroupLoadDeferrerStack().append(new PageGroupLoadDeferrer(*pageGroup->pages().begin(), true));
302 void WebView::didExitModalLoop()
304 ASSERT(pageGroupLoadDeferrerStack().size());
306 delete pageGroupLoadDeferrerStack().last();
307 pageGroupLoadDeferrerStack().removeLast();
310 void WebViewImpl::initializeMainFrame(WebFrameClient* frameClient)
312 // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame
313 // and releases that reference once the corresponding Frame is destroyed.
314 RefPtr<WebFrameImpl> frame = WebFrameImpl::create(frameClient);
316 frame->initializeAsMainFrame(page());
318 // Restrict the access to the local file system
319 // (see WebView.mm WebView::_commonInitializationWithFrameName).
320 SecurityPolicy::setLocalLoadPolicy(SecurityPolicy::AllowLocalLoadsForLocalOnly);
323 void WebViewImpl::initializeHelperPluginFrame(WebFrameClient* client)
325 RefPtr<WebFrameImpl> frame = WebFrameImpl::create(client);
328 void WebViewImpl::setAutofillClient(WebAutofillClient* autofillClient)
330 m_autofillClient = autofillClient;
333 void WebViewImpl::setDevToolsAgentClient(WebDevToolsAgentClient* devToolsClient)
336 m_devToolsAgent = adoptPtr(new WebDevToolsAgentImpl(this, devToolsClient));
338 m_devToolsAgent.clear();
341 void WebViewImpl::setPermissionClient(WebPermissionClient* permissionClient)
343 m_permissionClient = permissionClient;
344 m_featureSwitchClient->setPermissionClient(permissionClient);
347 void WebViewImpl::setPrerendererClient(WebPrerendererClient* prerendererClient)
349 providePrerendererClientTo(m_page.get(), new PrerendererClientImpl(prerendererClient));
352 void WebViewImpl::setSpellCheckClient(WebSpellCheckClient* spellCheckClient)
354 m_spellCheckClient = spellCheckClient;
357 void WebViewImpl::addTextFieldDecoratorClient(WebTextFieldDecoratorClient* client)
360 // We limit the number of decorators because it affects performance of text
361 // field creation. If you'd like to add more decorators, consider moving
362 // your decorator or existing decorators to WebCore.
363 const unsigned maximumNumberOfDecorators = 8;
364 if (m_textFieldDecorators.size() >= maximumNumberOfDecorators)
366 m_textFieldDecorators.append(TextFieldDecoratorImpl::create(client));
369 WebViewImpl::WebViewImpl(WebViewClient* client)
371 , m_autofillClient(0)
372 , m_permissionClient(0)
373 , m_spellCheckClient(0)
374 , m_chromeClientImpl(this)
375 , m_contextMenuClientImpl(this)
376 , m_dragClientImpl(this)
377 , m_editorClientImpl(this)
378 , m_inspectorClientImpl(this)
379 , m_shouldAutoResize(false)
380 , m_observedNewNavigation(false)
382 , m_newNavigationLoader(0)
385 , m_minimumZoomLevel(zoomFactorToZoomLevel(minTextSizeMultiplier))
386 , m_maximumZoomLevel(zoomFactorToZoomLevel(maxTextSizeMultiplier))
387 , m_pageDefinedMinimumPageScaleFactor(-1)
388 , m_pageDefinedMaximumPageScaleFactor(-1)
389 , m_minimumPageScaleFactor(minPageScaleFactor)
390 , m_maximumPageScaleFactor(maxPageScaleFactor)
391 , m_ignoreViewportTagMaximumScale(false)
392 , m_pageScaleFactorIsSet(false)
393 , m_savedPageScaleFactor(0)
394 , m_contextMenuAllowed(false)
395 , m_doingDragAndDrop(false)
396 , m_ignoreInputEvents(false)
397 , m_suppressNextKeypressEvent(false)
398 , m_initialNavigationPolicy(WebNavigationPolicyIgnore)
399 , m_imeAcceptEvents(true)
400 , m_operationsAllowed(WebDragOperationNone)
401 , m_dragOperation(WebDragOperationNone)
402 , m_featureSwitchClient(adoptPtr(new ContextFeaturesClientImpl()))
403 , m_autofillPopupShowing(false)
405 , m_isTransparent(false)
406 , m_tabsToLinks(false)
407 , m_dragScrollTimer(adoptPtr(new DragScrollTimer))
408 , m_isCancelingFullScreen(false)
409 , m_benchmarkSupport(this)
410 #if USE(ACCELERATED_COMPOSITING)
412 , m_rootGraphicsLayer(0)
413 , m_isAcceleratedCompositingActive(false)
414 , m_compositorCreationFailed(false)
415 , m_recreatingGraphicsContext(false)
416 , m_compositorSurfaceReady(false)
417 , m_deviceScaleInCompositor(1)
419 #if ENABLE(INPUT_SPEECH)
420 , m_speechInputClient(SpeechInputClientImpl::create(client))
422 #if ENABLE(SCRIPTED_SPEECH)
423 , m_speechRecognitionClient(SpeechRecognitionClientProxy::create(client ? client->speechRecognizer() : 0))
425 , m_deviceOrientationClientProxy(adoptPtr(new DeviceOrientationClientProxy(client ? client->deviceOrientationClient() : 0)))
426 , m_geolocationClientProxy(adoptPtr(new GeolocationClientProxy(client ? client->geolocationClient() : 0)))
427 #if ENABLE(BATTERY_STATUS)
428 , m_batteryClient(adoptPtr(new BatteryClientImpl(client ? client->batteryStatusClient() : 0)))
430 , m_emulatedTextZoomFactor(1)
431 #if ENABLE(MEDIA_STREAM)
432 , m_userMediaClientImpl(this)
434 #if ENABLE(REGISTER_PROTOCOL_HANDLER)
435 , m_registerProtocolHandlerClient(RegisterProtocolHandlerClientImpl::create(this))
439 // WebKit/win/WebView.cpp does the same thing, except they call the
440 // KJS specific wrapper around this method. We need to have threading
441 // initialized because CollatorICU requires it.
442 WTF::initializeThreading();
443 WTF::initializeMainThread();
445 Page::PageClients pageClients;
446 pageClients.chromeClient = &m_chromeClientImpl;
447 pageClients.contextMenuClient = &m_contextMenuClientImpl;
448 pageClients.editorClient = &m_editorClientImpl;
449 pageClients.dragClient = &m_dragClientImpl;
450 pageClients.inspectorClient = &m_inspectorClientImpl;
451 pageClients.backForwardClient = BackForwardListChromium::create(this);
453 m_page = adoptPtr(new Page(pageClients));
454 #if ENABLE(MEDIA_STREAM)
455 provideUserMediaTo(m_page.get(), &m_userMediaClientImpl);
457 #if ENABLE(INPUT_SPEECH)
458 provideSpeechInputTo(m_page.get(), m_speechInputClient.get());
460 #if ENABLE(SCRIPTED_SPEECH)
461 provideSpeechRecognitionTo(m_page.get(), m_speechRecognitionClient.get());
463 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
464 provideNotification(m_page.get(), notificationPresenterImpl());
466 #if ENABLE(REGISTER_PROTOCOL_HANDLER)
467 provideRegisterProtocolHandlerTo(m_page.get(), m_registerProtocolHandlerClient.get());
470 provideContextFeaturesTo(m_page.get(), m_featureSwitchClient.get());
471 provideDeviceOrientationTo(m_page.get(), m_deviceOrientationClientProxy.get());
472 provideGeolocationTo(m_page.get(), m_geolocationClientProxy.get());
473 m_geolocationClientProxy->setController(GeolocationController::from(m_page.get()));
475 #if ENABLE(BATTERY_STATUS)
476 provideBatteryTo(m_page.get(), m_batteryClient.get());
477 m_batteryClient->setController(BatteryController::from(m_page.get()));
480 m_page->setGroupName(pageGroupName);
482 #if ENABLE(PAGE_VISIBILITY_API)
484 setVisibilityState(m_client->visibilityState(), true);
487 m_inspectorSettingsMap = adoptPtr(new SettingsMap);
490 WebViewImpl::~WebViewImpl()
495 RenderTheme* WebViewImpl::theme() const
497 return m_page ? m_page->theme() : RenderTheme::defaultTheme().get();
500 WebFrameImpl* WebViewImpl::mainFrameImpl()
502 return m_page ? WebFrameImpl::fromFrame(m_page->mainFrame()) : 0;
505 bool WebViewImpl::tabKeyCyclesThroughElements() const
508 return m_page->tabKeyCyclesThroughElements();
511 void WebViewImpl::setTabKeyCyclesThroughElements(bool value)
514 m_page->setTabKeyCyclesThroughElements(value);
517 void WebViewImpl::handleMouseLeave(Frame& mainFrame, const WebMouseEvent& event)
519 m_client->setMouseOverURL(WebURL());
520 PageWidgetEventHandler::handleMouseLeave(mainFrame, event);
523 void WebViewImpl::handleMouseDown(Frame& mainFrame, const WebMouseEvent& event)
525 // If there is a popup open, close it as the user is clicking on the page (outside of the
526 // popup). We also save it so we can prevent a click on an element from immediately
527 // reopening the same popup.
528 RefPtr<WebCore::PopupContainer> selectPopup;
529 #if ENABLE(PAGE_POPUP)
530 RefPtr<WebPagePopupImpl> pagePopup;
532 if (event.button == WebMouseEvent::ButtonLeft) {
533 selectPopup = m_selectPopup;
534 #if ENABLE(PAGE_POPUP)
535 pagePopup = m_pagePopup;
538 ASSERT(!m_selectPopup);
539 #if ENABLE(PAGE_POPUP)
540 ASSERT(!m_pagePopup);
544 m_lastMouseDownPoint = WebPoint(event.x, event.y);
546 if (event.button == WebMouseEvent::ButtonLeft) {
547 IntPoint point(event.x, event.y);
548 point = m_page->mainFrame()->view()->windowToContents(point);
549 HitTestResult result(m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, false));
550 Node* hitNode = result.innerNonSharedNode();
552 // Take capture on a mouse down on a plugin so we can send it mouse events.
553 if (hitNode && hitNode->renderer() && hitNode->renderer()->isEmbeddedObject())
554 m_mouseCaptureNode = hitNode;
557 PageWidgetEventHandler::handleMouseDown(mainFrame, event);
559 if (m_selectPopup && m_selectPopup == selectPopup) {
560 // That click triggered a select popup which is the same as the one that
561 // was showing before the click. It means the user clicked the select
562 // while the popup was showing, and as a result we first closed then
563 // immediately reopened the select popup. It needs to be closed.
567 #if ENABLE(PAGE_POPUP)
568 if (m_pagePopup && pagePopup && m_pagePopup->hasSamePopupClient(pagePopup.get())) {
569 // That click triggered a page popup that is the same as the one we just closed.
570 // It needs to be closed.
571 closePagePopup(m_pagePopup.get());
575 // Dispatch the contextmenu event regardless of if the click was swallowed.
576 // On Windows, we handle it on mouse up, not down.
578 if (event.button == WebMouseEvent::ButtonRight
579 || (event.button == WebMouseEvent::ButtonLeft
580 && event.modifiers & WebMouseEvent::ControlKey))
581 mouseContextMenu(event);
582 #elif OS(UNIX) || OS(ANDROID)
583 if (event.button == WebMouseEvent::ButtonRight)
584 mouseContextMenu(event);
588 void WebViewImpl::mouseContextMenu(const WebMouseEvent& event)
590 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
593 m_page->contextMenuController()->clearContextMenu();
595 PlatformMouseEventBuilder pme(mainFrameImpl()->frameView(), event);
597 // Find the right target frame. See issue 1186900.
598 HitTestResult result = hitTestResultForWindowPos(pme.position());
600 if (result.innerNonSharedNode())
601 targetFrame = result.innerNonSharedNode()->document()->frame();
603 targetFrame = m_page->focusController()->focusedOrMainFrame();
606 targetFrame->view()->setCursor(pointerCursor());
609 m_contextMenuAllowed = true;
610 targetFrame->eventHandler()->sendContextMenuEvent(pme);
611 m_contextMenuAllowed = false;
612 // Actually showing the context menu is handled by the ContextMenuClient
616 void WebViewImpl::handleMouseUp(Frame& mainFrame, const WebMouseEvent& event)
618 #if OS(UNIX) && !OS(DARWIN)
619 // If the event was a middle click, attempt to copy text into the focused
620 // frame. We execute this before we let the page have a go at the event
621 // because the page may change what is focused during in its event handler.
623 // This code is in the mouse up handler. There is some debate about putting
624 // this here, as opposed to the mouse down handler.
625 // xterm: pastes on up.
626 // GTK: pastes on down.
627 // Firefox: pastes on up.
628 // Midori: couldn't paste at all with 0.1.2
630 // There is something of a webcompat angle to this well, as highlighted by
631 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
632 // down then the text is pasted just before the onclick handler runs and
633 // clears the text box. So it's important this happens after the
634 // handleMouseReleaseEvent() earlier in this function
635 if (event.button == WebMouseEvent::ButtonMiddle) {
636 Frame* focused = focusedWebCoreFrame();
637 FrameView* view = m_page->mainFrame()->view();
638 IntPoint clickPoint(m_lastMouseDownPoint.x, m_lastMouseDownPoint.y);
639 IntPoint contentPoint = view->windowToContents(clickPoint);
640 HitTestResult hitTestResult = focused->eventHandler()->hitTestResultAtPoint(contentPoint, false, false, ShouldHitTestScrollbars);
641 // We don't want to send a paste when middle clicking a scroll bar or a
642 // link (which will navigate later in the code). The main scrollbars
643 // have to be handled separately.
644 if (!hitTestResult.scrollbar() && !hitTestResult.isLiveLink() && focused && !view->scrollbarAtPoint(clickPoint)) {
645 Editor* editor = focused->editor();
646 Pasteboard* pasteboard = Pasteboard::generalPasteboard();
647 bool oldSelectionMode = pasteboard->isSelectionMode();
648 pasteboard->setSelectionMode(true);
649 editor->command(AtomicString("Paste")).execute();
650 pasteboard->setSelectionMode(oldSelectionMode);
655 PageWidgetEventHandler::handleMouseUp(mainFrame, event);
658 // Dispatch the contextmenu event regardless of if the click was swallowed.
659 // On Mac/Linux, we handle it on mouse down, not up.
660 if (event.button == WebMouseEvent::ButtonRight)
661 mouseContextMenu(event);
665 void WebViewImpl::scrollBy(const WebCore::IntPoint& delta)
667 WebMouseWheelEvent syntheticWheel;
668 const float tickDivisor = WebCore::WheelEvent::tickMultiplier;
670 syntheticWheel.deltaX = delta.x();
671 syntheticWheel.deltaY = delta.y();
672 syntheticWheel.wheelTicksX = delta.x() / tickDivisor;
673 syntheticWheel.wheelTicksY = delta.y() / tickDivisor;
674 syntheticWheel.hasPreciseScrollingDeltas = true;
675 syntheticWheel.x = m_lastWheelPosition.x;
676 syntheticWheel.y = m_lastWheelPosition.y;
677 syntheticWheel.globalX = m_lastWheelGlobalPosition.x;
678 syntheticWheel.globalY = m_lastWheelGlobalPosition.y;
679 syntheticWheel.modifiers = m_flingModifier;
681 if (m_page && m_page->mainFrame() && m_page->mainFrame()->view())
682 handleMouseWheel(*m_page->mainFrame(), syntheticWheel);
685 #if ENABLE(GESTURE_EVENTS)
686 bool WebViewImpl::handleGestureEvent(const WebGestureEvent& event)
688 switch (event.type) {
689 case WebInputEvent::GestureFlingStart: {
690 m_lastWheelPosition = WebPoint(event.x, event.y);
691 m_lastWheelGlobalPosition = WebPoint(event.globalX, event.globalY);
692 m_flingModifier = event.modifiers;
693 // FIXME: Make the curve parametrizable from the browser.
694 m_gestureAnimation = ActivePlatformGestureAnimation::create(TouchpadFlingPlatformGestureCurve::create(FloatPoint(event.deltaX, event.deltaY)), this);
698 case WebInputEvent::GestureFlingCancel:
699 if (m_gestureAnimation) {
700 m_gestureAnimation.clear();
704 case WebInputEvent::GestureTap: {
705 PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
706 RefPtr<WebCore::PopupContainer> selectPopup;
707 selectPopup = m_selectPopup;
709 ASSERT(!m_selectPopup);
710 bool gestureHandled = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
711 if (m_selectPopup && m_selectPopup == selectPopup) {
712 // That tap triggered a select popup which is the same as the one that
713 // was showing before the tap. It means the user tapped the select
714 // while the popup was showing, and as a result we first closed then
715 // immediately reopened the select popup. It needs to be closed.
718 return gestureHandled;
720 case WebInputEvent::GestureTwoFingerTap:
721 case WebInputEvent::GestureLongPress: {
722 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
725 m_page->contextMenuController()->clearContextMenu();
726 m_contextMenuAllowed = true;
727 PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
728 bool handled = mainFrameImpl()->frame()->eventHandler()->sendContextMenuEventForGesture(platformEvent);
729 m_contextMenuAllowed = false;
732 case WebInputEvent::GestureScrollBegin:
733 case WebInputEvent::GestureScrollEnd:
734 case WebInputEvent::GestureScrollUpdate:
735 case WebInputEvent::GestureTapDown:
736 case WebInputEvent::GestureDoubleTap:
737 case WebInputEvent::GesturePinchBegin:
738 case WebInputEvent::GesturePinchEnd:
739 case WebInputEvent::GesturePinchUpdate: {
740 PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
741 return mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
744 ASSERT_NOT_REACHED();
749 void WebViewImpl::transferActiveWheelFlingAnimation(const WebActiveWheelFlingParameters& parameters)
751 TRACE_EVENT0("webkit", "WebViewImpl::transferActiveWheelFlingAnimation");
752 ASSERT(!m_gestureAnimation);
753 m_lastWheelPosition = parameters.point;
754 m_lastWheelGlobalPosition = parameters.globalPoint;
755 m_flingModifier = parameters.modifiers;
756 OwnPtr<PlatformGestureCurve> curve = TouchpadFlingPlatformGestureCurve::create(parameters.delta, IntPoint(parameters.cumulativeScroll));
757 m_gestureAnimation = ActivePlatformGestureAnimation::create(curve.release(), this, parameters.startTime);
761 void WebViewImpl::renderingStats(WebRenderingStats& stats) const
763 if (!m_layerTreeView.isNull())
764 m_layerTreeView.renderingStats(stats);
767 void WebViewImpl::startPageScaleAnimation(const IntPoint& targetPosition, bool useAnchor, float newScale, double durationInSeconds)
769 if (m_layerTreeView.isNull())
772 IntPoint clampedPoint = targetPosition;
774 clampedPoint = clampOffsetAtScale(targetPosition, newScale);
776 if (!durationInSeconds && !useAnchor) {
777 setPageScaleFactor(newScale, clampedPoint);
781 m_layerTreeView.startPageScaleAnimation(targetPosition, useAnchor, newScale, durationInSeconds);
785 WebViewBenchmarkSupport* WebViewImpl::benchmarkSupport()
787 return &m_benchmarkSupport;
790 WebVector<WebFloatQuad> WebViewImpl::getTouchHighlightQuads(const WebPoint& point,
792 WebTouchCandidatesInfo& outTouchInfo,
793 WebColor& outTapHighlightColor)
795 // FIXME: Upstream this function from the chromium-android branch.
798 return WebVector<WebFloatQuad>();
801 bool WebViewImpl::handleKeyEvent(const WebKeyboardEvent& event)
803 ASSERT((event.type == WebInputEvent::RawKeyDown)
804 || (event.type == WebInputEvent::KeyDown)
805 || (event.type == WebInputEvent::KeyUp));
807 // Halt an in-progress fling on a key event.
808 if (m_gestureAnimation)
809 m_gestureAnimation.clear();
811 // Please refer to the comments explaining the m_suppressNextKeypressEvent
813 // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
814 // Webkit. A keyDown event is typically associated with a keyPress(char)
815 // event and a keyUp event. We reset this flag here as this is a new keyDown
817 m_suppressNextKeypressEvent = false;
819 // If there is a select popup, it should be the one processing the event,
822 return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
823 #if ENABLE(PAGE_POPUP)
825 m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
826 // We need to ignore the next Char event after this otherwise pressing
827 // enter when selecting an item in the popup will go to the page.
828 if (WebInputEvent::RawKeyDown == event.type)
829 m_suppressNextKeypressEvent = true;
834 // Give Autocomplete a chance to consume the key events it is interested in.
835 if (autocompleteHandleKeyEvent(event))
838 RefPtr<Frame> frame = focusedWebCoreFrame();
842 EventHandler* handler = frame->eventHandler();
844 return keyEventDefault(event);
847 const WebInputEvent::Type contextMenuTriggeringEventType =
849 WebInputEvent::KeyUp;
851 WebInputEvent::RawKeyDown;
854 bool isUnmodifiedMenuKey = !(event.modifiers & WebInputEvent::InputModifiers) && event.windowsKeyCode == VKEY_APPS;
855 bool isShiftF10 = event.modifiers == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10;
856 if ((isUnmodifiedMenuKey || isShiftF10) && event.type == contextMenuTriggeringEventType) {
857 sendContextMenuEvent(event);
860 #endif // !OS(DARWIN)
862 PlatformKeyboardEventBuilder evt(event);
864 if (handler->keyEvent(evt)) {
865 if (WebInputEvent::RawKeyDown == event.type) {
866 // Suppress the next keypress event unless the focused node is a plug-in node.
867 // (Flash needs these keypress events to handle non-US keyboards.)
868 Node* node = focusedWebCoreNode();
869 if (!node || !node->renderer() || !node->renderer()->isEmbeddedObject())
870 m_suppressNextKeypressEvent = true;
875 return keyEventDefault(event);
878 bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event)
880 if (!m_autofillPopupShowing
881 // Home and End should be left to the text field to process.
882 || event.windowsKeyCode == VKEY_HOME
883 || event.windowsKeyCode == VKEY_END)
886 // Pressing delete triggers the removal of the selected suggestion from the DB.
887 if (event.windowsKeyCode == VKEY_DELETE
888 && m_autofillPopup->selectedIndex() != -1) {
889 Node* node = focusedWebCoreNode();
890 if (!node || (node->nodeType() != Node::ELEMENT_NODE)) {
891 ASSERT_NOT_REACHED();
894 Element* element = static_cast<Element*>(node);
895 if (!element->hasLocalName(HTMLNames::inputTag)) {
896 ASSERT_NOT_REACHED();
900 int selectedIndex = m_autofillPopup->selectedIndex();
902 if (!m_autofillPopupClient->canRemoveSuggestionAtIndex(selectedIndex))
905 WebString name = WebInputElement(static_cast<HTMLInputElement*>(element)).nameForAutofill();
906 WebString value = m_autofillPopupClient->itemText(selectedIndex);
907 m_autofillClient->removeAutocompleteSuggestion(name, value);
908 // Update the entries in the currently showing popup to reflect the
910 m_autofillPopupClient->removeSuggestionAtIndex(selectedIndex);
911 refreshAutofillPopup();
915 if (!m_autofillPopup->isInterestedInEventForKey(event.windowsKeyCode))
918 if (m_autofillPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) {
919 // We need to ignore the next Char event after this otherwise pressing
920 // enter when selecting an item in the menu will go to the page.
921 if (WebInputEvent::RawKeyDown == event.type)
922 m_suppressNextKeypressEvent = true;
929 bool WebViewImpl::handleCharEvent(const WebKeyboardEvent& event)
931 ASSERT(event.type == WebInputEvent::Char);
933 // Please refer to the comments explaining the m_suppressNextKeypressEvent
934 // member. The m_suppressNextKeypressEvent is set if the KeyDown is
935 // handled by Webkit. A keyDown event is typically associated with a
936 // keyPress(char) event and a keyUp event. We reset this flag here as it
937 // only applies to the current keyPress event.
938 bool suppress = m_suppressNextKeypressEvent;
939 m_suppressNextKeypressEvent = false;
941 // If there is a select popup, it should be the one processing the event,
944 return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
945 #if ENABLE(PAGE_POPUP)
947 return m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
950 Frame* frame = focusedWebCoreFrame();
954 EventHandler* handler = frame->eventHandler();
956 return suppress || keyEventDefault(event);
958 PlatformKeyboardEventBuilder evt(event);
959 if (!evt.isCharacterKey())
962 // Accesskeys are triggered by char events and can't be suppressed.
963 if (handler->handleAccessKey(evt))
966 // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
967 // the eventHandler::keyEvent. We mimic this behavior on all platforms since
968 // for now we are converting other platform's key events to windows key
970 if (evt.isSystemKey())
973 if (!suppress && !handler->keyEvent(evt))
974 return keyEventDefault(event);
979 #if ENABLE(GESTURE_EVENTS)
980 WebRect WebViewImpl::computeBlockBounds(const WebRect& rect, AutoZoomType zoomType)
982 if (!mainFrameImpl())
985 // Use the rect-based hit test to find the node.
986 IntPoint point = mainFrameImpl()->frameView()->windowToContents(IntPoint(rect.x, rect.y));
987 HitTestResult result = mainFrameImpl()->frame()->eventHandler()->hitTestResultAtPoint(point,
988 false, zoomType == FindInPage, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly,
989 IntSize(rect.width, rect.height));
991 Node* node = result.innerNonSharedNode();
995 // Find the block type node based on the hit node.
996 while (node && (!node->renderer() || node->renderer()->isInline()))
997 node = node->parentNode();
999 // Return the bounding box in the window coordinate system.
1001 IntRect rect = node->Node::getPixelSnappedRect();
1002 Frame* frame = node->document()->frame();
1003 return frame->view()->contentsToWindow(rect);
1008 WebRect WebViewImpl::widenRectWithinPageBounds(const WebRect& source, int targetMargin, int minimumMargin)
1012 maxSize = mainFrame()->contentsSize();
1013 IntSize scrollOffset;
1015 scrollOffset = mainFrame()->scrollOffset();
1016 int leftMargin = targetMargin;
1017 int rightMargin = targetMargin;
1019 const int absoluteSourceX = source.x + scrollOffset.width();
1020 if (leftMargin > absoluteSourceX) {
1021 leftMargin = absoluteSourceX;
1022 rightMargin = max(leftMargin, minimumMargin);
1025 const int maximumRightMargin = maxSize.width - (source.width + absoluteSourceX);
1026 if (rightMargin > maximumRightMargin) {
1027 rightMargin = maximumRightMargin;
1028 leftMargin = min(leftMargin, max(rightMargin, minimumMargin));
1031 const int newWidth = source.width + leftMargin + rightMargin;
1032 const int newX = source.x - leftMargin;
1034 ASSERT(newWidth >= 0);
1035 ASSERT(scrollOffset.width() + newX + newWidth <= maxSize.width);
1037 return WebRect(newX, source.y, newWidth, source.height);
1040 void WebViewImpl::computeScaleAndScrollForHitRect(const WebRect& hitRect, AutoZoomType zoomType, float& scale, WebPoint& scroll)
1042 scale = pageScaleFactor();
1043 scroll.x = scroll.y = 0;
1044 WebRect targetRect = hitRect;
1045 if (targetRect.isEmpty())
1046 targetRect.width = targetRect.height = touchPointPadding;
1048 WebRect rect = computeBlockBounds(targetRect, zoomType);
1050 const float overviewScale = m_minimumPageScaleFactor;
1051 bool scaleUnchanged = true;
1052 if (!rect.isEmpty()) {
1053 // Pages should be as legible as on desktop when at dpi scale, so no
1054 // need to zoom in further when automatically determining zoom level
1055 // (after double tap, find in page, etc), though the user should still
1056 // be allowed to manually pinch zoom in further if they desire.
1057 const float maxScale = deviceScaleFactor();
1059 const float defaultMargin = doubleTapZoomContentDefaultMargin * deviceScaleFactor();
1060 const float minimumMargin = doubleTapZoomContentMinimumMargin * deviceScaleFactor();
1061 // We want the margins to have the same physical size, which means we
1062 // need to express them in post-scale size. To do that we'd need to know
1063 // the scale we're scaling to, but that depends on the margins. Instead
1064 // we express them as a fraction of the target rectangle: this will be
1065 // correct if we end up fully zooming to it, and won't matter if we
1067 rect = widenRectWithinPageBounds(rect,
1068 static_cast<int>(defaultMargin * rect.width / m_size.width),
1069 static_cast<int>(minimumMargin * rect.width / m_size.width));
1071 // Fit block to screen, respecting limits.
1072 scale *= static_cast<float>(m_size.width) / rect.width;
1073 scale = min(scale, maxScale);
1074 scale = clampPageScaleFactorToLimits(scale);
1076 scaleUnchanged = fabs(pageScaleFactor() - scale) < minScaleDifference;
1079 if (zoomType == DoubleTap) {
1080 if (rect.isEmpty() || scaleUnchanged) {
1081 // Zoom out to overview mode.
1083 scale = overviewScale;
1086 } else if (rect.isEmpty()) {
1087 // Keep current scale (no need to scroll as x,y will normally already
1088 // be visible). FIXME: Revisit this if it isn't always true.
1092 // FIXME: If this is being called for auto zoom during find in page,
1093 // then if the user manually zooms in it'd be nice to preserve the relative
1094 // increase in zoom they caused (if they zoom out then it's ok to zoom
1095 // them back in again). This isn't compatible with our current double-tap
1096 // zoom strategy (fitting the containing block to the screen) though.
1098 float screenHeight = m_size.height / scale * pageScaleFactor();
1099 float screenWidth = m_size.width / scale * pageScaleFactor();
1101 // Scroll to vertically align the block.
1102 if (rect.height < screenHeight) {
1103 // Vertically center short blocks.
1104 rect.y -= 0.5 * (screenHeight - rect.height);
1106 // Ensure position we're zooming to (+ padding) isn't off the bottom of
1108 rect.y = max<float>(rect.y, hitRect.y + touchPointPadding - screenHeight);
1109 } // Otherwise top align the block.
1111 // Do the same thing for horizontal alignment.
1112 if (rect.width < screenWidth)
1113 rect.x -= 0.5 * (screenWidth - rect.width);
1115 rect.x = max<float>(rect.x, hitRect.x + touchPointPadding - screenWidth);
1122 void WebViewImpl::animateZoomAroundPoint(const IntPoint& point, AutoZoomType zoomType)
1124 #if ENABLE(GESTURE_EVENTS)
1125 if (!mainFrameImpl())
1130 computeScaleAndScrollForHitRect(WebRect(point.x(), point.y(), 0, 0), zoomType, scale, scroll);
1132 bool isDoubleTap = (zoomType == DoubleTap);
1133 double durationInSeconds = isDoubleTap ? doubleTapZoomAnimationDurationInSeconds : 0;
1134 startPageScaleAnimation(scroll, isDoubleTap, scale, durationInSeconds);
1138 void WebViewImpl::zoomToFindInPageRect(const WebRect& rect)
1140 animateZoomAroundPoint(IntRect(rect).center(), FindInPage);
1143 void WebViewImpl::numberOfWheelEventHandlersChanged(unsigned numberOfWheelHandlers)
1146 m_client->numberOfWheelEventHandlersChanged(numberOfWheelHandlers);
1149 void WebViewImpl::hasTouchEventHandlers(bool hasTouchHandlers)
1152 m_client->hasTouchEventHandlers(hasTouchHandlers);
1156 // Mac has no way to open a context menu based on a keyboard event.
1157 bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event)
1159 // The contextMenuController() holds onto the last context menu that was
1160 // popped up on the page until a new one is created. We need to clear
1161 // this menu before propagating the event through the DOM so that we can
1162 // detect if we create a new menu for this event, since we won't create
1163 // a new menu if the DOM swallows the event and the defaultEventHandler does
1165 page()->contextMenuController()->clearContextMenu();
1167 m_contextMenuAllowed = true;
1168 Frame* focusedFrame = page()->focusController()->focusedOrMainFrame();
1169 bool handled = focusedFrame->eventHandler()->sendContextMenuEventForKey();
1170 m_contextMenuAllowed = false;
1175 bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event)
1177 Frame* frame = focusedWebCoreFrame();
1181 switch (event.type) {
1182 case WebInputEvent::Char:
1183 if (event.windowsKeyCode == VKEY_SPACE) {
1184 int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT);
1185 return scrollViewWithKeyboard(keyCode, event.modifiers);
1188 case WebInputEvent::RawKeyDown:
1189 if (event.modifiers == WebInputEvent::ControlKey) {
1190 switch (event.windowsKeyCode) {
1193 focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll"));
1197 focusedFrame()->executeCommand(WebString::fromUTF8("Copy"));
1200 // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
1201 // key combinations which affect scrolling. Safari is buggy in the
1202 // sense that it scrolls the page for all Ctrl+scrolling key
1203 // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
1211 if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey))
1212 return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers);
1220 bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers)
1222 ScrollDirection scrollDirection;
1223 ScrollGranularity scrollGranularity;
1225 // Control-Up/Down should be PageUp/Down on Mac.
1226 if (modifiers & WebMouseEvent::ControlKey) {
1227 if (keyCode == VKEY_UP)
1228 keyCode = VKEY_PRIOR;
1229 else if (keyCode == VKEY_DOWN)
1230 keyCode = VKEY_NEXT;
1233 if (!mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity))
1235 return propagateScroll(scrollDirection, scrollGranularity);
1238 bool WebViewImpl::mapKeyCodeForScroll(int keyCode,
1239 WebCore::ScrollDirection* scrollDirection,
1240 WebCore::ScrollGranularity* scrollGranularity)
1244 *scrollDirection = ScrollLeft;
1245 *scrollGranularity = ScrollByLine;
1248 *scrollDirection = ScrollRight;
1249 *scrollGranularity = ScrollByLine;
1252 *scrollDirection = ScrollUp;
1253 *scrollGranularity = ScrollByLine;
1256 *scrollDirection = ScrollDown;
1257 *scrollGranularity = ScrollByLine;
1260 *scrollDirection = ScrollUp;
1261 *scrollGranularity = ScrollByDocument;
1264 *scrollDirection = ScrollDown;
1265 *scrollGranularity = ScrollByDocument;
1267 case VKEY_PRIOR: // page up
1268 *scrollDirection = ScrollUp;
1269 *scrollGranularity = ScrollByPage;
1271 case VKEY_NEXT: // page down
1272 *scrollDirection = ScrollDown;
1273 *scrollGranularity = ScrollByPage;
1282 void WebViewImpl::hideSelectPopup()
1285 m_selectPopup->hidePopup();
1288 bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection,
1289 ScrollGranularity scrollGranularity)
1291 Frame* frame = focusedWebCoreFrame();
1295 bool scrollHandled = frame->eventHandler()->scrollOverflow(scrollDirection, scrollGranularity);
1296 Frame* currentFrame = frame;
1297 while (!scrollHandled && currentFrame) {
1298 scrollHandled = currentFrame->view()->scroll(scrollDirection, scrollGranularity);
1299 currentFrame = currentFrame->tree()->parent();
1301 return scrollHandled;
1304 void WebViewImpl::popupOpened(WebCore::PopupContainer* popupContainer)
1306 if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
1307 ASSERT(!m_selectPopup);
1308 m_selectPopup = popupContainer;
1312 void WebViewImpl::popupClosed(WebCore::PopupContainer* popupContainer)
1314 if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
1315 ASSERT(m_selectPopup);
1320 #if ENABLE(PAGE_POPUP)
1321 PagePopup* WebViewImpl::openPagePopup(PagePopupClient* client, const IntRect& originBoundsInRootView)
1324 if (hasOpenedPopup())
1326 ASSERT(!m_pagePopup);
1328 WebWidget* popupWidget = m_client->createPopupMenu(WebPopupTypePage);
1329 ASSERT(popupWidget);
1330 m_pagePopup = static_cast<WebPagePopupImpl*>(popupWidget);
1331 if (!m_pagePopup->init(this, client, originBoundsInRootView)) {
1332 m_pagePopup->closePopup();
1336 if (Frame* frame = focusedWebCoreFrame())
1337 frame->selection()->setCaretVisible(false);
1338 return m_pagePopup.get();
1341 void WebViewImpl::closePagePopup(PagePopup* popup)
1344 WebPagePopupImpl* popupImpl = static_cast<WebPagePopupImpl*>(popup);
1345 ASSERT(m_pagePopup.get() == popupImpl);
1346 if (m_pagePopup.get() != popupImpl)
1348 m_pagePopup->closePopup();
1351 if (Frame* frame = focusedWebCoreFrame())
1352 frame->selection()->pageActivationChanged();
1356 void WebViewImpl::hideAutofillPopup()
1358 if (m_autofillPopupShowing) {
1359 m_autofillPopup->hidePopup();
1360 m_autofillPopupShowing = false;
1364 WebHelperPluginImpl* WebViewImpl::createHelperPlugin(const String& pluginType)
1366 WebWidget* popupWidget = m_client->createPopupMenu(WebPopupTypeHelperPlugin);
1367 ASSERT(popupWidget);
1368 WebHelperPluginImpl* helperPlugin = static_cast<WebHelperPluginImpl*>(popupWidget);
1370 if (!helperPlugin->init(this, pluginType)) {
1371 helperPlugin->closeHelperPlugin();
1374 return helperPlugin;
1377 Frame* WebViewImpl::focusedWebCoreFrame() const
1379 return m_page ? m_page->focusController()->focusedOrMainFrame() : 0;
1382 WebViewImpl* WebViewImpl::fromPage(Page* page)
1387 ChromeClientImpl* chromeClient = static_cast<ChromeClientImpl*>(page->chrome()->client());
1388 return static_cast<WebViewImpl*>(chromeClient->webView());
1391 PageGroup* WebViewImpl::defaultPageGroup()
1393 return PageGroup::pageGroup(pageGroupName);
1396 // WebWidget ------------------------------------------------------------------
1398 void WebViewImpl::close()
1400 RefPtr<WebFrameImpl> mainFrameImpl;
1403 // Initiate shutdown for the entire frameset. This will cause a lot of
1404 // notifications to be sent.
1405 if (m_page->mainFrame()) {
1406 mainFrameImpl = WebFrameImpl::fromFrame(m_page->mainFrame());
1407 m_page->mainFrame()->loader()->frameDetached();
1412 // Should happen after m_page.clear().
1413 if (m_devToolsAgent)
1414 m_devToolsAgent.clear();
1416 // Reset the delegate to prevent notifications being sent as we're being
1420 deref(); // Balances ref() acquired in WebView::create
1423 void WebViewImpl::willStartLiveResize()
1425 if (mainFrameImpl() && mainFrameImpl()->frameView())
1426 mainFrameImpl()->frameView()->willStartLiveResize();
1428 Frame* frame = mainFrameImpl()->frame();
1429 WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
1430 if (pluginContainer)
1431 pluginContainer->willStartLiveResize();
1434 void WebViewImpl::resize(const WebSize& newSize)
1436 if (m_shouldAutoResize || m_size == newSize)
1439 FrameView* view = mainFrameImpl()->frameView();
1443 WebSize oldSize = m_size;
1444 float oldPageScaleFactor = pageScaleFactor();
1445 IntSize oldScrollOffset = view->scrollOffset();
1446 int oldFixedLayoutWidth = fixedLayoutSize().width;
1450 #if ENABLE(VIEWPORT)
1451 if (settings()->viewportEnabled()) {
1452 // Fallback width is used to layout sites designed for desktop. The
1453 // conventional size used by all mobile browsers is 980. When a mobile
1454 // device has a particularly wide screen (such as a 10" tablet held in
1455 // landscape), it can be larger.
1456 const int standardFallbackWidth = 980;
1457 int dpiIndependentViewportWidth = newSize.width / page()->deviceScaleFactor();
1458 settings()->setLayoutFallbackWidth(std::max(standardFallbackWidth, dpiIndependentViewportWidth));
1460 ViewportArguments viewportArguments = mainFrameImpl()->frame()->document()->viewportArguments();
1461 m_page->chrome()->client()->dispatchViewportPropertiesDidChange(viewportArguments);
1465 WebDevToolsAgentPrivate* agentPrivate = devToolsAgentPrivate();
1466 if (agentPrivate && agentPrivate->metricsOverridden())
1467 agentPrivate->webViewResized();
1469 WebFrameImpl* webFrame = mainFrameImpl();
1470 if (webFrame->frameView())
1471 webFrame->frameView()->resize(newSize.width, newSize.height);
1474 #if ENABLE(VIEWPORT)
1475 if (settings()->viewportEnabled()) {
1476 // Relayout immediately to obtain the new content width, which is needed
1477 // to calculate the minimum scale limit.
1479 computePageScaleFactorLimits();
1480 // When the device rotates:
1481 // - If the page width is unchanged, then zoom by new width/old width
1482 // such as to keep the same content horizontally onscreen.
1483 // - If the page width stretches proportionally to the change in
1484 // screen width, then don't zoom at all (assuming the content has
1485 // scaled uniformly, then the same content will be horizontally
1487 // - If the page width partially stretches, then zoom partially to
1488 // make up the difference.
1489 // In all cases try to keep the same content at the top of the screen.
1490 float viewportWidthRatio = !oldSize.width ? 1 : newSize.width / (float) oldSize.width;
1491 float fixedLayoutWidthRatio = !oldFixedLayoutWidth ? 1 : fixedLayoutSize().width / (float) oldFixedLayoutWidth;
1492 float scaleMultiplier = viewportWidthRatio / fixedLayoutWidthRatio;
1493 if (scaleMultiplier != 1) {
1494 IntSize scrollOffsetAtNewScale = oldScrollOffset;
1495 scrollOffsetAtNewScale.scale(scaleMultiplier);
1496 setPageScaleFactor(oldPageScaleFactor * scaleMultiplier, IntPoint(scrollOffsetAtNewScale));
1501 sendResizeEventAndRepaint();
1504 void WebViewImpl::willEndLiveResize()
1506 if (mainFrameImpl() && mainFrameImpl()->frameView())
1507 mainFrameImpl()->frameView()->willEndLiveResize();
1509 Frame* frame = mainFrameImpl()->frame();
1510 WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
1511 if (pluginContainer)
1512 pluginContainer->willEndLiveResize();
1515 void WebViewImpl::willEnterFullScreen()
1517 #if ENABLE(FULLSCREEN_API)
1518 if (!m_provisionalFullScreenElement)
1521 // Ensure that this element's document is still attached.
1522 Document* doc = m_provisionalFullScreenElement->document();
1524 doc->webkitWillEnterFullScreenForElement(m_provisionalFullScreenElement.get());
1525 m_fullScreenFrame = doc->frame();
1527 m_provisionalFullScreenElement.clear();
1531 void WebViewImpl::didEnterFullScreen()
1533 #if ENABLE(FULLSCREEN_API)
1534 if (!m_fullScreenFrame)
1537 if (Document* doc = m_fullScreenFrame->document()) {
1538 if (doc->webkitIsFullScreen())
1539 doc->webkitDidEnterFullScreenForElement(0);
1544 void WebViewImpl::willExitFullScreen()
1546 #if ENABLE(FULLSCREEN_API)
1547 if (!m_fullScreenFrame)
1550 if (Document* doc = m_fullScreenFrame->document()) {
1551 if (doc->webkitIsFullScreen()) {
1552 // When the client exits from full screen we have to call webkitCancelFullScreen to
1553 // notify the document. While doing that, suppress notifications back to the client.
1554 m_isCancelingFullScreen = true;
1555 doc->webkitCancelFullScreen();
1556 m_isCancelingFullScreen = false;
1557 doc->webkitWillExitFullScreenForElement(0);
1563 void WebViewImpl::didExitFullScreen()
1565 #if ENABLE(FULLSCREEN_API)
1566 if (!m_fullScreenFrame)
1569 if (Document* doc = m_fullScreenFrame->document()) {
1570 if (doc->webkitIsFullScreen())
1571 doc->webkitDidExitFullScreenForElement(0);
1574 m_fullScreenFrame.clear();
1578 void WebViewImpl::instrumentBeginFrame()
1580 InspectorInstrumentation::didBeginFrame(m_page.get());
1583 void WebViewImpl::instrumentCancelFrame()
1585 InspectorInstrumentation::didCancelFrame(m_page.get());
1588 #if ENABLE(BATTERY_STATUS)
1589 void WebViewImpl::updateBatteryStatus(const WebBatteryStatus& status)
1591 m_batteryClient->updateBatteryStatus(status);
1595 void WebViewImpl::setCompositorSurfaceReady()
1597 m_compositorSurfaceReady = true;
1598 if (!m_layerTreeView.isNull())
1599 m_layerTreeView.setSurfaceReady();
1602 void WebViewImpl::animate(double)
1604 #if ENABLE(REQUEST_ANIMATION_FRAME)
1605 double monotonicFrameBeginTime = monotonicallyIncreasingTime();
1607 #if USE(ACCELERATED_COMPOSITING)
1608 // In composited mode, we always go through the compositor so it can apply
1609 // appropriate flow-control mechanisms.
1610 if (isAcceleratedCompositingActive())
1611 m_layerTreeView.updateAnimations(monotonicFrameBeginTime);
1614 updateAnimations(monotonicFrameBeginTime);
1618 void WebViewImpl::willBeginFrame()
1620 instrumentBeginFrame();
1621 m_client->willBeginCompositorFrame();
1624 void WebViewImpl::didBeginFrame()
1626 InspectorInstrumentation::didComposite(m_page.get());
1629 void WebViewImpl::updateAnimations(double monotonicFrameBeginTime)
1631 #if ENABLE(REQUEST_ANIMATION_FRAME)
1632 TRACE_EVENT0("webkit", "WebViewImpl::updateAnimations");
1634 WebFrameImpl* webframe = mainFrameImpl();
1637 FrameView* view = webframe->frameView();
1641 // Create synthetic wheel events as necessary for fling.
1642 if (m_gestureAnimation) {
1643 if (m_gestureAnimation->animate(monotonicFrameBeginTime))
1644 scheduleAnimation();
1646 m_gestureAnimation.clear();
1649 PageWidgetDelegate::animate(m_page.get(), monotonicFrameBeginTime);
1653 void WebViewImpl::layout()
1655 TRACE_EVENT0("webkit", "WebViewImpl::layout");
1656 PageWidgetDelegate::layout(m_page.get());
1659 #if USE(ACCELERATED_COMPOSITING)
1660 void WebViewImpl::doPixelReadbackToCanvas(WebCanvas* canvas, const IntRect& rect)
1662 ASSERT(!m_layerTreeView.isNull());
1664 PlatformContextSkia context(canvas);
1666 // PlatformGraphicsContext is actually a pointer to PlatformContextSkia
1667 GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context));
1668 int bitmapHeight = canvas->getDevice()->accessBitmap(false).height();
1670 // Compute rect to sample from inverted GPU buffer.
1671 IntRect invertRect(rect.x(), bitmapHeight - rect.maxY(), rect.width(), rect.height());
1673 OwnPtr<ImageBuffer> imageBuffer(ImageBuffer::create(rect.size()));
1674 RefPtr<Uint8ClampedArray> pixelArray(Uint8ClampedArray::createUninitialized(rect.width() * rect.height() * 4));
1675 if (imageBuffer && pixelArray) {
1676 m_layerTreeView.compositeAndReadback(pixelArray->data(), invertRect);
1677 imageBuffer->putByteArray(Premultiplied, pixelArray.get(), rect.size(), IntRect(IntPoint(), rect.size()), IntPoint());
1679 gc.translate(IntSize(0, bitmapHeight));
1680 gc.scale(FloatSize(1.0f, -1.0f));
1681 // Use invertRect in next line, so that transform above inverts it back to
1682 // desired destination rect.
1683 gc.drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, invertRect.location());
1689 void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect)
1691 if (isAcceleratedCompositingActive()) {
1692 #if USE(ACCELERATED_COMPOSITING)
1693 // If a canvas was passed in, we use it to grab a copy of the
1694 // freshly-rendered pixels.
1696 // Clip rect to the confines of the rootLayerTexture.
1697 IntRect resizeRect(rect);
1698 resizeRect.intersect(IntRect(IntPoint(0, 0), m_layerTreeView.deviceViewportSize()));
1699 doPixelReadbackToCanvas(canvas, resizeRect);
1703 double paintStart = currentTime();
1704 PageWidgetDelegate::paint(m_page.get(), pageOverlays(), canvas, rect, isTransparent() ? PageWidgetDelegate::Translucent : PageWidgetDelegate::Opaque);
1705 double paintEnd = currentTime();
1706 double pixelsPerSec = (rect.width * rect.height) / (paintEnd - paintStart);
1707 WebKit::Platform::current()->histogramCustomCounts("Renderer4.SoftwarePaintDurationMS", (paintEnd - paintStart) * 1000, 0, 120, 30);
1708 WebKit::Platform::current()->histogramCustomCounts("Renderer4.SoftwarePaintMegapixPerSecond", pixelsPerSec / 1000000, 10, 210, 30);
1712 void WebViewImpl::themeChanged()
1716 FrameView* view = page()->mainFrame()->view();
1718 WebRect damagedRect(0, 0, m_size.width, m_size.height);
1719 view->invalidateRect(damagedRect);
1722 void WebViewImpl::composite(bool)
1724 #if USE(ACCELERATED_COMPOSITING)
1725 if (WebCompositor::threadingEnabled())
1726 m_layerTreeView.setNeedsRedraw();
1728 ASSERT(isAcceleratedCompositingActive());
1733 m_pageOverlays->update();
1735 m_layerTreeView.composite();
1740 void WebViewImpl::setNeedsRedraw()
1742 #if USE(ACCELERATED_COMPOSITING)
1743 if (!m_layerTreeView.isNull() && isAcceleratedCompositingActive())
1744 m_layerTreeView.setNeedsRedraw();
1748 bool WebViewImpl::isInputThrottled() const
1750 #if USE(ACCELERATED_COMPOSITING)
1751 if (!m_layerTreeView.isNull() && isAcceleratedCompositingActive())
1752 return m_layerTreeView.commitRequested();
1757 void WebViewImpl::loseCompositorContext(int numTimes)
1759 #if USE(ACCELERATED_COMPOSITING)
1760 if (!m_layerTreeView.isNull())
1761 m_layerTreeView.loseCompositorContext(numTimes);
1765 void WebViewImpl::enterFullScreenForElement(WebCore::Element* element)
1767 // We are already transitioning to fullscreen for a different element.
1768 if (m_provisionalFullScreenElement) {
1769 m_provisionalFullScreenElement = element;
1773 // We are already in fullscreen mode.
1774 if (m_fullScreenFrame) {
1775 m_provisionalFullScreenElement = element;
1776 willEnterFullScreen();
1777 didEnterFullScreen();
1781 #if USE(NATIVE_FULLSCREEN_VIDEO)
1782 if (element && element->isMediaElement()) {
1783 HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(element);
1784 if (mediaElement->player() && mediaElement->player()->canEnterFullscreen()) {
1785 mediaElement->player()->enterFullscreen();
1786 m_provisionalFullScreenElement = element;
1792 // We need to transition to fullscreen mode.
1793 if (m_client && m_client->enterFullScreen())
1794 m_provisionalFullScreenElement = element;
1797 void WebViewImpl::exitFullScreenForElement(WebCore::Element* element)
1799 // The client is exiting full screen, so don't send a notification.
1800 if (m_isCancelingFullScreen)
1802 #if USE(NATIVE_FULLSCREEN_VIDEO)
1803 if (element && element->isMediaElement()) {
1804 HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(element);
1805 if (mediaElement->player())
1806 mediaElement->player()->exitFullscreen();
1811 m_client->exitFullScreen();
1814 bool WebViewImpl::hasHorizontalScrollbar()
1816 return mainFrameImpl()->frameView()->horizontalScrollbar();
1819 bool WebViewImpl::hasVerticalScrollbar()
1821 return mainFrameImpl()->frameView()->verticalScrollbar();
1824 const WebInputEvent* WebViewImpl::m_currentInputEvent = 0;
1826 bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
1828 UserGestureIndicator gestureIndicator(WebInputEvent::isUserGestureEventType(inputEvent.type) ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);
1830 // If we've started a drag and drop operation, ignore input events until
1832 if (m_doingDragAndDrop)
1835 // Report the event to be NOT processed by WebKit, so that the browser can handle it appropriately.
1836 if (m_ignoreInputEvents)
1839 TemporaryChange<const WebInputEvent*> currentEventChange(m_currentInputEvent, &inputEvent);
1841 #if ENABLE(POINTER_LOCK)
1842 if (isPointerLocked() && WebInputEvent::isMouseEventType(inputEvent.type)) {
1843 pointerLockMouseEvent(inputEvent);
1848 if (m_mouseCaptureNode && WebInputEvent::isMouseEventType(inputEvent.type)) {
1849 // Save m_mouseCaptureNode since mouseCaptureLost() will clear it.
1850 RefPtr<Node> node = m_mouseCaptureNode;
1852 // Not all platforms call mouseCaptureLost() directly.
1853 if (inputEvent.type == WebInputEvent::MouseUp)
1856 AtomicString eventType;
1857 switch (inputEvent.type) {
1858 case WebInputEvent::MouseMove:
1859 eventType = eventNames().mousemoveEvent;
1861 case WebInputEvent::MouseLeave:
1862 eventType = eventNames().mouseoutEvent;
1864 case WebInputEvent::MouseDown:
1865 eventType = eventNames().mousedownEvent;
1867 case WebInputEvent::MouseUp:
1868 eventType = eventNames().mouseupEvent;
1871 ASSERT_NOT_REACHED();
1874 node->dispatchMouseEvent(
1875 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), *static_cast<const WebMouseEvent*>(&inputEvent)),
1876 eventType, static_cast<const WebMouseEvent*>(&inputEvent)->clickCount);
1880 bool handled = PageWidgetDelegate::handleInputEvent(m_page.get(), *this, inputEvent);
1884 void WebViewImpl::mouseCaptureLost()
1886 m_mouseCaptureNode = 0;
1889 void WebViewImpl::setFocus(bool enable)
1891 m_page->focusController()->setFocused(enable);
1893 m_page->focusController()->setActive(true);
1894 RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
1896 Node* focusedNode = focusedFrame->document()->focusedNode();
1897 if (focusedNode && focusedNode->isElementNode()
1898 && focusedFrame->selection()->selection().isNone()) {
1899 // If the selection was cleared while the WebView was not
1900 // focused, then the focus element shows with a focus ring but
1901 // no caret and does respond to keyboard inputs.
1902 Element* element = static_cast<Element*>(focusedNode);
1903 if (element->isTextFormControl())
1904 element->updateFocusAppearance(true);
1905 else if (focusedNode->isContentEditable()) {
1906 // updateFocusAppearance() selects all the text of
1907 // contentseditable DIVs. So we set the selection explicitly
1908 // instead. Note that this has the side effect of moving the
1909 // caret back to the beginning of the text.
1910 Position position(focusedNode, 0,
1911 Position::PositionIsOffsetInAnchor);
1912 focusedFrame->selection()->setSelection(
1913 VisibleSelection(position, SEL_DEFAULT_AFFINITY));
1917 m_imeAcceptEvents = true;
1921 // Clear focus on the currently focused frame if any.
1925 Frame* frame = m_page->mainFrame();
1929 RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
1931 // Finish an ongoing composition to delete the composition node.
1932 Editor* editor = focusedFrame->editor();
1933 if (editor && editor->hasComposition())
1934 editor->confirmComposition();
1935 m_imeAcceptEvents = false;
1940 bool WebViewImpl::setComposition(
1941 const WebString& text,
1942 const WebVector<WebCompositionUnderline>& underlines,
1946 Frame* focused = focusedWebCoreFrame();
1947 if (!focused || !m_imeAcceptEvents)
1949 Editor* editor = focused->editor();
1953 // The input focus has been moved to another WebWidget object.
1954 // We should use this |editor| object only to complete the ongoing
1956 if (!editor->canEdit() && !editor->hasComposition())
1959 // We should verify the parent node of this IME composition node are
1960 // editable because JavaScript may delete a parent node of the composition
1961 // node. In this case, WebKit crashes while deleting texts from the parent
1962 // node, which doesn't exist any longer.
1963 PassRefPtr<Range> range = editor->compositionRange();
1965 Node* node = range->startContainer();
1966 if (!node || !node->isContentEditable())
1970 // If we're not going to fire a keypress event, then the keydown event was
1971 // canceled. In that case, cancel any existing composition.
1972 if (text.isEmpty() || m_suppressNextKeypressEvent) {
1973 // A browser process sent an IPC message which does not contain a valid
1974 // string, which means an ongoing composition has been canceled.
1975 // If the ongoing composition has been canceled, replace the ongoing
1976 // composition string with an empty string and complete it.
1978 Vector<CompositionUnderline> emptyUnderlines;
1979 editor->setComposition(emptyString, emptyUnderlines, 0, 0);
1980 return text.isEmpty();
1983 // When the range of composition underlines overlap with the range between
1984 // selectionStart and selectionEnd, WebKit somehow won't paint the selection
1985 // at all (see InlineTextBox::paint() function in InlineTextBox.cpp).
1986 // But the selection range actually takes effect.
1987 editor->setComposition(String(text),
1988 CompositionUnderlineVectorBuilder(underlines),
1989 selectionStart, selectionEnd);
1991 return editor->hasComposition();
1994 bool WebViewImpl::confirmComposition()
1996 return confirmComposition(WebString());
1999 bool WebViewImpl::confirmComposition(const WebString& text)
2001 Frame* focused = focusedWebCoreFrame();
2002 if (!focused || !m_imeAcceptEvents)
2004 Editor* editor = focused->editor();
2005 if (!editor || (!editor->hasComposition() && !text.length()))
2008 // We should verify the parent node of this IME composition node are
2009 // editable because JavaScript may delete a parent node of the composition
2010 // node. In this case, WebKit crashes while deleting texts from the parent
2011 // node, which doesn't exist any longer.
2012 PassRefPtr<Range> range = editor->compositionRange();
2014 Node* node = range->startContainer();
2015 if (!node || !node->isContentEditable())
2019 if (editor->hasComposition()) {
2021 editor->confirmComposition(String(text));
2023 editor->confirmComposition();
2025 editor->insertText(String(text), 0);
2030 bool WebViewImpl::compositionRange(size_t* location, size_t* length)
2032 Frame* focused = focusedWebCoreFrame();
2033 if (!focused || !focused->selection() || !m_imeAcceptEvents)
2035 Editor* editor = focused->editor();
2036 if (!editor || !editor->hasComposition())
2039 RefPtr<Range> range = editor->compositionRange();
2043 if (TextIterator::getLocationAndLengthFromRange(focused->selection()->rootEditableElementOrDocumentElement(), range.get(), *location, *length))
2048 WebTextInputInfo WebViewImpl::textInputInfo()
2050 WebTextInputInfo info;
2052 Frame* focused = focusedWebCoreFrame();
2056 Editor* editor = focused->editor();
2057 if (!editor || !editor->canEdit())
2060 FrameSelection* selection = focused->selection();
2064 Node* node = selection->selection().rootEditableElement();
2068 info.type = textInputType();
2069 if (info.type == WebTextInputTypeNone)
2072 info.value = plainText(rangeOfContents(node).get());
2074 if (info.value.isEmpty())
2079 RefPtr<Range> range = selection->selection().firstRange();
2080 if (range && TextIterator::getLocationAndLengthFromRange(selection->rootEditableElement(), range.get(), location, length)) {
2081 info.selectionStart = location;
2082 info.selectionEnd = location + length;
2084 range = editor->compositionRange();
2085 if (range && TextIterator::getLocationAndLengthFromRange(selection->rootEditableElement(), range.get(), location, length)) {
2086 info.compositionStart = location;
2087 info.compositionEnd = location + length;
2093 WebTextInputType WebViewImpl::textInputType()
2095 Node* node = focusedWebCoreNode();
2097 return WebTextInputTypeNone;
2099 if (node->hasTagName(HTMLNames::inputTag)) {
2100 HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
2102 if (input->readOnly() || input->disabled())
2103 return WebTextInputTypeNone;
2105 if (input->isPasswordField())
2106 return WebTextInputTypePassword;
2107 if (input->isSearchField())
2108 return WebTextInputTypeSearch;
2109 if (input->isEmailField())
2110 return WebTextInputTypeEmail;
2111 if (input->isNumberField())
2112 return WebTextInputTypeNumber;
2113 if (input->isTelephoneField())
2114 return WebTextInputTypeTelephone;
2115 if (input->isURLField())
2116 return WebTextInputTypeURL;
2117 if (input->isDateField())
2118 return WebTextInputTypeDate;
2119 if (input->isDateTimeField())
2120 return WebTextInputTypeDateTime;
2121 if (input->isDateTimeLocalField())
2122 return WebTextInputTypeDateTimeLocal;
2123 if (input->isMonthField())
2124 return WebTextInputTypeMonth;
2125 if (input->isTimeField())
2126 return WebTextInputTypeTime;
2127 if (input->isWeekField())
2128 return WebTextInputTypeWeek;
2129 if (input->isTextField())
2130 return WebTextInputTypeText;
2132 return WebTextInputTypeNone;
2135 if (node->hasTagName(HTMLNames::textareaTag)) {
2136 HTMLTextAreaElement* textarea = static_cast<HTMLTextAreaElement*>(node);
2138 if (textarea->readOnly() || textarea->disabled())
2139 return WebTextInputTypeNone;
2141 return WebTextInputTypeTextArea;
2144 if (node->shouldUseInputMethod())
2145 return WebTextInputTypeContentEditable;
2147 return WebTextInputTypeNone;
2150 bool WebViewImpl::selectionBounds(WebRect& start, WebRect& end) const
2152 const Frame* frame = focusedWebCoreFrame();
2155 FrameSelection* selection = frame->selection();
2159 if (selection->isCaret()) {
2160 start = end = frame->view()->contentsToWindow(selection->absoluteCaretBounds());
2164 RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange();
2168 RefPtr<Range> range(Range::create(selectedRange->startContainer()->document(),
2169 selectedRange->startContainer(),
2170 selectedRange->startOffset(),
2171 selectedRange->startContainer(),
2172 selectedRange->startOffset()));
2173 start = frame->editor()->firstRectForRange(range.get());
2175 range = Range::create(selectedRange->endContainer()->document(),
2176 selectedRange->endContainer(),
2177 selectedRange->endOffset(),
2178 selectedRange->endContainer(),
2179 selectedRange->endOffset());
2180 end = frame->editor()->firstRectForRange(range.get());
2182 start = frame->view()->contentsToWindow(start);
2183 end = frame->view()->contentsToWindow(end);
2185 if (!frame->selection()->selection().isBaseFirst())
2186 std::swap(start, end);
2190 bool WebViewImpl::selectionTextDirection(WebTextDirection& start, WebTextDirection& end) const
2192 const Frame* frame = focusedWebCoreFrame();
2195 FrameSelection* selection = frame->selection();
2198 if (!selection->toNormalizedRange())
2200 start = selection->start().primaryDirection() == RTL ? WebTextDirectionRightToLeft : WebTextDirectionLeftToRight;
2201 end = selection->end().primaryDirection() == RTL ? WebTextDirectionRightToLeft : WebTextDirectionLeftToRight;
2205 bool WebViewImpl::setEditableSelectionOffsets(int start, int end)
2207 const Frame* focused = focusedWebCoreFrame();
2211 Editor* editor = focused->editor();
2212 if (!editor || !editor->canEdit())
2215 return editor->setSelectionOffsets(start, end);
2218 bool WebViewImpl::isSelectionEditable() const
2220 const Frame* frame = focusedWebCoreFrame();
2223 return frame->selection()->isContentEditable();
2226 WebColor WebViewImpl::backgroundColor() const
2229 return Color::white;
2230 FrameView* view = m_page->mainFrame()->view();
2231 Color backgroundColor = view->documentBackgroundColor();
2232 if (!backgroundColor.isValid())
2233 return Color::white;
2234 return backgroundColor.rgb();
2237 bool WebViewImpl::caretOrSelectionRange(size_t* location, size_t* length)
2239 const Frame* focused = focusedWebCoreFrame();
2243 FrameSelection* selection = focused->selection();
2247 RefPtr<Range> range = selection->selection().firstRange();
2251 if (TextIterator::getLocationAndLengthFromRange(selection->rootEditableElementOrDocumentElement(), range.get(), *location, *length))
2256 void WebViewImpl::setTextDirection(WebTextDirection direction)
2258 // The Editor::setBaseWritingDirection() function checks if we can change
2259 // the text direction of the selected node and updates its DOM "dir"
2260 // attribute and its CSS "direction" property.
2261 // So, we just call the function as Safari does.
2262 const Frame* focused = focusedWebCoreFrame();
2266 Editor* editor = focused->editor();
2267 if (!editor || !editor->canEdit())
2270 switch (direction) {
2271 case WebTextDirectionDefault:
2272 editor->setBaseWritingDirection(NaturalWritingDirection);
2275 case WebTextDirectionLeftToRight:
2276 editor->setBaseWritingDirection(LeftToRightWritingDirection);
2279 case WebTextDirectionRightToLeft:
2280 editor->setBaseWritingDirection(RightToLeftWritingDirection);
2289 bool WebViewImpl::isAcceleratedCompositingActive() const
2291 #if USE(ACCELERATED_COMPOSITING)
2292 return m_isAcceleratedCompositingActive;
2298 void WebViewImpl::didAcquirePointerLock()
2300 #if ENABLE(POINTER_LOCK)
2302 page()->pointerLockController()->didAcquirePointerLock();
2306 void WebViewImpl::didNotAcquirePointerLock()
2308 #if ENABLE(POINTER_LOCK)
2310 page()->pointerLockController()->didNotAcquirePointerLock();
2314 void WebViewImpl::didLosePointerLock()
2316 #if ENABLE(POINTER_LOCK)
2318 page()->pointerLockController()->didLosePointerLock();
2322 void WebViewImpl::didChangeWindowResizerRect()
2324 if (mainFrameImpl()->frameView())
2325 mainFrameImpl()->frameView()->windowResizerRectChanged();
2328 // WebView --------------------------------------------------------------------
2330 WebSettingsImpl* WebViewImpl::settingsImpl()
2333 m_webSettings = adoptPtr(new WebSettingsImpl(m_page->settings()));
2334 ASSERT(m_webSettings);
2335 return m_webSettings.get();
2338 WebSettings* WebViewImpl::settings()
2340 return settingsImpl();
2343 WebString WebViewImpl::pageEncoding() const
2348 // FIXME: Is this check needed?
2349 if (!m_page->mainFrame()->document()->loader())
2352 return m_page->mainFrame()->document()->encoding();
2355 void WebViewImpl::setPageEncoding(const WebString& encodingName)
2360 // Only change override encoding, don't change default encoding.
2361 // Note that the new encoding must be 0 if it isn't supposed to be set.
2362 String newEncodingName;
2363 if (!encodingName.isEmpty())
2364 newEncodingName = encodingName;
2365 m_page->mainFrame()->loader()->reloadWithOverrideEncoding(newEncodingName);
2368 bool WebViewImpl::dispatchBeforeUnloadEvent()
2370 // FIXME: This should really cause a recursive depth-first walk of all
2371 // frames in the tree, calling each frame's onbeforeunload. At the moment,
2372 // we're consistent with Safari 3.1, not IE/FF.
2373 Frame* frame = m_page->mainFrame();
2377 return frame->loader()->shouldClose();
2380 void WebViewImpl::dispatchUnloadEvent()
2382 // Run unload handlers.
2383 m_page->mainFrame()->loader()->closeURL();
2386 WebFrame* WebViewImpl::mainFrame()
2388 return mainFrameImpl();
2391 WebFrame* WebViewImpl::findFrameByName(
2392 const WebString& name, WebFrame* relativeToFrame)
2394 if (!relativeToFrame)
2395 relativeToFrame = mainFrame();
2396 Frame* frame = static_cast<WebFrameImpl*>(relativeToFrame)->frame();
2397 frame = frame->tree()->find(name);
2398 return WebFrameImpl::fromFrame(frame);
2401 WebFrame* WebViewImpl::focusedFrame()
2403 return WebFrameImpl::fromFrame(focusedWebCoreFrame());
2406 void WebViewImpl::setFocusedFrame(WebFrame* frame)
2409 // Clears the focused frame if any.
2410 Frame* frame = focusedWebCoreFrame();
2412 frame->selection()->setFocused(false);
2415 WebFrameImpl* frameImpl = static_cast<WebFrameImpl*>(frame);
2416 Frame* webcoreFrame = frameImpl->frame();
2417 webcoreFrame->page()->focusController()->setFocusedFrame(webcoreFrame);
2420 void WebViewImpl::setInitialFocus(bool reverse)
2425 // Since we don't have a keyboard event, we'll create one.
2426 WebKeyboardEvent keyboardEvent;
2427 keyboardEvent.type = WebInputEvent::RawKeyDown;
2429 keyboardEvent.modifiers = WebInputEvent::ShiftKey;
2431 // VK_TAB which is only defined on Windows.
2432 keyboardEvent.windowsKeyCode = 0x09;
2433 PlatformKeyboardEventBuilder platformEvent(keyboardEvent);
2434 RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0);
2436 Frame* frame = page()->focusController()->focusedOrMainFrame();
2437 if (Document* document = frame->document())
2438 document->setFocusedNode(0);
2439 page()->focusController()->setInitialFocus(
2440 reverse ? FocusDirectionBackward : FocusDirectionForward,
2444 void WebViewImpl::clearFocusedNode()
2446 RefPtr<Frame> frame = focusedWebCoreFrame();
2450 RefPtr<Document> document = frame->document();
2454 RefPtr<Node> oldFocusedNode = document->focusedNode();
2456 // Clear the focused node.
2457 document->setFocusedNode(0);
2459 if (!oldFocusedNode)
2462 // If a text field has focus, we need to make sure the selection controller
2463 // knows to remove selection from it. Otherwise, the text field is still
2464 // processing keyboard events even though focus has been moved to the page and
2465 // keystrokes get eaten as a result.
2466 if (oldFocusedNode->isContentEditable()
2467 || (oldFocusedNode->isElementNode()
2468 && static_cast<Element*>(oldFocusedNode.get())->isTextFormControl())) {
2469 frame->selection()->clear();
2473 void WebViewImpl::scrollFocusedNodeIntoView()
2475 Node* focusedNode = focusedWebCoreNode();
2476 if (focusedNode && focusedNode->isElementNode()) {
2477 Element* elementNode = static_cast<Element*>(focusedNode);
2478 elementNode->scrollIntoViewIfNeeded(true);
2482 void WebViewImpl::scrollFocusedNodeIntoRect(const WebRect& rect)
2484 Frame* frame = page()->mainFrame();
2485 Node* focusedNode = focusedWebCoreNode();
2486 if (!frame || !frame->view() || !focusedNode || !focusedNode->isElementNode())
2488 Element* elementNode = static_cast<Element*>(focusedNode);
2489 frame->view()->scrollElementToRect(elementNode, IntRect(rect.x, rect.y, rect.width, rect.height));
2492 void WebViewImpl::advanceFocus(bool reverse)
2494 page()->focusController()->advanceFocus(reverse ? FocusDirectionBackward : FocusDirectionForward, 0);
2497 double WebViewImpl::zoomLevel()
2502 double WebViewImpl::setZoomLevel(bool textOnly, double zoomLevel)
2504 if (zoomLevel < m_minimumZoomLevel)
2505 m_zoomLevel = m_minimumZoomLevel;
2506 else if (zoomLevel > m_maximumZoomLevel)
2507 m_zoomLevel = m_maximumZoomLevel;
2509 m_zoomLevel = zoomLevel;
2511 Frame* frame = mainFrameImpl()->frame();
2512 WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
2513 if (pluginContainer)
2514 pluginContainer->plugin()->setZoomLevel(m_zoomLevel, textOnly);
2516 float zoomFactor = static_cast<float>(zoomLevelToZoomFactor(m_zoomLevel));
2518 frame->setPageAndTextZoomFactors(1, zoomFactor * m_emulatedTextZoomFactor);
2520 frame->setPageAndTextZoomFactors(zoomFactor, m_emulatedTextZoomFactor);
2525 void WebViewImpl::zoomLimitsChanged(double minimumZoomLevel,
2526 double maximumZoomLevel)
2528 m_minimumZoomLevel = minimumZoomLevel;
2529 m_maximumZoomLevel = maximumZoomLevel;
2530 m_client->zoomLimitsChanged(m_minimumZoomLevel, m_maximumZoomLevel);
2533 void WebViewImpl::fullFramePluginZoomLevelChanged(double zoomLevel)
2535 if (zoomLevel == m_zoomLevel)
2538 m_zoomLevel = max(min(zoomLevel, m_maximumZoomLevel), m_minimumZoomLevel);
2539 m_client->zoomLevelChanged();
2542 double WebView::zoomLevelToZoomFactor(double zoomLevel)
2544 return pow(textSizeMultiplierRatio, zoomLevel);
2547 double WebView::zoomFactorToZoomLevel(double factor)
2549 // Since factor = 1.2^level, level = log(factor) / log(1.2)
2550 return log(factor) / log(textSizeMultiplierRatio);
2553 float WebViewImpl::pageScaleFactor() const
2558 return page()->pageScaleFactor();
2561 bool WebViewImpl::isPageScaleFactorSet() const
2563 return m_pageScaleFactorIsSet;
2566 float WebViewImpl::clampPageScaleFactorToLimits(float scaleFactor)
2568 return min(max(scaleFactor, m_minimumPageScaleFactor), m_maximumPageScaleFactor);
2571 WebPoint WebViewImpl::clampOffsetAtScale(const WebPoint& offset, float scale)
2573 // This is the scaled content size. We need to convert it to the new scale factor.
2574 WebSize contentSize = mainFrame()->contentsSize();
2575 float deltaScale = scale / pageScaleFactor();
2576 int docWidthAtNewScale = contentSize.width * deltaScale;
2577 int docHeightAtNewScale = contentSize.height * deltaScale;
2578 int viewWidth = m_size.width;
2579 int viewHeight = m_size.height;
2581 // Enforce the maximum and minimum scroll positions at the new scale.
2582 IntPoint clampedOffset = offset;
2583 clampedOffset = clampedOffset.shrunkTo(IntPoint(docWidthAtNewScale - viewWidth, docHeightAtNewScale - viewHeight));
2584 clampedOffset.clampNegativeToZero();
2585 return clampedOffset;
2588 void WebViewImpl::setPageScaleFactorPreservingScrollOffset(float scaleFactor)
2590 // Pick a scale factor that is within the expected limits
2591 scaleFactor = clampPageScaleFactorToLimits(scaleFactor);
2593 IntPoint scrollOffsetAtNewScale(mainFrame()->scrollOffset().width, mainFrame()->scrollOffset().height);
2594 float deltaScale = scaleFactor / pageScaleFactor();
2595 scrollOffsetAtNewScale.scale(deltaScale, deltaScale);
2597 WebPoint clampedOffsetAtNewScale = clampOffsetAtScale(scrollOffsetAtNewScale, scaleFactor);
2598 setPageScaleFactor(scaleFactor, clampedOffsetAtNewScale);
2601 void WebViewImpl::setPageScaleFactor(float scaleFactor, const WebPoint& origin)
2609 if (m_deviceScaleInCompositor != 1) {
2610 // Don't allow page scaling when compositor scaling is being used,
2611 // as they are currently incompatible.
2612 ASSERT(scaleFactor == 1);
2615 scaleFactor = clampPageScaleFactorToLimits(scaleFactor);
2616 WebPoint clampedOrigin = clampOffsetAtScale(origin, scaleFactor);
2617 page()->setPageScaleFactor(scaleFactor, clampedOrigin);
2618 m_pageScaleFactorIsSet = true;
2621 float WebViewImpl::deviceScaleFactor() const
2626 return page()->deviceScaleFactor();
2629 void WebViewImpl::setDeviceScaleFactor(float scaleFactor)
2634 page()->setDeviceScaleFactor(scaleFactor);
2636 if (!m_layerTreeView.isNull() && m_webSettings->applyDefaultDeviceScaleFactorInCompositor()) {
2637 m_deviceScaleInCompositor = page()->deviceScaleFactor();
2638 m_layerTreeView.setDeviceScaleFactor(m_deviceScaleInCompositor);
2640 if (m_deviceScaleInCompositor != 1) {
2641 // Don't allow page scaling when compositor scaling is being used,
2642 // as they are currently incompatible. This means the deviceScale
2643 // needs to match the one in the compositor.
2644 ASSERT(scaleFactor == m_deviceScaleInCompositor);
2648 bool WebViewImpl::isFixedLayoutModeEnabled() const
2653 Frame* frame = page()->mainFrame();
2654 if (!frame || !frame->view())
2657 return frame->view()->useFixedLayout();
2660 void WebViewImpl::enableFixedLayoutMode(bool enable)
2665 Frame* frame = page()->mainFrame();
2666 if (!frame || !frame->view())
2669 frame->view()->setUseFixedLayout(enable);
2671 #if USE(ACCELERATED_COMPOSITING)
2672 // Also notify the base layer, which RenderLayerCompositor does not see.
2673 if (m_nonCompositedContentHost)
2674 updateLayerTreeViewport();
2679 void WebViewImpl::enableAutoResizeMode(const WebSize& minSize, const WebSize& maxSize)
2681 m_shouldAutoResize = true;
2682 m_minAutoSize = minSize;
2683 m_maxAutoSize = maxSize;
2684 configureAutoResizeMode();
2687 void WebViewImpl::disableAutoResizeMode()
2689 m_shouldAutoResize = false;
2690 configureAutoResizeMode();
2693 void WebViewImpl::setPageScaleFactorLimits(float minPageScale, float maxPageScale)
2695 m_pageDefinedMinimumPageScaleFactor = minPageScale;
2696 m_pageDefinedMaximumPageScaleFactor = maxPageScale;
2697 computePageScaleFactorLimits();
2700 void WebViewImpl::setIgnoreViewportTagMaximumScale(bool flag)
2702 m_ignoreViewportTagMaximumScale = flag;
2704 if (!page() || !page()->mainFrame())
2707 m_page->chrome()->client()->dispatchViewportPropertiesDidChange(page()->mainFrame()->document()->viewportArguments());
2710 bool WebViewImpl::computePageScaleFactorLimits()
2712 if (m_pageDefinedMinimumPageScaleFactor == -1 || m_pageDefinedMaximumPageScaleFactor == -1)
2715 if (!mainFrame() || !page() || !page()->mainFrame() || !page()->mainFrame()->view())
2718 m_minimumPageScaleFactor = min(max(m_pageDefinedMinimumPageScaleFactor, minPageScaleFactor), maxPageScaleFactor) * (deviceScaleFactor() / m_deviceScaleInCompositor);
2719 m_maximumPageScaleFactor = max(min(m_pageDefinedMaximumPageScaleFactor, maxPageScaleFactor), minPageScaleFactor) * (deviceScaleFactor() / m_deviceScaleInCompositor);
2721 int viewWidthNotIncludingScrollbars = page()->mainFrame()->view()->visibleContentRect(false).width();
2722 int contentsWidth = mainFrame()->contentsSize().width;
2723 if (viewWidthNotIncludingScrollbars && contentsWidth) {
2724 // Limit page scaling down to the document width.
2725 int unscaledContentWidth = contentsWidth / pageScaleFactor();
2726 m_minimumPageScaleFactor = max(m_minimumPageScaleFactor, static_cast<float>(viewWidthNotIncludingScrollbars) / unscaledContentWidth);
2727 m_maximumPageScaleFactor = max(m_minimumPageScaleFactor, m_maximumPageScaleFactor);
2729 ASSERT(m_minimumPageScaleFactor <= m_maximumPageScaleFactor);
2731 float clampedScale = clampPageScaleFactorToLimits(pageScaleFactor());
2732 #if USE(ACCELERATED_COMPOSITING)
2733 if (!m_layerTreeView.isNull())
2734 m_layerTreeView.setPageScaleFactorAndLimits(clampedScale, m_minimumPageScaleFactor, m_maximumPageScaleFactor);
2736 if (clampedScale != pageScaleFactor()) {
2737 setPageScaleFactorPreservingScrollOffset(clampedScale);
2744 float WebViewImpl::minimumPageScaleFactor() const
2746 return m_minimumPageScaleFactor;
2749 float WebViewImpl::maximumPageScaleFactor() const
2751 return m_maximumPageScaleFactor;
2754 void WebViewImpl::saveScrollAndScaleState()
2756 m_savedPageScaleFactor = pageScaleFactor();
2757 m_savedScrollOffset = mainFrame()->scrollOffset();
2760 void WebViewImpl::restoreScrollAndScaleState()
2762 if (!m_savedPageScaleFactor)
2765 #if ENABLE(GESTURE_EVENTS)
2766 startPageScaleAnimation(IntPoint(m_savedScrollOffset), false, m_savedPageScaleFactor, scrollAndScaleAnimationDurationInSeconds);
2768 setPageScaleFactor(m_savedPageScaleFactor, WebPoint());
2769 mainFrame()->setScrollOffset(m_savedScrollOffset);
2772 resetSavedScrollAndScaleState();
2775 void WebViewImpl::resetSavedScrollAndScaleState()
2777 m_savedPageScaleFactor = 0;
2778 m_savedScrollOffset = IntSize();
2781 WebSize WebViewImpl::fixedLayoutSize() const
2786 Frame* frame = page()->mainFrame();
2787 if (!frame || !frame->view())
2790 return frame->view()->fixedLayoutSize();
2793 void WebViewImpl::setFixedLayoutSize(const WebSize& layoutSize)
2798 Frame* frame = page()->mainFrame();
2799 if (!frame || !frame->view())
2802 frame->view()->setFixedLayoutSize(layoutSize);
2805 void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action,
2806 const WebPoint& location)
2808 HitTestResult result = hitTestResultForWindowPos(location);
2809 RefPtr<Node> node = result.innerNonSharedNode();
2810 if (!node->hasTagName(HTMLNames::videoTag) && !node->hasTagName(HTMLNames::audioTag))
2813 RefPtr<HTMLMediaElement> mediaElement =
2814 static_pointer_cast<HTMLMediaElement>(node);
2815 switch (action.type) {
2816 case WebMediaPlayerAction::Play:
2818 mediaElement->play();
2820 mediaElement->pause();
2822 case WebMediaPlayerAction::Mute:
2823 mediaElement->setMuted(action.enable);
2825 case WebMediaPlayerAction::Loop:
2826 mediaElement->setLoop(action.enable);
2828 case WebMediaPlayerAction::Controls:
2829 mediaElement->setControls(action.enable);
2832 ASSERT_NOT_REACHED();
2836 void WebViewImpl::performPluginAction(const WebPluginAction& action,
2837 const WebPoint& location)
2839 HitTestResult result = hitTestResultForWindowPos(location);
2840 RefPtr<Node> node = result.innerNonSharedNode();
2841 if (!node->hasTagName(HTMLNames::objectTag) && !node->hasTagName(HTMLNames::embedTag))
2844 RenderObject* object = node->renderer();
2845 if (object && object->isWidget()) {
2846 Widget* widget = toRenderWidget(object)->widget();
2847 if (widget && widget->isPluginContainer()) {
2848 WebPluginContainerImpl* plugin = static_cast<WebPluginContainerImpl*>(widget);
2849 switch (action.type) {
2850 case WebPluginAction::Rotate90Clockwise:
2851 plugin->plugin()->rotateView(WebPlugin::RotationType90Clockwise);
2853 case WebPluginAction::Rotate90Counterclockwise:
2854 plugin->plugin()->rotateView(WebPlugin::RotationType90Counterclockwise);
2857 ASSERT_NOT_REACHED();
2863 void WebViewImpl::copyImageAt(const WebPoint& point)
2868 HitTestResult result = hitTestResultForWindowPos(point);
2870 if (result.absoluteImageURL().isEmpty()) {
2871 // There isn't actually an image at these coordinates. Might be because
2872 // the window scrolled while the context menu was open or because the page
2873 // changed itself between when we thought there was an image here and when
2874 // we actually tried to retreive the image.
2876 // FIXME: implement a cache of the most recent HitTestResult to avoid having
2877 // to do two hit tests.
2881 m_page->mainFrame()->editor()->copyImage(result);
2884 void WebViewImpl::dragSourceEndedAt(
2885 const WebPoint& clientPoint,
2886 const WebPoint& screenPoint,
2887 WebDragOperation operation)
2889 PlatformMouseEvent pme(clientPoint,
2891 LeftButton, PlatformEvent::MouseMoved, 0, false, false, false,
2893 m_page->mainFrame()->eventHandler()->dragSourceEndedAt(pme,
2894 static_cast<DragOperation>(operation));
2895 m_dragScrollTimer->stop();
2898 void WebViewImpl::dragSourceMovedTo(
2899 const WebPoint& clientPoint,
2900 const WebPoint& screenPoint,
2901 WebDragOperation operation)
2903 m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint);
2906 void WebViewImpl::dragSourceSystemDragEnded()
2908 // It's possible for us to get this callback while not doing a drag if
2909 // it's from a previous page that got unloaded.
2910 if (m_doingDragAndDrop) {
2911 m_page->dragController()->dragEnded();
2912 m_doingDragAndDrop = false;
2916 WebDragOperation WebViewImpl::dragTargetDragEnter(
2917 const WebDragData& webDragData,
2918 const WebPoint& clientPoint,
2919 const WebPoint& screenPoint,
2920 WebDragOperationsMask operationsAllowed,
2923 ASSERT(!m_currentDragData);
2925 m_currentDragData = webDragData;
2926 m_operationsAllowed = operationsAllowed;
2928 return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragEnter, keyModifiers);
2931 WebDragOperation WebViewImpl::dragTargetDragOver(
2932 const WebPoint& clientPoint,
2933 const WebPoint& screenPoint,
2934 WebDragOperationsMask operationsAllowed,
2937 m_operationsAllowed = operationsAllowed;
2939 return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragOver, keyModifiers);
2942 void WebViewImpl::dragTargetDragLeave()
2944 ASSERT(m_currentDragData);
2947 m_currentDragData.get(),
2950 static_cast<DragOperation>(m_operationsAllowed));
2952 m_page->dragController()->dragExited(&dragData);
2954 // FIXME: why is the drag scroll timer not stopped here?
2956 m_dragOperation = WebDragOperationNone;
2957 m_currentDragData = 0;
2960 void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint,
2961 const WebPoint& screenPoint,
2964 ASSERT(m_currentDragData);
2966 // If this webview transitions from the "drop accepting" state to the "not
2967 // accepting" state, then our IPC message reply indicating that may be in-
2968 // flight, or else delayed by javascript processing in this webview. If a
2969 // drop happens before our IPC reply has reached the browser process, then
2970 // the browser forwards the drop to this webview. So only allow a drop to
2971 // proceed if our webview m_dragOperation state is not DragOperationNone.
2973 if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop.
2974 dragTargetDragLeave();
2978 m_currentDragData->setModifierKeyState(webInputEventKeyStateToPlatformEventKeyState(keyModifiers));
2980 m_currentDragData.get(),
2983 static_cast<DragOperation>(m_operationsAllowed));
2985 m_page->dragController()->performDrag(&dragData);
2987 m_dragOperation = WebDragOperationNone;
2988 m_currentDragData = 0;
2990 m_dragScrollTimer->stop();
2993 WebDragOperation WebViewImpl::dragTargetDragEnterOrOver(const WebPoint& clientPoint, const WebPoint& screenPoint, DragAction dragAction, int keyModifiers)
2995 ASSERT(m_currentDragData);
2997 m_currentDragData->setModifierKeyState(webInputEventKeyStateToPlatformEventKeyState(keyModifiers));
2999 m_currentDragData.get(),
3002 static_cast<DragOperation>(m_operationsAllowed));
3004 DragSession dragSession;
3005 if (dragAction == DragEnter)
3006 dragSession = m_page->dragController()->dragEntered(&dragData);
3008 dragSession = m_page->dragController()->dragUpdated(&dragData);
3010 DragOperation dropEffect = dragSession.operation;
3012 // Mask the drop effect operation against the drag source's allowed operations.
3013 if (!(dropEffect & dragData.draggingSourceOperationMask()))
3014 dropEffect = DragOperationNone;
3016 m_dragOperation = static_cast<WebDragOperation>(dropEffect);
3018 if (dragAction == DragOver)
3019 m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint);
3021 m_dragScrollTimer->stop();
3023 return m_dragOperation;
3026 void WebViewImpl::sendResizeEventAndRepaint()
3028 if (mainFrameImpl()->frameView()) {
3029 // Enqueues the resize event.
3030 mainFrameImpl()->frame()->eventHandler()->sendResizeEvent();
3034 if (isAcceleratedCompositingActive()) {
3035 #if USE(ACCELERATED_COMPOSITING)
3036 updateLayerTreeViewport();
3039 WebRect damagedRect(0, 0, m_size.width, m_size.height);
3040 m_client->didInvalidateRect(damagedRect);
3045 void WebViewImpl::configureAutoResizeMode()
3047 if (!mainFrameImpl() || !mainFrameImpl()->frame() || !mainFrameImpl()->frame()->view())
3050 mainFrameImpl()->frame()->view()->enableAutoSizeMode(m_shouldAutoResize, m_minAutoSize, m_maxAutoSize);
3053 unsigned long WebViewImpl::createUniqueIdentifierForRequest()
3056 return m_page->progress()->createUniqueIdentifier();
3060 void WebViewImpl::inspectElementAt(const WebPoint& point)
3065 if (point.x == -1 || point.y == -1)
3066 m_page->inspectorController()->inspect(0);
3068 HitTestResult result = hitTestResultForWindowPos(point);
3070 if (!result.innerNonSharedNode())
3073 m_page->inspectorController()->inspect(result.innerNonSharedNode());
3077 WebString WebViewImpl::inspectorSettings() const
3079 return m_inspectorSettings;
3082 void WebViewImpl::setInspectorSettings(const WebString& settings)
3084 m_inspectorSettings = settings;
3087 bool WebViewImpl::inspectorSetting(const WebString& key, WebString* value) const
3089 if (!m_inspectorSettingsMap->contains(key))
3091 *value = m_inspectorSettingsMap->get(key);
3095 void WebViewImpl::setInspectorSetting(const WebString& key,
3096 const WebString& value)
3098 m_inspectorSettingsMap->set(key, value);
3099 client()->didUpdateInspectorSetting(key, value);
3102 WebDevToolsAgent* WebViewImpl::devToolsAgent()
3104 return m_devToolsAgent.get();
3107 WebAccessibilityObject WebViewImpl::accessibilityObject()
3109 if (!mainFrameImpl())
3110 return WebAccessibilityObject();
3112 Document* document = mainFrameImpl()->frame()->document();
3113 return WebAccessibilityObject(
3114 document->axObjectCache()->getOrCreate(document->renderer()));
3117 void WebViewImpl::applyAutofillSuggestions(
3118 const WebNode& node,
3119 const WebVector<WebString>& names,
3120 const WebVector<WebString>& labels,
3121 const WebVector<WebString>& icons,
3122 const WebVector<int>& itemIDs,
3125 ASSERT(names.size() == labels.size());
3126 ASSERT(names.size() == itemIDs.size());
3128 if (names.isEmpty()) {
3129 hideAutofillPopup();
3133 RefPtr<Node> focusedNode = focusedWebCoreNode();
3134 // If the node for which we queried the Autofill suggestions is not the
3135 // focused node, then we have nothing to do. FIXME: also check the
3136 // caret is at the end and that the text has not changed.
3137 if (!focusedNode || focusedNode != PassRefPtr<Node>(node)) {
3138 hideAutofillPopup();
3142 HTMLInputElement* inputElem = focusedNode->toInputElement();
3145 // The first time the Autofill popup is shown we'll create the client and
3147 if (!m_autofillPopupClient)
3148 m_autofillPopupClient = adoptPtr(new AutofillPopupMenuClient);
3150 m_autofillPopupClient->initialize(
3151 inputElem, names, labels, icons, itemIDs, separatorIndex);
3153 if (!m_autofillPopup) {
3154 PopupContainerSettings popupSettings = autofillPopupSettings;
3155 popupSettings.deviceSupportsTouch = settingsImpl()->deviceSupportsTouch();
3156 m_autofillPopup = PopupContainer::create(m_autofillPopupClient.get(),
3157 PopupContainer::Suggestion,
3161 if (m_autofillPopupShowing) {
3162 refreshAutofillPopup();
3164 m_autofillPopupShowing = true;
3165 m_autofillPopup->showInRect(focusedNode->getPixelSnappedRect(), focusedNode->ownerDocument()->view(), 0);
3169 void WebViewImpl::hidePopups()
3172 hideAutofillPopup();
3173 #if ENABLE(PAGE_POPUP)
3175 closePagePopup(m_pagePopup.get());
3179 void WebViewImpl::performCustomContextMenuAction(unsigned action)
3183 ContextMenu* menu = m_page->contextMenuController()->contextMenu();
3186 ContextMenuItem* item = menu->itemWithAction(static_cast<ContextMenuAction>(ContextMenuItemBaseCustomTag + action));
3188 m_page->contextMenuController()->contextMenuItemSelected(item);
3189 m_page->contextMenuController()->clearContextMenu();
3192 // WebView --------------------------------------------------------------------
3194 void WebViewImpl::setIsTransparent(bool isTransparent)
3196 // Set any existing frames to be transparent.
3197 Frame* frame = m_page->mainFrame();
3199 frame->view()->setTransparent(isTransparent);
3200 frame = frame->tree()->traverseNext();
3203 // Future frames check this to know whether to be transparent.
3204 m_isTransparent = isTransparent;
3206 if (m_nonCompositedContentHost)
3207 m_nonCompositedContentHost->setOpaque(!isTransparent);
3209 if (!m_layerTreeView.isNull())
3210 m_layerTreeView.setHasTransparentBackground(isTransparent);
3213 bool WebViewImpl::isTransparent() const
3215 return m_isTransparent;
3218 void WebViewImpl::setIsActive(bool active)
3220 if (page() && page()->focusController())
3221 page()->focusController()->setActive(active);
3224 bool WebViewImpl::isActive() const
3226 return (page() && page()->focusController()) ? page()->focusController()->isActive() : false;
3229 void WebViewImpl::setDomainRelaxationForbidden(bool forbidden, const WebString& scheme)
3231 SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(forbidden, String(scheme));
3234 void WebViewImpl::setScrollbarColors(unsigned inactiveColor,
3235 unsigned activeColor,
3236 unsigned trackColor) {
3237 #if OS(UNIX) && !OS(DARWIN) && !OS(ANDROID)
3238 PlatformThemeChromiumLinux::setScrollbarColors(inactiveColor, activeColor, trackColor);
3242 void WebViewImpl::setSelectionColors(unsigned activeBackgroundColor,
3243 unsigned activeForegroundColor,
3244 unsigned inactiveBackgroundColor,
3245 unsigned inactiveForegroundColor) {
3246 #if OS(UNIX) && !OS(DARWIN) && !OS(ANDROID)
3247 RenderThemeChromiumLinux::setSelectionColors(activeBackgroundColor,
3248 activeForegroundColor,
3249 inactiveBackgroundColor,
3250 inactiveForegroundColor);
3251 theme()->platformColorsDidChange();
3255 void WebView::addUserScript(const WebString& sourceCode,
3256 const WebVector<WebString>& patternsIn,
3257 WebView::UserScriptInjectAt injectAt,
3258 WebView::UserContentInjectIn injectIn)
3260 OwnPtr<Vector<String> > patterns = adoptPtr(new Vector<String>);
3261 for (size_t i = 0; i < patternsIn.size(); ++i)
3262 patterns->append(patternsIn[i]);
3264 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
3265 RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create());
3266 pageGroup->addUserScriptToWorld(world.get(), sourceCode, WebURL(), patterns.release(), nullptr,
3267 static_cast<UserScriptInjectionTime>(injectAt),
3268 static_cast<UserContentInjectedFrames>(injectIn));
3271 void WebView::addUserStyleSheet(const WebString& sourceCode,
3272 const WebVector<WebString>& patternsIn,
3273 WebView::UserContentInjectIn injectIn,
3274 WebView::UserStyleInjectionTime injectionTime)
3276 OwnPtr<Vector<String> > patterns = adoptPtr(new Vector<String>);
3277 for (size_t i = 0; i < patternsIn.size(); ++i)
3278 patterns->append(patternsIn[i]);
3280 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
3281 RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create());
3283 // FIXME: Current callers always want the level to be "author". It probably makes sense to let
3284 // callers specify this though, since in other cases the caller will probably want "user" level.
3286 // FIXME: It would be nice to populate the URL correctly, instead of passing an empty URL.
3287 pageGroup->addUserStyleSheetToWorld(world.get(), sourceCode, WebURL(), patterns.release(), nullptr,
3288 static_cast<UserContentInjectedFrames>(injectIn),
3289 UserStyleAuthorLevel,
3290 static_cast<WebCore::UserStyleInjectionTime>(injectionTime));
3293 void WebView::removeAllUserContent()
3295 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
3296 pageGroup->removeAllUserContent();
3299 void WebViewImpl::didCommitLoad(bool* isNewNavigation, bool isNavigationWithinPage)
3301 if (isNewNavigation)
3302 *isNewNavigation = m_observedNewNavigation;
3305 ASSERT(!m_observedNewNavigation
3306 || m_page->mainFrame()->loader()->documentLoader() == m_newNavigationLoader);
3307 m_newNavigationLoader = 0;
3309 m_observedNewNavigation = false;
3310 if (*isNewNavigation && !isNavigationWithinPage)
3311 m_pageScaleFactorIsSet = false;
3313 m_gestureAnimation.clear();
3314 resetSavedScrollAndScaleState();
3317 void WebViewImpl::layoutUpdated(WebFrameImpl* webframe)
3319 if (!m_client || webframe != mainFrameImpl())
3322 if (m_shouldAutoResize && mainFrameImpl()->frame() && mainFrameImpl()->frame()->view()) {
3323 WebSize frameSize = mainFrameImpl()->frame()->view()->frameRect().size();
3324 if (frameSize != m_size) {
3326 m_client->didAutoResize(m_size);
3327 sendResizeEventAndRepaint();
3331 m_client->didUpdateLayout();
3334 void WebViewImpl::didChangeContentsSize()
3336 #if ENABLE(VIEWPORT)
3337 if (!settings()->viewportEnabled())
3340 bool didChangeScale = false;
3341 if (!isPageScaleFactorSet()) {
3342 // If the viewport tag failed to be processed earlier, we need
3343 // to recompute it now.
3344 ViewportArguments viewportArguments = mainFrameImpl()->frame()->document()->viewportArguments();
3345 m_page->chrome()->client()->dispatchViewportPropertiesDidChange(viewportArguments);
3346 didChangeScale = true;
3348 didChangeScale = computePageScaleFactorLimits();
3350 if (!didChangeScale)
3353 if (!mainFrameImpl())
3356 FrameView* view = mainFrameImpl()->frameView();
3357 if (view && view->needsLayout())
3362 bool WebViewImpl::useExternalPopupMenus()
3364 return shouldUseExternalPopupMenus;
3367 void WebViewImpl::setEmulatedTextZoomFactor(float textZoomFactor)
3369 m_emulatedTextZoomFactor = textZoomFactor;
3370 Frame* frame = mainFrameImpl()->frame();
3372 frame->setPageAndTextZoomFactors(frame->pageZoomFactor(), m_emulatedTextZoomFactor);
3375 bool WebViewImpl::navigationPolicyFromMouseEvent(unsigned short button,
3376 bool ctrl, bool shift,
3377 bool alt, bool meta,
3378 WebNavigationPolicy* policy)
3381 const bool newTabModifier = (button == 1) || meta;
3383 const bool newTabModifier = (button == 1) || ctrl;
3385 if (!newTabModifier && !shift && !alt)
3389 if (newTabModifier) {
3391 *policy = WebNavigationPolicyNewForegroundTab;
3393 *policy = WebNavigationPolicyNewBackgroundTab;
3396 *policy = WebNavigationPolicyNewWindow;
3398 *policy = WebNavigationPolicyDownload;
3403 void WebViewImpl::startDragging(Frame* frame,
3404 const WebDragData& dragData,
3405 WebDragOperationsMask mask,
3406 const WebImage& dragImage,
3407 const WebPoint& dragImageOffset)
3411 ASSERT(!m_doingDragAndDrop);
3412 m_doingDragAndDrop = true;
3413 m_client->startDragging(WebFrameImpl::fromFrame(frame), dragData, mask, dragImage, dragImageOffset);
3416 void WebViewImpl::observeNewNavigation()
3418 m_observedNewNavigation = true;
3420 m_newNavigationLoader = m_page->mainFrame()->loader()->documentLoader();
3424 void WebViewImpl::setIgnoreInputEvents(bool newValue)
3426 ASSERT(m_ignoreInputEvents != newValue);
3427 m_ignoreInputEvents = newValue;
3430 void WebViewImpl::addPageOverlay(WebPageOverlay* overlay, int zOrder)
3432 if (!m_pageOverlays)
3433 m_pageOverlays = PageOverlayList::create(this);
3435 m_pageOverlays->add(overlay, zOrder);
3438 void WebViewImpl::removePageOverlay(WebPageOverlay* overlay)
3440 if (m_pageOverlays && m_pageOverlays->remove(overlay) && m_pageOverlays->empty())
3441 m_pageOverlays = nullptr;
3444 void WebViewImpl::setOverlayLayer(WebCore::GraphicsLayer* layer)
3446 if (m_rootGraphicsLayer) {
3447 if (layer->parent() != m_rootGraphicsLayer)
3448 m_rootGraphicsLayer->addChild(layer);
3452 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
3453 NotificationPresenterImpl* WebViewImpl::notificationPresenterImpl()
3455 if (!m_notificationPresenter.isInitialized() && m_client)
3456 m_notificationPresenter.initialize(m_client->notificationPresenter());
3457 return &m_notificationPresenter;
3461 void WebViewImpl::refreshAutofillPopup()
3463 ASSERT(m_autofillPopupShowing);
3465 // Hide the popup if it has become empty.
3466 if (!m_autofillPopupClient->listSize()) {
3467 hideAutofillPopup();
3471 WebRect newWidgetRect = m_autofillPopup->refresh(focusedWebCoreNode()->getPixelSnappedRect());
3472 // Let's resize the backing window if necessary.
3473 WebPopupMenuImpl* popupMenu = static_cast<WebPopupMenuImpl*>(m_autofillPopup->client());
3474 if (popupMenu && popupMenu->client()->windowRect() != newWidgetRect)
3475 popupMenu->client()->setWindowRect(newWidgetRect);
3478 Node* WebViewImpl::focusedWebCoreNode()
3480 Frame* frame = m_page->focusController()->focusedFrame();
3484 Document* document = frame->document();
3488 return document->focusedNode();
3491 HitTestResult WebViewImpl::hitTestResultForWindowPos(const IntPoint& pos)
3493 IntPoint docPoint(m_page->mainFrame()->view()->windowToContents(pos));
3494 return m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(docPoint, false);
3497 void WebViewImpl::setTabsToLinks(bool enable)
3499 m_tabsToLinks = enable;
3502 bool WebViewImpl::tabsToL