Partially revert 104427, change WebWidgetClient::didHandleGestureEvent semantics.
[WebKit-https.git] / Source / WebKit / chromium / src / WebViewImpl.cpp
1 /*
2  * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "WebViewImpl.h"
33
34 #include "AXObjectCache.h"
35 #include "AutofillPopupMenuClient.h"
36 #include "BackForwardListChromium.h"
37 #include "BatteryClientImpl.h"
38 #include "BatteryController.h"
39 #include "CSSValueKeywords.h"
40 #include "Chrome.h"
41 #include "Color.h"
42 #include "ColorSpace.h"
43 #include "CompositionUnderlineVectorBuilder.h"
44 #include "CompositorHUDFontAtlas.h"
45 #include "ContextFeaturesClientImpl.h"
46 #include "ContextMenu.h"
47 #include "ContextMenuController.h"
48 #include "ContextMenuItem.h"
49 #include "Cursor.h"
50 #include "DOMUtilitiesPrivate.h"
51 #include "DeviceOrientationClientProxy.h"
52 #include "Document.h"
53 #include "DocumentLoader.h"
54 #include "DragController.h"
55 #include "DragData.h"
56 #include "DragSession.h"
57 #include "Editor.h"
58 #include "EventHandler.h"
59 #include "Extensions3D.h"
60 #include "FocusController.h"
61 #include "FontDescription.h"
62 #include "Frame.h"
63 #include "FrameLoader.h"
64 #include "FrameSelection.h"
65 #include "FrameTree.h"
66 #include "FrameView.h"
67 #include "GeolocationClientProxy.h"
68 #include "GeolocationController.h"
69 #include "GraphicsContext.h"
70 #include "GraphicsContext3D.h"
71 #include "GraphicsContext3DPrivate.h"
72 #include "HTMLInputElement.h"
73 #include "HTMLMediaElement.h"
74 #include "HTMLNames.h"
75 #include "HTMLTextAreaElement.h"
76 #include "HitTestResult.h"
77 #include "Image.h"
78 #include "ImageBuffer.h"
79 #include "InspectorController.h"
80 #include "InspectorInstrumentation.h"
81 #include "KeyboardCodes.h"
82 #include "KeyboardEvent.h"
83 #include "LayerPainterChromium.h"
84 #include "LinkHighlight.h"
85 #include "MIMETypeRegistry.h"
86 #include "NodeRenderStyle.h"
87 #include "NonCompositedContentHost.h"
88 #include "Page.h"
89 #include "PageGroup.h"
90 #include "PageGroupLoadDeferrer.h"
91 #include "PagePopupClient.h"
92 #include "PageWidgetDelegate.h"
93 #include "PlatformContextSkia.h"
94 #include "PlatformKeyboardEvent.h"
95 #include "PlatformMouseEvent.h"
96 #include "PlatformWheelEvent.h"
97 #include "PointerLockController.h"
98 #include "PopupContainer.h"
99 #include "PopupMenuClient.h"
100 #include "PrerendererClientImpl.h"
101 #include "ProgressTracker.h"
102 #include "RenderLayerCompositor.h"
103 #include "RenderView.h"
104 #include "RenderWidget.h"
105 #include "ResourceHandle.h"
106 #include "SchemeRegistry.h"
107 #include "SecurityOrigin.h"
108 #include "SecurityPolicy.h"
109 #include "Settings.h"
110 #include "SharedGraphicsContext3D.h"
111 #include "SpeechInputClientImpl.h"
112 #include "SpeechRecognitionClientProxy.h"
113 #include "StyleResolver.h"
114 #include "Text.h"
115 #include "TextFieldDecoratorImpl.h"
116 #include "TextIterator.h"
117 #include "Timer.h"
118 #include "TraceEvent.h"
119 #include "ValidationMessageClientImpl.h"
120 #include "WebAccessibilityObject.h"
121 #include "WebActiveWheelFlingParameters.h"
122 #include "WebAutofillClient.h"
123 #include "WebCompositorInputHandlerImpl.h"
124 #include "WebDevToolsAgentImpl.h"
125 #include "WebDevToolsAgentPrivate.h"
126 #include "WebFrameImpl.h"
127 #include "WebHelperPluginImpl.h"
128 #include "WebHitTestResult.h"
129 #include "WebInputElement.h"
130 #include "WebInputEvent.h"
131 #include "WebInputEventConversion.h"
132 #include "WebMediaPlayerAction.h"
133 #include "WebNode.h"
134 #include "WebPagePopupImpl.h"
135 #include "WebPlugin.h"
136 #include "WebPluginAction.h"
137 #include "WebPluginContainerImpl.h"
138 #include "WebPopupMenuImpl.h"
139 #include "WebRange.h"
140 #include "WebRuntimeFeatures.h"
141 #include "WebSettingsImpl.h"
142 #include "WebTextInputInfo.h"
143 #include "WebViewClient.h"
144 #include "WheelEvent.h"
145 #include "painting/ContinuousPainter.h"
146 #include "painting/GraphicsContextBuilder.h"
147 #include "src/WebActiveGestureAnimation.h"
148 #include <public/Platform.h>
149 #include <public/WebCompositorOutputSurface.h>
150 #include <public/WebCompositorSupport.h>
151 #include <public/WebDragData.h>
152 #include <public/WebFloatPoint.h>
153 #include <public/WebGraphicsContext3D.h>
154 #include <public/WebImage.h>
155 #include <public/WebLayer.h>
156 #include <public/WebLayerTreeView.h>
157 #include <public/WebPoint.h>
158 #include <public/WebRect.h>
159 #include <public/WebString.h>
160 #include <public/WebVector.h>
161 #include <wtf/CurrentTime.h>
162 #include <wtf/MainThread.h>
163 #include <wtf/RefPtr.h>
164 #include <wtf/TemporaryChange.h>
165 #include <wtf/Uint8ClampedArray.h>
166
167 #if ENABLE(DEFAULT_RENDER_THEME)
168 #include "PlatformThemeChromiumDefault.h"
169 #include "RenderThemeChromiumDefault.h"
170 #endif
171
172 #if ENABLE(GESTURE_EVENTS)
173 #include "PlatformGestureEvent.h"
174 #include "TouchDisambiguation.h"
175 #endif
176
177 #if OS(WINDOWS)
178 #if !ENABLE(DEFAULT_RENDER_THEME)
179 #include "RenderThemeChromiumWin.h"
180 #endif
181 #else
182 #include "RenderTheme.h"
183 #endif
184
185 // Get rid of WTF's pow define so we can use std::pow.
186 #undef pow
187 #include <cmath> // for std::pow
188
189 using namespace WebCore;
190 using namespace std;
191
192 // The following constants control parameters for automated scaling of webpages
193 // (such as due to a double tap gesture or find in page etc.). These are
194 // experimentally determined.
195 static const int touchPointPadding = 32;
196 static const int nonUserInitiatedPointPadding = 11;
197 static const float minScaleDifference = 0.01f;
198 static const float doubleTapZoomContentDefaultMargin = 5;
199 static const float doubleTapZoomContentMinimumMargin = 2;
200 static const double doubleTapZoomAnimationDurationInSeconds = 0.25;
201 static const float doubleTapZoomAlreadyLegibleRatio = 1.2f;
202
203 // Constants for zooming in on a focused text field.
204 static const double scrollAndScaleAnimationDurationInSeconds = 0.2;
205 static const int minReadableCaretHeight = 18;
206 static const float minScaleChangeToTriggerZoom = 1.05f;
207 static const float leftBoxRatio = 0.3f;
208 static const int caretPadding = 10;
209
210 namespace WebKit {
211
212 // Change the text zoom level by kTextSizeMultiplierRatio each time the user
213 // zooms text in or out (ie., change by 20%).  The min and max values limit
214 // text zoom to half and 3x the original text size.  These three values match
215 // those in Apple's port in WebKit/WebKit/WebView/WebView.mm
216 const double WebView::textSizeMultiplierRatio = 1.2;
217 const double WebView::minTextSizeMultiplier = 0.5;
218 const double WebView::maxTextSizeMultiplier = 3.0;
219 const float WebView::minPageScaleFactor = 0.25f;
220 const float WebView::maxPageScaleFactor = 4.0f;
221
222
223 // The group name identifies a namespace of pages. Page group is used on PLATFORM(MAC)
224 // for some programs that use HTML views to display things that don't seem like
225 // web pages to the user (so shouldn't have visited link coloring).  We only use
226 // one page group.
227 const char* pageGroupName = "default";
228
229 // Used to defer all page activity in cases where the embedder wishes to run
230 // a nested event loop. Using a stack enables nesting of message loop invocations.
231 static Vector<PageGroupLoadDeferrer*>& pageGroupLoadDeferrerStack()
232 {
233     DEFINE_STATIC_LOCAL(Vector<PageGroupLoadDeferrer*>, deferrerStack, ());
234     return deferrerStack;
235 }
236
237 // Ensure that the WebDragOperation enum values stay in sync with the original
238 // DragOperation constants.
239 #define COMPILE_ASSERT_MATCHING_ENUM(coreName) \
240     COMPILE_ASSERT(int(coreName) == int(Web##coreName), dummy##coreName)
241 COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone);
242 COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy);
243 COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink);
244 COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric);
245 COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate);
246 COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove);
247 COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete);
248 COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery);
249
250 static const PopupContainerSettings autofillPopupSettings = {
251     false, // setTextOnIndexChange
252     false, // acceptOnAbandon
253     true, // loopSelectionNavigation
254     false // restrictWidthOfListBox (For security reasons show the entire entry
255           // so the user doesn't enter information he did not intend to.)
256 };
257
258 static bool shouldUseExternalPopupMenus = false;
259
260 static int webInputEventKeyStateToPlatformEventKeyState(int webInputEventKeyState)
261 {
262     int platformEventKeyState = 0;
263     if (webInputEventKeyState & WebInputEvent::ShiftKey)
264         platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::ShiftKey;
265     if (webInputEventKeyState & WebInputEvent::ControlKey)
266         platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::CtrlKey;
267     if (webInputEventKeyState & WebInputEvent::AltKey)
268         platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::AltKey;
269     if (webInputEventKeyState & WebInputEvent::MetaKey)
270         platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::MetaKey;
271     return platformEventKeyState;
272 }
273
274 // WebView ----------------------------------------------------------------
275
276 WebView* WebView::create(WebViewClient* client)
277 {
278     // Pass the WebViewImpl's self-reference to the caller.
279     return adoptRef(new WebViewImpl(client)).leakRef();
280 }
281
282 void WebView::setUseExternalPopupMenus(bool useExternalPopupMenus)
283 {
284     shouldUseExternalPopupMenus = useExternalPopupMenus;
285 }
286
287 void WebView::updateVisitedLinkState(unsigned long long linkHash)
288 {
289     Page::visitedStateChanged(PageGroup::pageGroup(pageGroupName), linkHash);
290 }
291
292 void WebView::resetVisitedLinkState()
293 {
294     Page::allVisitedStateChanged(PageGroup::pageGroup(pageGroupName));
295 }
296
297 void WebView::willEnterModalLoop()
298 {
299     PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
300     ASSERT(pageGroup);
301
302     if (pageGroup->pages().isEmpty())
303         pageGroupLoadDeferrerStack().append(static_cast<PageGroupLoadDeferrer*>(0));
304     else {
305         // Pick any page in the page group since we are deferring all pages.
306         pageGroupLoadDeferrerStack().append(new PageGroupLoadDeferrer(*pageGroup->pages().begin(), true));
307     }
308 }
309
310 void WebView::didExitModalLoop()
311 {
312     ASSERT(pageGroupLoadDeferrerStack().size());
313
314     delete pageGroupLoadDeferrerStack().last();
315     pageGroupLoadDeferrerStack().removeLast();
316 }
317
318 void WebViewImpl::initializeMainFrame(WebFrameClient* frameClient)
319 {
320     // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame
321     // and releases that reference once the corresponding Frame is destroyed.
322     RefPtr<WebFrameImpl> frame = WebFrameImpl::create(frameClient);
323
324     frame->initializeAsMainFrame(page());
325
326     // Restrict the access to the local file system
327     // (see WebView.mm WebView::_commonInitializationWithFrameName).
328     SecurityPolicy::setLocalLoadPolicy(SecurityPolicy::AllowLocalLoadsForLocalOnly);
329 }
330
331 void WebViewImpl::initializeHelperPluginFrame(WebFrameClient* client)
332 {
333     RefPtr<WebFrameImpl> frame = WebFrameImpl::create(client);
334 }
335
336 void WebViewImpl::setAutofillClient(WebAutofillClient* autofillClient)
337 {
338     m_autofillClient = autofillClient;
339 }
340
341 void WebViewImpl::setDevToolsAgentClient(WebDevToolsAgentClient* devToolsClient)
342 {
343     if (devToolsClient)
344         m_devToolsAgent = adoptPtr(new WebDevToolsAgentImpl(this, devToolsClient));
345     else
346         m_devToolsAgent.clear();
347 }
348
349 void WebViewImpl::setPermissionClient(WebPermissionClient* permissionClient)
350 {
351     m_permissionClient = permissionClient;
352     m_featureSwitchClient->setPermissionClient(permissionClient);
353 }
354
355 void WebViewImpl::setPrerendererClient(WebPrerendererClient* prerendererClient)
356 {
357     providePrerendererClientTo(m_page.get(), new PrerendererClientImpl(prerendererClient));
358 }
359
360 void WebViewImpl::setSpellCheckClient(WebSpellCheckClient* spellCheckClient)
361 {
362     m_spellCheckClient = spellCheckClient;
363 }
364
365 void WebViewImpl::addTextFieldDecoratorClient(WebTextFieldDecoratorClient* client)
366 {
367     ASSERT(client);
368     // We limit the number of decorators because it affects performance of text
369     // field creation. If you'd like to add more decorators, consider moving
370     // your decorator or existing decorators to WebCore.
371     const unsigned maximumNumberOfDecorators = 8;
372     if (m_textFieldDecorators.size() >= maximumNumberOfDecorators)
373         CRASH();
374     m_textFieldDecorators.append(TextFieldDecoratorImpl::create(client));
375 }
376
377 WebViewImpl::WebViewImpl(WebViewClient* client)
378     : m_client(client)
379     , m_autofillClient(0)
380     , m_permissionClient(0)
381     , m_spellCheckClient(0)
382     , m_chromeClientImpl(this)
383     , m_contextMenuClientImpl(this)
384     , m_dragClientImpl(this)
385     , m_editorClientImpl(this)
386     , m_inspectorClientImpl(this)
387     , m_shouldAutoResize(false)
388     , m_observedNewNavigation(false)
389 #ifndef NDEBUG
390     , m_newNavigationLoader(0)
391 #endif
392     , m_zoomLevel(0)
393     , m_minimumZoomLevel(zoomFactorToZoomLevel(minTextSizeMultiplier))
394     , m_maximumZoomLevel(zoomFactorToZoomLevel(maxTextSizeMultiplier))
395     , m_pageDefinedMinimumPageScaleFactor(-1)
396     , m_pageDefinedMaximumPageScaleFactor(-1)
397     , m_minimumPageScaleFactor(minPageScaleFactor)
398     , m_maximumPageScaleFactor(maxPageScaleFactor)
399     , m_ignoreViewportTagMaximumScale(false)
400     , m_pageScaleFactorIsSet(false)
401     , m_savedPageScaleFactor(0)
402     , m_doubleTapZoomInEffect(false)
403     , m_shouldUseDoubleTapTimeZero(false)
404     , m_contextMenuAllowed(false)
405     , m_doingDragAndDrop(false)
406     , m_ignoreInputEvents(false)
407     , m_suppressNextKeypressEvent(false)
408     , m_initialNavigationPolicy(WebNavigationPolicyIgnore)
409     , m_imeAcceptEvents(true)
410     , m_operationsAllowed(WebDragOperationNone)
411     , m_dragOperation(WebDragOperationNone)
412     , m_featureSwitchClient(adoptPtr(new ContextFeaturesClientImpl()))
413     , m_autofillPopupShowing(false)
414     , m_autofillPopup(0)
415     , m_isTransparent(false)
416     , m_tabsToLinks(false)
417     , m_isCancelingFullScreen(false)
418     , m_benchmarkSupport(this)
419 #if USE(ACCELERATED_COMPOSITING)
420     , m_layerTreeView(0)
421     , m_ownsLayerTreeView(false)
422     , m_rootLayer(0)
423     , m_rootGraphicsLayer(0)
424     , m_isAcceleratedCompositingActive(false)
425     , m_layerTreeViewCommitsDeferred(false)
426     , m_compositorCreationFailed(false)
427     , m_recreatingGraphicsContext(false)
428     , m_compositorSurfaceReady(false)
429     , m_inputHandlerIdentifier(-1)
430 #endif
431 #if ENABLE(INPUT_SPEECH)
432     , m_speechInputClient(SpeechInputClientImpl::create(client))
433 #endif
434 #if ENABLE(SCRIPTED_SPEECH)
435     , m_speechRecognitionClient(SpeechRecognitionClientProxy::create(client ? client->speechRecognizer() : 0))
436 #endif
437     , m_deviceOrientationClientProxy(adoptPtr(new DeviceOrientationClientProxy(client ? client->deviceOrientationClient() : 0)))
438     , m_geolocationClientProxy(adoptPtr(new GeolocationClientProxy(client ? client->geolocationClient() : 0)))
439 #if ENABLE(BATTERY_STATUS)
440     , m_batteryClient(adoptPtr(new BatteryClientImpl(client ? client->batteryStatusClient() : 0)))
441 #endif
442     , m_emulatedTextZoomFactor(1)
443 #if ENABLE(MEDIA_STREAM)
444     , m_userMediaClientImpl(this)
445 #endif
446 #if ENABLE(NAVIGATOR_CONTENT_UTILS)
447     , m_navigatorContentUtilsClient(NavigatorContentUtilsClientImpl::create(this))
448 #endif
449     , m_flingModifier(0)
450     , m_flingSourceDevice(false)
451     , m_validationMessage(ValidationMessageClientImpl::create(*client))
452     , m_suppressInvalidations(false)
453     , m_showFPSCounter(false)
454     , m_showPaintRects(false)
455     , m_continuousPaintingEnabled(false)
456 {
457     // WebKit/win/WebView.cpp does the same thing, except they call the
458     // KJS specific wrapper around this method. We need to have threading
459     // initialized because CollatorICU requires it.
460     WTF::initializeThreading();
461     WTF::initializeMainThread();
462
463     Page::PageClients pageClients;
464     pageClients.chromeClient = &m_chromeClientImpl;
465     pageClients.contextMenuClient = &m_contextMenuClientImpl;
466     pageClients.editorClient = &m_editorClientImpl;
467     pageClients.dragClient = &m_dragClientImpl;
468     pageClients.inspectorClient = &m_inspectorClientImpl;
469     pageClients.backForwardClient = BackForwardListChromium::create(this);
470     // FIXME: Set pageClients.validationMessageClient when Chromium-side implementation is done.
471
472     m_page = adoptPtr(new Page(pageClients));
473 #if ENABLE(MEDIA_STREAM)
474     provideUserMediaTo(m_page.get(), &m_userMediaClientImpl);
475 #endif
476 #if ENABLE(INPUT_SPEECH)
477     provideSpeechInputTo(m_page.get(), m_speechInputClient.get());
478 #endif
479 #if ENABLE(SCRIPTED_SPEECH)
480     provideSpeechRecognitionTo(m_page.get(), m_speechRecognitionClient.get());
481 #endif
482 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
483     provideNotification(m_page.get(), notificationPresenterImpl());
484 #endif
485 #if ENABLE(NAVIGATOR_CONTENT_UTILS)
486     provideNavigatorContentUtilsTo(m_page.get(), m_navigatorContentUtilsClient.get());
487 #endif
488
489     provideContextFeaturesTo(m_page.get(), m_featureSwitchClient.get());
490     provideDeviceOrientationTo(m_page.get(), m_deviceOrientationClientProxy.get());
491     provideGeolocationTo(m_page.get(), m_geolocationClientProxy.get());
492     m_geolocationClientProxy->setController(GeolocationController::from(m_page.get()));
493
494 #if ENABLE(BATTERY_STATUS)
495     provideBatteryTo(m_page.get(), m_batteryClient.get());
496     m_batteryClient->setController(BatteryController::from(m_page.get()));
497 #endif
498
499     m_page->setGroupName(pageGroupName);
500
501     unsigned layoutMilestones = DidFirstLayout | DidFirstVisuallyNonEmptyLayout;
502     m_page->addLayoutMilestones(static_cast<LayoutMilestones>(layoutMilestones));
503
504 #if ENABLE(PAGE_VISIBILITY_API)
505     if (m_client)
506         setVisibilityState(m_client->visibilityState(), true);
507 #endif
508
509     m_inspectorSettingsMap = adoptPtr(new SettingsMap);
510 }
511
512 WebViewImpl::~WebViewImpl()
513 {
514     if (m_ownsLayerTreeView)
515         delete m_layerTreeView;
516     ASSERT(!m_page);
517 }
518
519 RenderTheme* WebViewImpl::theme() const
520 {
521     return m_page ? m_page->theme() : RenderTheme::defaultTheme().get();
522 }
523
524 WebFrameImpl* WebViewImpl::mainFrameImpl()
525 {
526     return m_page ? WebFrameImpl::fromFrame(m_page->mainFrame()) : 0;
527 }
528
529 bool WebViewImpl::tabKeyCyclesThroughElements() const
530 {
531     ASSERT(m_page);
532     return m_page->tabKeyCyclesThroughElements();
533 }
534
535 void WebViewImpl::setTabKeyCyclesThroughElements(bool value)
536 {
537     if (m_page)
538         m_page->setTabKeyCyclesThroughElements(value);
539 }
540
541 void WebViewImpl::handleMouseLeave(Frame& mainFrame, const WebMouseEvent& event)
542 {
543     m_client->setMouseOverURL(WebURL());
544     PageWidgetEventHandler::handleMouseLeave(mainFrame, event);
545 }
546
547 void WebViewImpl::handleMouseDown(Frame& mainFrame, const WebMouseEvent& event)
548 {
549     // If there is a popup open, close it as the user is clicking on the page (outside of the
550     // popup). We also save it so we can prevent a click on an element from immediately
551     // reopening the same popup.
552     RefPtr<WebCore::PopupContainer> selectPopup;
553 #if ENABLE(PAGE_POPUP)
554     RefPtr<WebPagePopupImpl> pagePopup;
555 #endif
556     if (event.button == WebMouseEvent::ButtonLeft) {
557         selectPopup = m_selectPopup;
558 #if ENABLE(PAGE_POPUP)
559         pagePopup = m_pagePopup;
560 #endif
561         hidePopups();
562         ASSERT(!m_selectPopup);
563 #if ENABLE(PAGE_POPUP)
564         ASSERT(!m_pagePopup);
565 #endif
566     }
567
568     m_lastMouseDownPoint = WebPoint(event.x, event.y);
569
570     if (event.button == WebMouseEvent::ButtonLeft) {
571         IntPoint point(event.x, event.y);
572         point = m_page->mainFrame()->view()->windowToContents(point);
573         HitTestResult result(m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, false));
574         Node* hitNode = result.innerNonSharedNode();
575
576         // Take capture on a mouse down on a plugin so we can send it mouse events.
577         if (hitNode && hitNode->renderer() && hitNode->renderer()->isEmbeddedObject())
578             m_mouseCaptureNode = hitNode;
579     }
580
581     PageWidgetEventHandler::handleMouseDown(mainFrame, event);
582
583     if (m_selectPopup && m_selectPopup == selectPopup) {
584         // That click triggered a select popup which is the same as the one that
585         // was showing before the click.  It means the user clicked the select
586         // while the popup was showing, and as a result we first closed then
587         // immediately reopened the select popup.  It needs to be closed.
588         hideSelectPopup();
589     }
590
591 #if ENABLE(PAGE_POPUP)
592     if (m_pagePopup && pagePopup && m_pagePopup->hasSamePopupClient(pagePopup.get())) {
593         // That click triggered a page popup that is the same as the one we just closed.
594         // It needs to be closed.
595         closePagePopup(m_pagePopup.get());
596     }
597 #endif
598
599     // Dispatch the contextmenu event regardless of if the click was swallowed.
600     // On Windows, we handle it on mouse up, not down.
601 #if OS(DARWIN)
602     if (event.button == WebMouseEvent::ButtonRight
603         || (event.button == WebMouseEvent::ButtonLeft
604             && event.modifiers & WebMouseEvent::ControlKey))
605         mouseContextMenu(event);
606 #elif OS(UNIX) || OS(ANDROID)
607     if (event.button == WebMouseEvent::ButtonRight)
608         mouseContextMenu(event);
609 #endif
610 }
611
612 void WebViewImpl::mouseContextMenu(const WebMouseEvent& event)
613 {
614     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
615         return;
616
617     m_page->contextMenuController()->clearContextMenu();
618
619     PlatformMouseEventBuilder pme(mainFrameImpl()->frameView(), event);
620
621     // Find the right target frame. See issue 1186900.
622     HitTestResult result = hitTestResultForWindowPos(pme.position());
623     Frame* targetFrame;
624     if (result.innerNonSharedNode())
625         targetFrame = result.innerNonSharedNode()->document()->frame();
626     else
627         targetFrame = m_page->focusController()->focusedOrMainFrame();
628
629 #if OS(WINDOWS)
630     targetFrame->view()->setCursor(pointerCursor());
631 #endif
632
633     m_contextMenuAllowed = true;
634     targetFrame->eventHandler()->sendContextMenuEvent(pme);
635     m_contextMenuAllowed = false;
636     // Actually showing the context menu is handled by the ContextMenuClient
637     // implementation...
638 }
639
640 void WebViewImpl::handleMouseUp(Frame& mainFrame, const WebMouseEvent& event)
641 {
642     PageWidgetEventHandler::handleMouseUp(mainFrame, event);
643
644 #if OS(WINDOWS)
645     // Dispatch the contextmenu event regardless of if the click was swallowed.
646     // On Mac/Linux, we handle it on mouse down, not up.
647     if (event.button == WebMouseEvent::ButtonRight)
648         mouseContextMenu(event);
649 #endif
650 }
651
652 bool WebViewImpl::handleMouseWheel(Frame& mainFrame, const WebMouseWheelEvent& event)
653 {
654     hidePopups();
655     return PageWidgetEventHandler::handleMouseWheel(mainFrame, event);
656 }
657
658 void WebViewImpl::scrollBy(const WebPoint& delta)
659 {
660     if (m_flingSourceDevice == WebGestureEvent::Touchpad) {
661         WebMouseWheelEvent syntheticWheel;
662         const float tickDivisor = WebCore::WheelEvent::tickMultiplier;
663
664         syntheticWheel.deltaX = delta.x;
665         syntheticWheel.deltaY = delta.y;
666         syntheticWheel.wheelTicksX = delta.x / tickDivisor;
667         syntheticWheel.wheelTicksY = delta.y / tickDivisor;
668         syntheticWheel.hasPreciseScrollingDeltas = true;
669         syntheticWheel.x = m_positionOnFlingStart.x;
670         syntheticWheel.y = m_positionOnFlingStart.y;
671         syntheticWheel.globalX = m_globalPositionOnFlingStart.x;
672         syntheticWheel.globalY = m_globalPositionOnFlingStart.y;
673         syntheticWheel.modifiers = m_flingModifier;
674
675         if (m_page && m_page->mainFrame() && m_page->mainFrame()->view())
676             handleMouseWheel(*m_page->mainFrame(), syntheticWheel);
677     } else {
678         WebGestureEvent syntheticGestureEvent;
679
680         syntheticGestureEvent.type = WebInputEvent::GestureScrollUpdate;
681         syntheticGestureEvent.data.scrollUpdate.deltaX = delta.x;
682         syntheticGestureEvent.data.scrollUpdate.deltaY = delta.y;
683         syntheticGestureEvent.x = m_positionOnFlingStart.x;
684         syntheticGestureEvent.y = m_positionOnFlingStart.y;
685         syntheticGestureEvent.globalX = m_globalPositionOnFlingStart.x;
686         syntheticGestureEvent.globalY = m_globalPositionOnFlingStart.y;
687         syntheticGestureEvent.modifiers = m_flingModifier;
688         syntheticGestureEvent.sourceDevice = WebGestureEvent::Touchscreen;
689
690         if (m_page && m_page->mainFrame() && m_page->mainFrame()->view())
691             handleGestureEvent(syntheticGestureEvent);
692     }
693 }
694
695 #if ENABLE(GESTURE_EVENTS)
696 bool WebViewImpl::handleGestureEvent(const WebGestureEvent& event)
697 {
698     bool eventSwallowed = false;
699     bool eventCancelled = false; // for disambiguation
700
701     // Handle link highlighting outside the main switch to avoid getting lost in the
702     // complicated set of cases handled below.
703     switch (event.type) {
704     case WebInputEvent::GestureTapDown:
705         // Queue a highlight animation, then hand off to regular handler.
706 #if OS(LINUX)
707         if (settingsImpl()->gestureTapHighlightEnabled())
708             enableTouchHighlight(event);
709 #endif
710         break;
711     case WebInputEvent::GestureTapCancel:
712     case WebInputEvent::GestureTap:
713     case WebInputEvent::GestureLongPress:
714         if (m_linkHighlight)
715             m_linkHighlight->startHighlightAnimationIfNeeded();
716         break;
717     default:
718         break;
719     }
720
721     switch (event.type) {
722     case WebInputEvent::GestureFlingStart: {
723         if (mainFrameImpl()->frame()->eventHandler()->isScrollbarHandlingGestures())
724             break;
725         m_client->cancelScheduledContentIntents();
726         m_positionOnFlingStart = WebPoint(event.x, event.y);
727         m_globalPositionOnFlingStart = WebPoint(event.globalX, event.globalY);
728         m_flingModifier = event.modifiers;
729         m_flingSourceDevice = event.sourceDevice;
730         OwnPtr<WebGestureCurve> flingCurve = adoptPtr(Platform::current()->createFlingAnimationCurve(event.sourceDevice, WebFloatPoint(event.data.flingStart.velocityX, event.data.flingStart.velocityY), WebSize()));
731         m_gestureAnimation = WebActiveGestureAnimation::createAtAnimationStart(flingCurve.release(), this);
732         scheduleAnimation();
733         eventSwallowed = true;
734         break;
735     }
736     case WebInputEvent::GestureFlingCancel:
737         if (m_gestureAnimation) {
738             m_gestureAnimation.clear();
739             if (m_layerTreeView)
740                 m_layerTreeView->didStopFlinging();
741             eventSwallowed = true;
742         }
743         break;
744     case WebInputEvent::GestureTap: {
745         m_client->cancelScheduledContentIntents();
746         if (detectContentOnTouch(WebPoint(event.x, event.y))) {
747             eventSwallowed = true;
748             break;
749         }
750
751         RefPtr<WebCore::PopupContainer> selectPopup;
752         selectPopup = m_selectPopup;
753         hideSelectPopup();
754         ASSERT(!m_selectPopup);
755
756         if (event.data.tap.width > 0) {
757             IntRect boundingBox(event.x - event.data.tap.width / 2, event.y - event.data.tap.height / 2, event.data.tap.width, event.data.tap.height);
758             Vector<IntRect> goodTargets;
759             findGoodTouchTargets(boundingBox, mainFrameImpl()->frame(), pageScaleFactor(), goodTargets);
760             // FIXME: replace touch adjustment code when numberOfGoodTargets == 1?
761             // Single candidate case is currently handled by: https://bugs.webkit.org/show_bug.cgi?id=85101
762             if (goodTargets.size() >= 2 && m_client && m_client->didTapMultipleTargets(event, goodTargets)) {
763                 eventSwallowed = true;
764                 eventCancelled = true;
765                 break;
766             }
767         }
768
769         PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
770         eventSwallowed = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
771
772         if (m_selectPopup && m_selectPopup == selectPopup) {
773             // That tap triggered a select popup which is the same as the one that
774             // was showing before the tap. It means the user tapped the select
775             // while the popup was showing, and as a result we first closed then
776             // immediately reopened the select popup. It needs to be closed.
777             hideSelectPopup();
778         }
779
780         break;
781     }
782     case WebInputEvent::GestureTwoFingerTap:
783     case WebInputEvent::GestureLongPress:
784     case WebInputEvent::GestureLongTap: {
785         if (!mainFrameImpl() || !mainFrameImpl()->frameView())
786             break;
787
788         m_client->cancelScheduledContentIntents();
789         m_page->contextMenuController()->clearContextMenu();
790         m_contextMenuAllowed = true;
791         PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
792         eventSwallowed = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
793         m_contextMenuAllowed = false;
794
795         break;
796     }
797     case WebInputEvent::GestureTapDown: {
798         m_client->cancelScheduledContentIntents();
799         PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
800         eventSwallowed = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
801         break;
802     }
803     case WebInputEvent::GestureDoubleTap:
804         if (m_webSettings->doubleTapToZoomEnabled() && m_minimumPageScaleFactor != m_maximumPageScaleFactor) {
805             m_client->cancelScheduledContentIntents();
806             animateZoomAroundPoint(WebPoint(event.x, event.y), DoubleTap);
807             eventSwallowed = true;
808             break;
809         }
810     case WebInputEvent::GestureScrollBegin:
811     case WebInputEvent::GesturePinchBegin:
812         m_client->cancelScheduledContentIntents();
813     case WebInputEvent::GestureScrollEnd:
814     case WebInputEvent::GestureScrollUpdate:
815     case WebInputEvent::GestureTapCancel:
816     case WebInputEvent::GesturePinchEnd:
817     case WebInputEvent::GesturePinchUpdate: {
818         PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
819         eventSwallowed = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
820         break;
821     }
822     default:
823         ASSERT_NOT_REACHED();
824     }
825     m_client->didHandleGestureEvent(event, eventCancelled);
826     return eventSwallowed;
827 }
828
829 void WebViewImpl::transferActiveWheelFlingAnimation(const WebActiveWheelFlingParameters& parameters)
830 {
831     TRACE_EVENT0("webkit", "WebViewImpl::transferActiveWheelFlingAnimation");
832     ASSERT(!m_gestureAnimation);
833     m_positionOnFlingStart = parameters.point;
834     m_globalPositionOnFlingStart = parameters.globalPoint;
835     m_flingModifier = parameters.modifiers;
836     OwnPtr<WebGestureCurve> curve = adoptPtr(Platform::current()->createFlingAnimationCurve(parameters.sourceDevice, WebFloatPoint(parameters.delta), parameters.cumulativeScroll));
837     m_gestureAnimation = WebActiveGestureAnimation::createWithTimeOffset(curve.release(), this, parameters.startTime);
838     scheduleAnimation();
839 }
840
841 void WebViewImpl::renderingStats(WebRenderingStats& stats) const
842 {
843     if (m_layerTreeView)
844         m_layerTreeView->renderingStats(stats);
845 }
846
847 void WebViewImpl::startPageScaleAnimation(const IntPoint& targetPosition, bool useAnchor, float newScale, double durationInSeconds)
848 {
849     WebPoint clampedPoint = targetPosition;
850     if (!useAnchor)
851         clampedPoint = clampOffsetAtScale(targetPosition, newScale);
852     if ((!durationInSeconds && !useAnchor) || m_shouldUseDoubleTapTimeZero) {
853         setPageScaleFactor(newScale, clampedPoint);
854         return;
855     }
856     if (!m_layerTreeView)
857         return;
858
859     m_layerTreeView->startPageScaleAnimation(targetPosition, useAnchor, newScale, durationInSeconds);
860 }
861 #endif
862
863 WebViewBenchmarkSupport* WebViewImpl::benchmarkSupport()
864 {
865     return &m_benchmarkSupport;
866 }
867
868 void WebViewImpl::setShowFPSCounter(bool show)
869 {
870     if (isAcceleratedCompositingActive()) {
871         TRACE_EVENT0("webkit", "WebViewImpl::setShowFPSCounter");
872         m_layerTreeView->setShowFPSCounter(show);
873     }
874     m_showFPSCounter = show;
875 }
876
877 void WebViewImpl::setShowPaintRects(bool show)
878 {
879     if (isAcceleratedCompositingActive()) {
880         TRACE_EVENT0("webkit", "WebViewImpl::setShowPaintRects");
881         m_layerTreeView->setShowPaintRects(show);
882     }
883     m_showPaintRects = show;
884 }
885
886 bool WebViewImpl::handleKeyEvent(const WebKeyboardEvent& event)
887 {
888     ASSERT((event.type == WebInputEvent::RawKeyDown)
889         || (event.type == WebInputEvent::KeyDown)
890         || (event.type == WebInputEvent::KeyUp));
891
892     // Halt an in-progress fling on a key event.
893     if (m_gestureAnimation) {
894         m_gestureAnimation.clear();
895         if (m_layerTreeView)
896             m_layerTreeView->didStopFlinging();
897     }
898
899     // Please refer to the comments explaining the m_suppressNextKeypressEvent
900     // member.
901     // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
902     // Webkit. A keyDown event is typically associated with a keyPress(char)
903     // event and a keyUp event. We reset this flag here as this is a new keyDown
904     // event.
905     m_suppressNextKeypressEvent = false;
906
907     // If there is a select popup, it should be the one processing the event,
908     // not the page.
909     if (m_selectPopup)
910         return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
911 #if ENABLE(PAGE_POPUP)
912     if (m_pagePopup) {
913         m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
914         // We need to ignore the next Char event after this otherwise pressing
915         // enter when selecting an item in the popup will go to the page.
916         if (WebInputEvent::RawKeyDown == event.type)
917             m_suppressNextKeypressEvent = true;
918         return true;
919     }
920 #endif
921
922     // Give Autocomplete a chance to consume the key events it is interested in.
923     if (autocompleteHandleKeyEvent(event))
924         return true;
925
926     RefPtr<Frame> frame = focusedWebCoreFrame();
927     if (!frame)
928         return false;
929
930     EventHandler* handler = frame->eventHandler();
931     if (!handler)
932         return keyEventDefault(event);
933
934 #if !OS(DARWIN)
935     const WebInputEvent::Type contextMenuTriggeringEventType =
936 #if OS(WINDOWS)
937         WebInputEvent::KeyUp;
938 #elif OS(UNIX)
939         WebInputEvent::RawKeyDown;
940 #endif
941
942     bool isUnmodifiedMenuKey = !(event.modifiers & WebInputEvent::InputModifiers) && event.windowsKeyCode == VKEY_APPS;
943     bool isShiftF10 = event.modifiers == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10;
944     if ((isUnmodifiedMenuKey || isShiftF10) && event.type == contextMenuTriggeringEventType) {
945         sendContextMenuEvent(event);
946         return true;
947     }
948 #endif // !OS(DARWIN)
949
950     PlatformKeyboardEventBuilder evt(event);
951
952     if (handler->keyEvent(evt)) {
953         if (WebInputEvent::RawKeyDown == event.type) {
954             // Suppress the next keypress event unless the focused node is a plug-in node.
955             // (Flash needs these keypress events to handle non-US keyboards.)
956             Node* node = focusedWebCoreNode();
957             if (!node || !node->renderer() || !node->renderer()->isEmbeddedObject())
958                 m_suppressNextKeypressEvent = true;
959         }
960         return true;
961     }
962
963     return keyEventDefault(event);
964 }
965
966 bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event)
967 {
968     if (!m_autofillPopupShowing
969         // Home and End should be left to the text field to process.
970         || event.windowsKeyCode == VKEY_HOME
971         || event.windowsKeyCode == VKEY_END)
972       return false;
973
974     // Pressing delete triggers the removal of the selected suggestion from the DB.
975     if (event.windowsKeyCode == VKEY_DELETE
976         && m_autofillPopup->selectedIndex() != -1) {
977         Node* node = focusedWebCoreNode();
978         if (!node || (node->nodeType() != Node::ELEMENT_NODE)) {
979             ASSERT_NOT_REACHED();
980             return false;
981         }
982         Element* element = static_cast<Element*>(node);
983         if (!element->hasLocalName(HTMLNames::inputTag)) {
984             ASSERT_NOT_REACHED();
985             return false;
986         }
987
988         int selectedIndex = m_autofillPopup->selectedIndex();
989
990         if (!m_autofillPopupClient->canRemoveSuggestionAtIndex(selectedIndex))
991             return false;
992
993         WebString name = WebInputElement(static_cast<HTMLInputElement*>(element)).nameForAutofill();
994         WebString value = m_autofillPopupClient->itemText(selectedIndex);
995         m_autofillClient->removeAutocompleteSuggestion(name, value);
996         // Update the entries in the currently showing popup to reflect the
997         // deletion.
998         m_autofillPopupClient->removeSuggestionAtIndex(selectedIndex);
999         refreshAutofillPopup();
1000         return false;
1001     }
1002
1003     if (!m_autofillPopup->isInterestedInEventForKey(event.windowsKeyCode))
1004         return false;
1005
1006     if (m_autofillPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) {
1007         // We need to ignore the next Char event after this otherwise pressing
1008         // enter when selecting an item in the menu will go to the page.
1009         if (WebInputEvent::RawKeyDown == event.type)
1010             m_suppressNextKeypressEvent = true;
1011         return true;
1012     }
1013
1014     return false;
1015 }
1016
1017 bool WebViewImpl::handleCharEvent(const WebKeyboardEvent& event)
1018 {
1019     ASSERT(event.type == WebInputEvent::Char);
1020
1021     // Please refer to the comments explaining the m_suppressNextKeypressEvent
1022     // member.  The m_suppressNextKeypressEvent is set if the KeyDown is
1023     // handled by Webkit. A keyDown event is typically associated with a
1024     // keyPress(char) event and a keyUp event. We reset this flag here as it
1025     // only applies to the current keyPress event.
1026     bool suppress = m_suppressNextKeypressEvent;
1027     m_suppressNextKeypressEvent = false;
1028
1029     // If there is a select popup, it should be the one processing the event,
1030     // not the page.
1031     if (m_selectPopup)
1032         return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
1033 #if ENABLE(PAGE_POPUP)
1034     if (m_pagePopup)
1035         return m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
1036 #endif
1037
1038     Frame* frame = focusedWebCoreFrame();
1039     if (!frame)
1040         return suppress;
1041
1042     EventHandler* handler = frame->eventHandler();
1043     if (!handler)
1044         return suppress || keyEventDefault(event);
1045
1046     PlatformKeyboardEventBuilder evt(event);
1047     if (!evt.isCharacterKey())
1048         return true;
1049
1050     // Accesskeys are triggered by char events and can't be suppressed.
1051     if (handler->handleAccessKey(evt))
1052         return true;
1053
1054     // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
1055     // the eventHandler::keyEvent. We mimic this behavior on all platforms since
1056     // for now we are converting other platform's key events to windows key
1057     // events.
1058     if (evt.isSystemKey())
1059         return false;
1060
1061     if (!suppress && !handler->keyEvent(evt))
1062         return keyEventDefault(event);
1063
1064     return true;
1065 }
1066
1067 #if ENABLE(GESTURE_EVENTS)
1068 WebRect WebViewImpl::computeBlockBounds(const WebRect& rect, AutoZoomType zoomType)
1069 {
1070     if (!mainFrameImpl())
1071         return WebRect();
1072
1073     // Use the rect-based hit test to find the node.
1074     IntPoint point = mainFrameImpl()->frameView()->windowToContents(IntPoint(rect.x, rect.y));
1075     HitTestResult result = mainFrameImpl()->frame()->eventHandler()->hitTestResultAtPoint(point,
1076             false, zoomType == FindInPage, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly,
1077             IntSize(rect.width, rect.height));
1078
1079     Node* node = result.innerNonSharedNode();
1080     if (!node)
1081         return WebRect();
1082
1083     // Find the block type node based on the hit node.
1084     while (node && (!node->renderer() || node->renderer()->isInline()))
1085         node = node->parentNode();
1086
1087     // Return the bounding box in the window coordinate system.
1088     if (node) {
1089         IntRect rect = node->Node::pixelSnappedBoundingBox();
1090         Frame* frame = node->document()->frame();
1091         return frame->view()->contentsToWindow(rect);
1092     }
1093     return WebRect();
1094 }
1095
1096 WebRect WebViewImpl::widenRectWithinPageBounds(const WebRect& source, int targetMargin, int minimumMargin)
1097 {
1098     WebSize maxSize;
1099     if (mainFrame())
1100         maxSize = mainFrame()->contentsSize();
1101     IntSize scrollOffset;
1102     if (mainFrame())
1103         scrollOffset = mainFrame()->scrollOffset();
1104     int leftMargin = targetMargin;
1105     int rightMargin = targetMargin;
1106
1107     const int absoluteSourceX = source.x + scrollOffset.width();
1108     if (leftMargin > absoluteSourceX) {
1109         leftMargin = absoluteSourceX;
1110         rightMargin = max(leftMargin, minimumMargin);
1111     }
1112
1113     const int maximumRightMargin = maxSize.width - (source.width + absoluteSourceX);
1114     if (rightMargin > maximumRightMargin) {
1115         rightMargin = maximumRightMargin;
1116         leftMargin = min(leftMargin, max(rightMargin, minimumMargin));
1117     }
1118
1119     const int newWidth = source.width + leftMargin + rightMargin;
1120     const int newX = source.x - leftMargin;
1121
1122     ASSERT(newWidth >= 0);
1123     ASSERT(scrollOffset.width() + newX + newWidth <= maxSize.width);
1124
1125     return WebRect(newX, source.y, newWidth, source.height);
1126 }
1127
1128 void WebViewImpl::shouldUseAnimateDoubleTapTimeZeroForTesting(bool setToZero)
1129 {
1130     m_shouldUseDoubleTapTimeZero = setToZero;
1131 }
1132
1133 void WebViewImpl::computeScaleAndScrollForHitRect(const WebRect& hitRect, AutoZoomType zoomType, float& scale, WebPoint& scroll, bool& isAnchor)
1134 {
1135     scale = pageScaleFactor();
1136     scroll.x = scroll.y = 0;
1137     WebRect targetRect = hitRect;
1138     // Padding only depends on page scale when triggered by manually tapping
1139     int padding = (zoomType == DoubleTap) ? touchPointPadding : nonUserInitiatedPointPadding;
1140     if (targetRect.isEmpty())
1141         targetRect.width = targetRect.height = padding;
1142     WebRect rect = computeBlockBounds(targetRect, zoomType);
1143     if (zoomType == FindInPage && rect.isEmpty()) {
1144         // Keep current scale (no need to scroll as x,y will normally already
1145         // be visible). FIXME: Revisit this if it isn't always true.
1146         return;
1147     }
1148
1149     bool scaleUnchanged = true;
1150     if (!rect.isEmpty()) {
1151         // Pages should be as legible as on desktop when at dpi scale, so no
1152         // need to zoom in further when automatically determining zoom level
1153         // (after double tap, find in page, etc), though the user should still
1154         // be allowed to manually pinch zoom in further if they desire.
1155         const float defaultScaleWhenAlreadyLegible = m_minimumPageScaleFactor * doubleTapZoomAlreadyLegibleRatio;
1156         float legibleScale = deviceScaleFactor();
1157 #if ENABLE(TEXT_AUTOSIZING)
1158         if (page() && page()->settings())
1159             legibleScale *= page()->settings()->textAutosizingFontScaleFactor();
1160 #endif
1161         if (legibleScale < defaultScaleWhenAlreadyLegible)
1162             legibleScale = (scale == m_minimumPageScaleFactor) ? defaultScaleWhenAlreadyLegible : m_minimumPageScaleFactor;
1163
1164         const float defaultMargin = doubleTapZoomContentDefaultMargin * deviceScaleFactor();
1165         const float minimumMargin = doubleTapZoomContentMinimumMargin * deviceScaleFactor();
1166         // We want the margins to have the same physical size, which means we
1167         // need to express them in post-scale size. To do that we'd need to know
1168         // the scale we're scaling to, but that depends on the margins. Instead
1169         // we express them as a fraction of the target rectangle: this will be
1170         // correct if we end up fully zooming to it, and won't matter if we
1171         // don't.
1172         rect = widenRectWithinPageBounds(rect,
1173                 static_cast<int>(defaultMargin * rect.width / m_size.width),
1174                 static_cast<int>(minimumMargin * rect.width / m_size.width));
1175         // Fit block to screen, respecting limits.
1176         scale *= static_cast<float>(m_size.width) / rect.width;
1177         scale = min(scale, legibleScale);
1178         scale = clampPageScaleFactorToLimits(scale);
1179
1180         scaleUnchanged = fabs(pageScaleFactor() - scale) < minScaleDifference;
1181     }
1182
1183     if (zoomType == DoubleTap && (rect.isEmpty() || scaleUnchanged || m_doubleTapZoomInEffect)) {
1184         // Zoom out to minimum scale.
1185         scale = m_minimumPageScaleFactor;
1186         scroll = WebPoint(hitRect.x, hitRect.y);
1187         isAnchor = true;
1188         m_doubleTapZoomInEffect = false;
1189     } else {
1190         if (zoomType == DoubleTap && scale != m_minimumPageScaleFactor)
1191             m_doubleTapZoomInEffect = true;
1192         else
1193             m_doubleTapZoomInEffect = false;
1194         // FIXME: If this is being called for auto zoom during find in page,
1195         // then if the user manually zooms in it'd be nice to preserve the
1196         // relative increase in zoom they caused (if they zoom out then it's ok
1197         // to zoom them back in again). This isn't compatible with our current
1198         // double-tap zoom strategy (fitting the containing block to the screen)
1199         // though.
1200
1201         float screenHeight = m_size.height / scale * pageScaleFactor();
1202         float screenWidth = m_size.width / scale * pageScaleFactor();
1203
1204         // Scroll to vertically align the block.
1205         if (rect.height < screenHeight) {
1206             // Vertically center short blocks.
1207             rect.y -= 0.5 * (screenHeight - rect.height);
1208         } else {
1209             // Ensure position we're zooming to (+ padding) isn't off the bottom of
1210             // the screen.
1211             rect.y = max<float>(rect.y, hitRect.y + padding - screenHeight);
1212         } // Otherwise top align the block.
1213
1214         // Do the same thing for horizontal alignment.
1215         if (rect.width < screenWidth)
1216             rect.x -= 0.5 * (screenWidth - rect.width);
1217         else
1218             rect.x = max<float>(rect.x, hitRect.x + padding - screenWidth);
1219         scroll.x = rect.x;
1220         scroll.y = rect.y;
1221         isAnchor = false;
1222     }
1223
1224     scale = clampPageScaleFactorToLimits(scale);
1225     scroll = mainFrameImpl()->frameView()->windowToContents(scroll);
1226     float scaleDelta = scale / pageScaleFactor();
1227     scroll = WebPoint(scroll.x * scaleDelta, scroll.y * scaleDelta);
1228     if (!isAnchor)
1229         scroll = clampOffsetAtScale(scroll, scale);
1230 }
1231
1232 static bool invokesHandCursor(Node* node, bool shiftKey, Frame* frame)
1233 {
1234     if (!node || !node->renderer())
1235         return false;
1236
1237     ECursor cursor = node->renderer()->style()->cursor();
1238     return cursor == CURSOR_POINTER
1239         || (cursor == CURSOR_AUTO && frame->eventHandler()->useHandCursor(node, node->isLink(), shiftKey));
1240 }
1241
1242 Node* WebViewImpl::bestTouchLinkNode(const WebGestureEvent& touchEvent)
1243 {
1244     if (!m_page || !m_page->mainFrame())
1245         return 0;
1246
1247     Node* bestTouchNode = 0;
1248
1249     IntSize touchEventSearchRegionSize(touchEvent.data.tapDown.width / 2, touchEvent.data.tapDown.height / 2);
1250     IntPoint touchEventLocation(touchEvent.x, touchEvent.y);
1251 #if ENABLE(TOUCH_ADJUSTMENT)
1252     m_page->mainFrame()->eventHandler()->adjustGesturePosition(PlatformGestureEventBuilder(mainFrameImpl()->frameView(), touchEvent), touchEventLocation);
1253 #endif
1254
1255     IntPoint hitTestPoint = m_page->mainFrame()->view()->windowToContents(touchEventLocation);
1256     HitTestResult result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(
1257         hitTestPoint, false, false, DontHitTestScrollbars, HitTestRequest::TouchEvent);
1258     bestTouchNode = result.targetNode();
1259
1260     // Make sure our highlight candidate uses a hand cursor as a heuristic to
1261     // choose appropriate targets.
1262     bool shiftKey = touchEvent.modifiers & WebGestureEvent::ShiftKey;
1263     while (bestTouchNode && !invokesHandCursor(bestTouchNode, shiftKey, m_page->mainFrame()))
1264         bestTouchNode = bestTouchNode->parentNode();
1265
1266     // We should pick the largest enclosing node with hand cursor set.
1267     while (bestTouchNode && bestTouchNode->parentNode() && invokesHandCursor(bestTouchNode->parentNode(), shiftKey, m_page->mainFrame()))
1268         bestTouchNode = bestTouchNode->parentNode();
1269
1270     return bestTouchNode;
1271 }
1272
1273 void WebViewImpl::enableTouchHighlight(const WebGestureEvent& touchEvent)
1274 {
1275     // Always clear any existing highlight when this is invoked, even if we don't get a new target to highlight.
1276     m_linkHighlight.clear();
1277
1278     Node* touchNode = bestTouchLinkNode(touchEvent);
1279
1280     if (!touchNode || !touchNode->renderer() || !touchNode->renderer()->enclosingLayer())
1281         return;
1282
1283     Color highlightColor = touchNode->renderer()->style()->tapHighlightColor();
1284     // Safari documentation for -webkit-tap-highlight-color says if the specified color has 0 alpha,
1285     // then tap highlighting is disabled.
1286     // http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safaricssref/articles/standardcssproperties.html
1287     if (!highlightColor.alpha())
1288         return;
1289
1290     m_linkHighlight = LinkHighlight::create(touchNode, this);
1291 }
1292
1293 #endif
1294
1295 void WebViewImpl::animateZoomAroundPoint(const IntPoint& point, AutoZoomType zoomType)
1296 {
1297 #if ENABLE(GESTURE_EVENTS)
1298     if (!mainFrameImpl())
1299         return;
1300
1301     float scale;
1302     WebPoint scroll;
1303     bool isAnchor;
1304     WebPoint webPoint = point;
1305     computeScaleAndScrollForHitRect(WebRect(webPoint.x, webPoint.y, 0, 0), zoomType, scale, scroll, isAnchor);
1306
1307     bool isDoubleTap = (zoomType == DoubleTap);
1308     double durationInSeconds = (isDoubleTap && !m_shouldUseDoubleTapTimeZero) ? doubleTapZoomAnimationDurationInSeconds : 0;
1309     startPageScaleAnimation(scroll, isAnchor, scale, durationInSeconds);
1310 #endif
1311 }
1312
1313 void WebViewImpl::zoomToFindInPageRect(const WebRect& rect)
1314 {
1315     animateZoomAroundPoint(IntRect(rect).center(), FindInPage);
1316 }
1317
1318 void WebViewImpl::numberOfWheelEventHandlersChanged(unsigned numberOfWheelHandlers)
1319 {
1320     if (m_client)
1321         m_client->numberOfWheelEventHandlersChanged(numberOfWheelHandlers);
1322 }
1323
1324 void WebViewImpl::hasTouchEventHandlers(bool hasTouchHandlers)
1325 {
1326     if (m_client)
1327         m_client->hasTouchEventHandlers(hasTouchHandlers);
1328 }
1329
1330 bool WebViewImpl::hasTouchEventHandlersAt(const WebPoint& point)
1331 {
1332     return true;
1333 }
1334
1335 #if !OS(DARWIN)
1336 // Mac has no way to open a context menu based on a keyboard event.
1337 bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event)
1338 {
1339     // The contextMenuController() holds onto the last context menu that was
1340     // popped up on the page until a new one is created. We need to clear
1341     // this menu before propagating the event through the DOM so that we can
1342     // detect if we create a new menu for this event, since we won't create
1343     // a new menu if the DOM swallows the event and the defaultEventHandler does
1344     // not run.
1345     page()->contextMenuController()->clearContextMenu();
1346
1347     m_contextMenuAllowed = true;
1348     Frame* focusedFrame = page()->focusController()->focusedOrMainFrame();
1349     bool handled = focusedFrame->eventHandler()->sendContextMenuEventForKey();
1350     m_contextMenuAllowed = false;
1351     return handled;
1352 }
1353 #endif
1354
1355 bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event)
1356 {
1357     Frame* frame = focusedWebCoreFrame();
1358     if (!frame)
1359         return false;
1360
1361     switch (event.type) {
1362     case WebInputEvent::Char:
1363         if (event.windowsKeyCode == VKEY_SPACE) {
1364             int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT);
1365             return scrollViewWithKeyboard(keyCode, event.modifiers);
1366         }
1367         break;
1368     case WebInputEvent::RawKeyDown:
1369         if (event.modifiers == WebInputEvent::ControlKey) {
1370             switch (event.windowsKeyCode) {
1371 #if !OS(DARWIN)
1372             case 'A':
1373                 focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll"));
1374                 return true;
1375             case VKEY_INSERT:
1376             case 'C':
1377                 focusedFrame()->executeCommand(WebString::fromUTF8("Copy"));
1378                 return true;
1379 #endif
1380             // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
1381             // key combinations which affect scrolling. Safari is buggy in the
1382             // sense that it scrolls the page for all Ctrl+scrolling key
1383             // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
1384             case VKEY_HOME:
1385             case VKEY_END:
1386                 break;
1387             default:
1388                 return false;
1389             }
1390         }
1391         if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey))
1392             return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers);
1393         break;
1394     default:
1395         break;
1396     }
1397     return false;
1398 }
1399
1400 bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers)
1401 {
1402     ScrollDirection scrollDirection;
1403     ScrollGranularity scrollGranularity;
1404 #if OS(DARWIN)
1405     // Control-Up/Down should be PageUp/Down on Mac.
1406     if (modifiers & WebMouseEvent::ControlKey) {
1407       if (keyCode == VKEY_UP)
1408         keyCode = VKEY_PRIOR;
1409       else if (keyCode == VKEY_DOWN)
1410         keyCode = VKEY_NEXT;
1411     }
1412 #endif
1413     if (!mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity))
1414         return false;
1415     return propagateScroll(scrollDirection, scrollGranularity);
1416 }
1417
1418 bool WebViewImpl::mapKeyCodeForScroll(int keyCode,
1419                                       WebCore::ScrollDirection* scrollDirection,
1420                                       WebCore::ScrollGranularity* scrollGranularity)
1421 {
1422     switch (keyCode) {
1423     case VKEY_LEFT:
1424         *scrollDirection = ScrollLeft;
1425         *scrollGranularity = ScrollByLine;
1426         break;
1427     case VKEY_RIGHT:
1428         *scrollDirection = ScrollRight;
1429         *scrollGranularity = ScrollByLine;
1430         break;
1431     case VKEY_UP:
1432         *scrollDirection = ScrollUp;
1433         *scrollGranularity = ScrollByLine;
1434         break;
1435     case VKEY_DOWN:
1436         *scrollDirection = ScrollDown;
1437         *scrollGranularity = ScrollByLine;
1438         break;
1439     case VKEY_HOME:
1440         *scrollDirection = ScrollUp;
1441         *scrollGranularity = ScrollByDocument;
1442         break;
1443     case VKEY_END:
1444         *scrollDirection = ScrollDown;
1445         *scrollGranularity = ScrollByDocument;
1446         break;
1447     case VKEY_PRIOR:  // page up
1448         *scrollDirection = ScrollUp;
1449         *scrollGranularity = ScrollByPage;
1450         break;
1451     case VKEY_NEXT:  // page down
1452         *scrollDirection = ScrollDown;
1453         *scrollGranularity = ScrollByPage;
1454         break;
1455     default:
1456         return false;
1457     }
1458
1459     return true;
1460 }
1461
1462 void WebViewImpl::hideSelectPopup()
1463 {
1464     if (m_selectPopup)
1465         m_selectPopup->hidePopup();
1466 }
1467
1468 bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection,
1469                                   ScrollGranularity scrollGranularity)
1470 {
1471     Frame* frame = focusedWebCoreFrame();
1472     if (!frame)
1473         return false;
1474
1475     bool scrollHandled = frame->eventHandler()->scrollOverflow(scrollDirection, scrollGranularity);
1476     Frame* currentFrame = frame;
1477     while (!scrollHandled && currentFrame) {
1478         scrollHandled = currentFrame->view()->scroll(scrollDirection, scrollGranularity);
1479         currentFrame = currentFrame->tree()->parent();
1480     }
1481     return scrollHandled;
1482 }
1483
1484 void  WebViewImpl::popupOpened(WebCore::PopupContainer* popupContainer)
1485 {
1486     if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
1487         ASSERT(!m_selectPopup);
1488         m_selectPopup = popupContainer;
1489     }
1490 }
1491
1492 void  WebViewImpl::popupClosed(WebCore::PopupContainer* popupContainer)
1493 {
1494     if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
1495         ASSERT(m_selectPopup);
1496         m_selectPopup = 0;
1497     }
1498 }
1499
1500 #if ENABLE(PAGE_POPUP)
1501 PagePopup* WebViewImpl::openPagePopup(PagePopupClient* client, const IntRect& originBoundsInRootView)
1502 {
1503     ASSERT(client);
1504     if (hasOpenedPopup())
1505         hidePopups();
1506     ASSERT(!m_pagePopup);
1507
1508     WebWidget* popupWidget = m_client->createPopupMenu(WebPopupTypePage);
1509     ASSERT(popupWidget);
1510     m_pagePopup = static_cast<WebPagePopupImpl*>(popupWidget);
1511     if (!m_pagePopup->initialize(this, client, originBoundsInRootView)) {
1512         m_pagePopup->closePopup();
1513         m_pagePopup = 0;
1514     }
1515     return m_pagePopup.get();
1516 }
1517
1518 void WebViewImpl::closePagePopup(PagePopup* popup)
1519 {
1520     ASSERT(popup);
1521     WebPagePopupImpl* popupImpl = static_cast<WebPagePopupImpl*>(popup);
1522     ASSERT(m_pagePopup.get() == popupImpl);
1523     if (m_pagePopup.get() != popupImpl)
1524         return;
1525     m_pagePopup->closePopup();
1526     m_pagePopup = 0;
1527 }
1528 #endif
1529
1530 void WebViewImpl::hideAutofillPopup()
1531 {
1532     if (m_autofillPopupShowing) {
1533         m_autofillPopup->hidePopup();
1534         m_autofillPopupShowing = false;
1535     }
1536 }
1537
1538 WebHelperPluginImpl* WebViewImpl::createHelperPlugin(const String& pluginType)
1539 {
1540     WebWidget* popupWidget = m_client->createPopupMenu(WebPopupTypeHelperPlugin);
1541     ASSERT(popupWidget);
1542     WebHelperPluginImpl* helperPlugin = static_cast<WebHelperPluginImpl*>(popupWidget);
1543
1544     if (!helperPlugin->initialize(this, pluginType)) {
1545         helperPlugin->closeHelperPlugin();
1546         helperPlugin = 0;
1547     }
1548     return helperPlugin;
1549 }
1550
1551 Frame* WebViewImpl::focusedWebCoreFrame() const
1552 {
1553     return m_page ? m_page->focusController()->focusedOrMainFrame() : 0;
1554 }
1555
1556 WebViewImpl* WebViewImpl::fromPage(Page* page)
1557 {
1558     if (!page)
1559         return 0;
1560
1561     ChromeClientImpl* chromeClient = static_cast<ChromeClientImpl*>(page->chrome()->client());
1562     return static_cast<WebViewImpl*>(chromeClient->webView());
1563 }
1564
1565 PageGroup* WebViewImpl::defaultPageGroup()
1566 {
1567     return PageGroup::pageGroup(pageGroupName);
1568 }
1569
1570 // WebWidget ------------------------------------------------------------------
1571
1572 void WebViewImpl::close()
1573 {
1574     if (m_page) {
1575         // Initiate shutdown for the entire frameset.  This will cause a lot of
1576         // notifications to be sent.
1577         if (m_page->mainFrame())
1578             m_page->mainFrame()->loader()->frameDetached();
1579
1580         m_page.clear();
1581     }
1582
1583     // Should happen after m_page.clear().
1584     if (m_devToolsAgent)
1585         m_devToolsAgent.clear();
1586
1587     // Reset the delegate to prevent notifications being sent as we're being
1588     // deleted.
1589     m_client = 0;
1590
1591     deref();  // Balances ref() acquired in WebView::create
1592 }
1593
1594 void WebViewImpl::willStartLiveResize()
1595 {
1596     if (mainFrameImpl() && mainFrameImpl()->frameView())
1597         mainFrameImpl()->frameView()->willStartLiveResize();
1598
1599     Frame* frame = mainFrameImpl()->frame();
1600     WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
1601     if (pluginContainer)
1602         pluginContainer->willStartLiveResize();
1603 }
1604
1605 WebSize WebViewImpl::size()
1606 {
1607     if (isFixedLayoutModeEnabled() && settingsImpl()->applyPageScaleFactorInCompositor())
1608         return layoutSize();
1609
1610     return m_size;
1611 }
1612
1613 void WebViewImpl::resize(const WebSize& newSize)
1614 {
1615     if (m_shouldAutoResize || m_size == newSize)
1616         return;
1617
1618     FrameView* view = mainFrameImpl()->frameView();
1619     if (!view)
1620         return;
1621
1622     WebSize oldSize = m_size;
1623     float oldPageScaleFactor = pageScaleFactor();
1624     IntSize oldScrollOffset = view->scrollOffset();
1625     int oldFixedLayoutWidth = fixedLayoutSize().width;
1626
1627     m_size = newSize;
1628
1629 #if ENABLE(VIEWPORT)
1630     ViewportArguments viewportArguments = mainFrameImpl()->frame()->document()->viewportArguments();
1631     m_page->chrome()->client()->dispatchViewportPropertiesDidChange(viewportArguments);
1632 #endif
1633
1634     WebDevToolsAgentPrivate* agentPrivate = devToolsAgentPrivate();
1635     if (agentPrivate)
1636         agentPrivate->webViewResized(newSize);
1637     if (!agentPrivate || !agentPrivate->metricsOverridden()) {
1638         WebFrameImpl* webFrame = mainFrameImpl();
1639         if (webFrame->frameView())
1640             webFrame->frameView()->resize(size());
1641     }
1642
1643 #if ENABLE(VIEWPORT)
1644     if (settings()->viewportEnabled()) {
1645         if (!settingsImpl()->applyPageScaleFactorInCompositor()) {
1646             // Relayout immediately to obtain the new content width, which is needed
1647             // to calculate the minimum scale limit.
1648             view->layout();
1649         }
1650         computePageScaleFactorLimits();
1651
1652         // When the device rotates:
1653         // - If the page width is unchanged, then zoom by new width/old width
1654         //   such as to keep the same content horizontally onscreen.
1655         // - If the page width stretches proportionally to the change in
1656         //   screen width, then don't zoom at all (assuming the content has
1657         //   scaled uniformly, then the same content will be horizontally
1658         //   onscreen).
1659         //   - If the page width partially stretches, then zoom partially to
1660         //   make up the difference.
1661         // In all cases try to keep the same content at the top of the screen.
1662         float viewportWidthRatio = !oldSize.width ? 1 : newSize.width / (float) oldSize.width;
1663         float fixedLayoutWidthRatio = !oldFixedLayoutWidth ? 1 : fixedLayoutSize().width / (float) oldFixedLayoutWidth;
1664         float scaleMultiplier = viewportWidthRatio / fixedLayoutWidthRatio;
1665         if (scaleMultiplier != 1) {
1666             IntSize scrollOffsetAtNewScale = oldScrollOffset;
1667             if (!settingsImpl()->applyPageScaleFactorInCompositor())
1668                 scrollOffsetAtNewScale.scale(scaleMultiplier);
1669             setPageScaleFactor(oldPageScaleFactor * scaleMultiplier, IntPoint(scrollOffsetAtNewScale));
1670         }
1671     }
1672 #endif
1673
1674     sendResizeEventAndRepaint();
1675 }
1676
1677 void WebViewImpl::willEndLiveResize()
1678 {
1679     if (mainFrameImpl() && mainFrameImpl()->frameView())
1680         mainFrameImpl()->frameView()->willEndLiveResize();
1681
1682     Frame* frame = mainFrameImpl()->frame();
1683     WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
1684     if (pluginContainer)
1685         pluginContainer->willEndLiveResize();
1686 }
1687
1688 void WebViewImpl::willEnterFullScreen()
1689 {
1690 #if ENABLE(FULLSCREEN_API)
1691     if (!m_provisionalFullScreenElement)
1692         return;
1693
1694     // Ensure that this element's document is still attached.
1695     Document* doc = m_provisionalFullScreenElement->document();
1696     if (doc->frame()) {
1697         doc->webkitWillEnterFullScreenForElement(m_provisionalFullScreenElement.get());
1698         m_fullScreenFrame = doc->frame();
1699     }
1700     m_provisionalFullScreenElement.clear();
1701 #endif
1702 }
1703
1704 void WebViewImpl::didEnterFullScreen()
1705 {
1706 #if ENABLE(FULLSCREEN_API)
1707     if (!m_fullScreenFrame)
1708         return;
1709
1710     if (Document* doc = m_fullScreenFrame->document()) {
1711         if (doc->webkitIsFullScreen())
1712             doc->webkitDidEnterFullScreenForElement(0);
1713     }
1714 #endif
1715 }
1716
1717 void WebViewImpl::willExitFullScreen()
1718 {
1719 #if ENABLE(FULLSCREEN_API)
1720     if (!m_fullScreenFrame)
1721         return;
1722
1723     if (Document* doc = m_fullScreenFrame->document()) {
1724         if (doc->webkitIsFullScreen()) {
1725             // When the client exits from full screen we have to call webkitCancelFullScreen to
1726             // notify the document. While doing that, suppress notifications back to the client.
1727             m_isCancelingFullScreen = true;
1728             doc->webkitCancelFullScreen();
1729             m_isCancelingFullScreen = false;
1730             doc->webkitWillExitFullScreenForElement(0);
1731         }
1732     }
1733 #endif
1734 }
1735
1736 void WebViewImpl::didExitFullScreen()
1737 {
1738 #if ENABLE(FULLSCREEN_API)
1739     if (!m_fullScreenFrame)
1740         return;
1741
1742     if (Document* doc = m_fullScreenFrame->document()) {
1743         if (doc->webkitIsFullScreen())
1744             doc->webkitDidExitFullScreenForElement(0);
1745     }
1746
1747     m_fullScreenFrame.clear();
1748 #endif
1749 }
1750
1751 void WebViewImpl::instrumentBeginFrame()
1752 {
1753     InspectorInstrumentation::didBeginFrame(m_page.get());
1754 }
1755
1756 void WebViewImpl::instrumentCancelFrame()
1757 {
1758     InspectorInstrumentation::didCancelFrame(m_page.get());
1759 }
1760
1761 #if ENABLE(BATTERY_STATUS)
1762 void WebViewImpl::updateBatteryStatus(const WebBatteryStatus& status)
1763 {
1764     m_batteryClient->updateBatteryStatus(status);
1765 }
1766 #endif
1767
1768 void WebViewImpl::setCompositorSurfaceReady()
1769 {
1770     m_compositorSurfaceReady = true;
1771     if (m_layerTreeView)
1772         m_layerTreeView->setSurfaceReady();
1773 }
1774
1775 void WebViewImpl::animate(double)
1776 {
1777 #if ENABLE(REQUEST_ANIMATION_FRAME)
1778     double monotonicFrameBeginTime = monotonicallyIncreasingTime();
1779
1780 #if USE(ACCELERATED_COMPOSITING)
1781     // In composited mode, we always go through the compositor so it can apply
1782     // appropriate flow-control mechanisms.
1783     if (isAcceleratedCompositingActive())
1784         m_layerTreeView->updateAnimations(monotonicFrameBeginTime);
1785     else
1786 #endif
1787         updateAnimations(monotonicFrameBeginTime);
1788 #endif
1789 }
1790
1791 void WebViewImpl::willBeginFrame()
1792 {
1793     instrumentBeginFrame();
1794     m_client->willBeginCompositorFrame();
1795 }
1796
1797 void WebViewImpl::didBeginFrame()
1798 {
1799     InspectorInstrumentation::didComposite(m_page.get());
1800
1801     if (m_continuousPaintingEnabled)
1802         ContinuousPainter::setNeedsDisplayRecursive(m_rootGraphicsLayer, m_pageOverlays.get());
1803 }
1804
1805 void WebViewImpl::updateAnimations(double monotonicFrameBeginTime)
1806 {
1807 #if ENABLE(REQUEST_ANIMATION_FRAME)
1808     TRACE_EVENT0("webkit", "WebViewImpl::updateAnimations");
1809
1810     // Create synthetic wheel events as necessary for fling.
1811     if (m_gestureAnimation) {
1812         if (m_gestureAnimation->animate(monotonicFrameBeginTime))
1813             scheduleAnimation();
1814         else {
1815             m_gestureAnimation.clear();
1816             if (m_layerTreeView)
1817                 m_layerTreeView->didStopFlinging();
1818         }
1819     }
1820
1821     if (!m_page)
1822         return;
1823
1824     PageWidgetDelegate::animate(m_page.get(), monotonicFrameBeginTime);
1825 #endif
1826 }
1827
1828 void WebViewImpl::layout()
1829 {
1830     TRACE_EVENT0("webkit", "WebViewImpl::layout");
1831     PageWidgetDelegate::layout(m_page.get());
1832
1833     if (m_linkHighlight)
1834         m_linkHighlight->updateGeometry();
1835 }
1836
1837 void WebViewImpl::enterForceCompositingMode(bool enter)
1838 {
1839     TRACE_EVENT1("webkit", "WebViewImpl::enterForceCompositingMode", "enter", enter);
1840     settingsImpl()->setForceCompositingMode(enter);
1841     if (enter) {
1842         if (!m_page)
1843             return;
1844         Frame* mainFrame = m_page->mainFrame();
1845         if (!mainFrame)
1846             return;
1847         mainFrame->view()->updateCompositingLayersAfterStyleChange();
1848     }
1849 }
1850
1851 #if USE(ACCELERATED_COMPOSITING)
1852 void WebViewImpl::doPixelReadbackToCanvas(WebCanvas* canvas, const IntRect& rect)
1853 {
1854     ASSERT(m_layerTreeView);
1855
1856     SkBitmap target;
1857     target.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height(), rect.width() * 4);
1858     target.allocPixels();
1859     m_layerTreeView->compositeAndReadback(target.getPixels(), rect);
1860 #if (!SK_R32_SHIFT && SK_B32_SHIFT == 16)
1861     // The compositor readback always gives back pixels in BGRA order, but for
1862     // example Android's Skia uses RGBA ordering so the red and blue channels
1863     // need to be swapped.
1864     uint8_t* pixels = reinterpret_cast<uint8_t*>(target.getPixels());
1865     for (size_t i = 0; i < target.getSize(); i += 4)
1866         std::swap(pixels[i], pixels[i + 2]);
1867 #endif
1868     canvas->writePixels(target, rect.x(), rect.y());
1869 }
1870 #endif
1871
1872 void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect, PaintOptions option)
1873 {
1874 #if !OS(ANDROID)
1875     // ReadbackFromCompositorIfAvailable is the only option available on non-Android.
1876     // Ideally, Android would always use ReadbackFromCompositorIfAvailable as well.
1877     ASSERT(option == ReadbackFromCompositorIfAvailable);
1878 #endif
1879
1880     if (option == ReadbackFromCompositorIfAvailable && isAcceleratedCompositingActive()) {
1881 #if USE(ACCELERATED_COMPOSITING)
1882         // If a canvas was passed in, we use it to grab a copy of the
1883         // freshly-rendered pixels.
1884         if (canvas) {
1885             // Clip rect to the confines of the rootLayerTexture.
1886             IntRect resizeRect(rect);
1887             resizeRect.intersect(IntRect(IntPoint(0, 0), m_layerTreeView->deviceViewportSize()));
1888             doPixelReadbackToCanvas(canvas, resizeRect);
1889         }
1890 #endif
1891     } else {
1892         FrameView* view = page()->mainFrame()->view();
1893         PaintBehavior oldPaintBehavior = view->paintBehavior();
1894         if (isAcceleratedCompositingActive()) {
1895             ASSERT(option == ForceSoftwareRenderingAndIgnoreGPUResidentContent);            
1896             view->setPaintBehavior(oldPaintBehavior | PaintBehaviorFlattenCompositingLayers);
1897         }
1898
1899         double paintStart = currentTime();
1900         PageWidgetDelegate::paint(m_page.get(), pageOverlays(), canvas, rect, isTransparent() ? PageWidgetDelegate::Translucent : PageWidgetDelegate::Opaque, m_webSettings->applyDeviceScaleFactorInCompositor());
1901         double paintEnd = currentTime();
1902         double pixelsPerSec = (rect.width * rect.height) / (paintEnd - paintStart);
1903         WebKit::Platform::current()->histogramCustomCounts("Renderer4.SoftwarePaintDurationMS", (paintEnd - paintStart) * 1000, 0, 120, 30);
1904         WebKit::Platform::current()->histogramCustomCounts("Renderer4.SoftwarePaintMegapixPerSecond", pixelsPerSec / 1000000, 10, 210, 30);
1905
1906         if (isAcceleratedCompositingActive()) {
1907             ASSERT(option == ForceSoftwareRenderingAndIgnoreGPUResidentContent);            
1908             view->setPaintBehavior(oldPaintBehavior);
1909         }
1910     }
1911 }
1912
1913 bool WebViewImpl::isTrackingRepaints() const
1914 {
1915     if (!page())
1916         return false;
1917     FrameView* view = page()->mainFrame()->view();
1918     return view->isTrackingRepaints();
1919 }
1920
1921 void WebViewImpl::themeChanged()
1922 {
1923     if (!page())
1924         return;
1925     FrameView* view = page()->mainFrame()->view();
1926
1927     WebRect damagedRect(0, 0, m_size.width, m_size.height);
1928     view->invalidateRect(damagedRect);
1929 }
1930
1931 void WebViewImpl::composite(bool)
1932 {
1933 #if USE(ACCELERATED_COMPOSITING)
1934     if (Platform::current()->compositorSupport()->isThreadingEnabled())
1935         m_layerTreeView->setNeedsRedraw();
1936     else {
1937         ASSERT(isAcceleratedCompositingActive());
1938         if (!page())
1939             return;
1940
1941         m_layerTreeView->composite();
1942     }
1943 #endif
1944 }
1945
1946 void WebViewImpl::setNeedsRedraw()
1947 {
1948 #if USE(ACCELERATED_COMPOSITING)
1949     if (m_layerTreeView && isAcceleratedCompositingActive())
1950         m_layerTreeView->setNeedsRedraw();
1951 #endif
1952 }
1953
1954 bool WebViewImpl::isInputThrottled() const
1955 {
1956 #if USE(ACCELERATED_COMPOSITING)
1957     if (m_layerTreeView && isAcceleratedCompositingActive())
1958         return m_layerTreeView->commitRequested();
1959 #endif
1960     return false;
1961 }
1962
1963 void WebViewImpl::enterFullScreenForElement(WebCore::Element* element)
1964 {
1965     // We are already transitioning to fullscreen for a different element.
1966     if (m_provisionalFullScreenElement) {
1967         m_provisionalFullScreenElement = element;
1968         return;
1969     }
1970
1971     // We are already in fullscreen mode.
1972     if (m_fullScreenFrame) {
1973         m_provisionalFullScreenElement = element;
1974         willEnterFullScreen();
1975         didEnterFullScreen();
1976         return;
1977     }
1978
1979 #if USE(NATIVE_FULLSCREEN_VIDEO)
1980     if (element && element->isMediaElement()) {
1981         HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(element);
1982         if (mediaElement->player() && mediaElement->player()->canEnterFullscreen()) {
1983             mediaElement->player()->enterFullscreen();
1984             m_provisionalFullScreenElement = element;
1985         }
1986         return;
1987     }
1988 #endif
1989
1990     // We need to transition to fullscreen mode.
1991     if (m_client && m_client->enterFullScreen())
1992         m_provisionalFullScreenElement = element;
1993 }
1994
1995 void WebViewImpl::exitFullScreenForElement(WebCore::Element* element)
1996 {
1997     // The client is exiting full screen, so don't send a notification.
1998     if (m_isCancelingFullScreen)
1999         return;
2000 #if USE(NATIVE_FULLSCREEN_VIDEO)
2001     if (element && element->isMediaElement()) {
2002         HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(element);
2003         if (mediaElement->player())
2004             mediaElement->player()->exitFullscreen();
2005         return;
2006     }
2007 #endif
2008     if (m_client)
2009         m_client->exitFullScreen();
2010 }
2011
2012 bool WebViewImpl::hasHorizontalScrollbar()
2013 {
2014     return mainFrameImpl()->frameView()->horizontalScrollbar();
2015 }
2016
2017 bool WebViewImpl::hasVerticalScrollbar()
2018 {
2019     return mainFrameImpl()->frameView()->verticalScrollbar();
2020 }
2021
2022 const WebInputEvent* WebViewImpl::m_currentInputEvent = 0;
2023
2024 bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
2025 {
2026     // If we've started a drag and drop operation, ignore input events until
2027     // we're done.
2028     if (m_doingDragAndDrop)
2029         return true;
2030
2031     // Report the event to be NOT processed by WebKit, so that the browser can handle it appropriately.
2032     if (m_ignoreInputEvents)
2033         return false;
2034
2035     TemporaryChange<const WebInputEvent*> currentEventChange(m_currentInputEvent, &inputEvent);
2036
2037 #if ENABLE(POINTER_LOCK)
2038     if (isPointerLocked() && WebInputEvent::isMouseEventType(inputEvent.type)) {
2039       pointerLockMouseEvent(inputEvent);
2040       return true;
2041     }
2042 #endif
2043
2044     if (m_mouseCaptureNode && WebInputEvent::isMouseEventType(inputEvent.type)) {
2045         // Save m_mouseCaptureNode since mouseCaptureLost() will clear it.
2046         RefPtr<Node> node = m_mouseCaptureNode;
2047
2048         // Not all platforms call mouseCaptureLost() directly.
2049         if (inputEvent.type == WebInputEvent::MouseUp)
2050             mouseCaptureLost();
2051
2052         AtomicString eventType;
2053         switch (inputEvent.type) {
2054         case WebInputEvent::MouseMove:
2055             eventType = eventNames().mousemoveEvent;
2056             break;
2057         case WebInputEvent::MouseLeave:
2058             eventType = eventNames().mouseoutEvent;
2059             break;
2060         case WebInputEvent::MouseDown:
2061             eventType = eventNames().mousedownEvent;
2062             break;
2063         case WebInputEvent::MouseUp:
2064             eventType = eventNames().mouseupEvent;
2065             break;
2066         default:
2067             ASSERT_NOT_REACHED();
2068         }
2069
2070         node->dispatchMouseEvent(
2071               PlatformMouseEventBuilder(mainFrameImpl()->frameView(), *static_cast<const WebMouseEvent*>(&inputEvent)),
2072               eventType, static_cast<const WebMouseEvent*>(&inputEvent)->clickCount);
2073         return true;
2074     }
2075
2076     if (!m_layerTreeView)
2077         return PageWidgetDelegate::handleInputEvent(m_page.get(), *this, inputEvent);
2078
2079     const WebInputEvent* inputEventTransformed = &inputEvent;
2080     WebMouseEvent mouseEvent;
2081     WebGestureEvent gestureEvent;
2082     if (WebInputEvent::isMouseEventType(inputEvent.type)) {
2083         mouseEvent = *static_cast<const WebMouseEvent*>(&inputEvent);
2084
2085         IntPoint transformedLocation = roundedIntPoint(m_layerTreeView->adjustEventPointForPinchZoom(WebFloatPoint(mouseEvent.x, mouseEvent.y)));
2086         mouseEvent.x = transformedLocation.x();
2087         mouseEvent.y = transformedLocation.y();
2088         inputEventTransformed = static_cast<const WebInputEvent*>(&mouseEvent);
2089     } else if (WebInputEvent::isGestureEventType(inputEvent.type)) {
2090         gestureEvent = *static_cast<const WebGestureEvent*>(&inputEvent);
2091
2092         IntPoint transformedLocation = roundedIntPoint(m_layerTreeView->adjustEventPointForPinchZoom(WebFloatPoint(gestureEvent.x, gestureEvent.y)));
2093         gestureEvent.x = transformedLocation.x();
2094         gestureEvent.y = transformedLocation.y();
2095         inputEventTransformed = static_cast<const WebInputEvent*>(&gestureEvent);
2096     }
2097
2098     bool handled = PageWidgetDelegate::handleInputEvent(m_page.get(), *this, *inputEventTransformed);
2099     return handled;
2100 }
2101
2102 void WebViewImpl::mouseCaptureLost()
2103 {
2104     m_mouseCaptureNode = 0;
2105 }
2106
2107 void WebViewImpl::setFocus(bool enable)
2108 {
2109     m_page->focusController()->setFocused(enable);
2110     if (enable) {
2111         m_page->focusController()->setActive(true);
2112         RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
2113         if (focusedFrame) {
2114             Node* focusedNode = focusedFrame->document()->focusedNode();
2115             if (focusedNode && focusedNode->isElementNode()
2116                 && focusedFrame->selection()->selection().isNone()) {
2117                 // If the selection was cleared while the WebView was not
2118                 // focused, then the focus element shows with a focus ring but
2119                 // no caret and does respond to keyboard inputs.
2120                 Element* element = static_cast<Element*>(focusedNode);
2121                 if (element->isTextFormControl())
2122                     element->updateFocusAppearance(true);
2123                 else if (focusedNode->isContentEditable()) {
2124                     // updateFocusAppearance() selects all the text of
2125                     // contentseditable DIVs. So we set the selection explicitly
2126                     // instead. Note that this has the side effect of moving the
2127                     // caret back to the beginning of the text.
2128                     Position position(focusedNode, 0,
2129                                       Position::PositionIsOffsetInAnchor);
2130                     focusedFrame->selection()->setSelection(
2131                         VisibleSelection(position, SEL_DEFAULT_AFFINITY));
2132                 }
2133             }
2134         }
2135         m_imeAcceptEvents = true;
2136     } else {
2137         hidePopups();
2138
2139         // Clear focus on the currently focused frame if any.
2140         if (!m_page)
2141             return;
2142
2143         Frame* frame = m_page->mainFrame();
2144         if (!frame)
2145             return;
2146
2147         RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
2148         if (focusedFrame) {
2149             // Finish an ongoing composition to delete the composition node.
2150             Editor* editor = focusedFrame->editor();
2151             if (editor && editor->hasComposition())
2152                 editor->confirmComposition();
2153             m_imeAcceptEvents = false;
2154         }
2155     }
2156 }
2157
2158 bool WebViewImpl::setComposition(
2159     const WebString& text,
2160     const WebVector<WebCompositionUnderline>& underlines,
2161     int selectionStart,
2162     int selectionEnd)
2163 {
2164     Frame* focused = focusedWebCoreFrame();
2165     if (!focused || !m_imeAcceptEvents)
2166         return false;
2167     Editor* editor = focused->editor();
2168     if (!editor)
2169         return false;
2170
2171     // The input focus has been moved to another WebWidget object.
2172     // We should use this |editor| object only to complete the ongoing
2173     // composition.
2174     if (!editor->canEdit() && !editor->hasComposition())
2175         return false;
2176
2177     // We should verify the parent node of this IME composition node are
2178     // editable because JavaScript may delete a parent node of the composition
2179     // node. In this case, WebKit crashes while deleting texts from the parent
2180     // node, which doesn't exist any longer.
2181     PassRefPtr<Range> range = editor->compositionRange();
2182     if (range) {
2183         Node* node = range->startContainer();
2184         if (!node || !node->isContentEditable())
2185             return false;
2186     }
2187
2188     // If we're not going to fire a keypress event, then the keydown event was
2189     // canceled.  In that case, cancel any existing composition.
2190     if (text.isEmpty() || m_suppressNextKeypressEvent) {
2191         // A browser process sent an IPC message which does not contain a valid
2192         // string, which means an ongoing composition has been canceled.
2193         // If the ongoing composition has been canceled, replace the ongoing
2194         // composition string with an empty string and complete it.
2195         String emptyString;
2196         Vector<CompositionUnderline> emptyUnderlines;
2197         editor->setComposition(emptyString, emptyUnderlines, 0, 0);
2198         return text.isEmpty();
2199     }
2200
2201     // When the range of composition underlines overlap with the range between
2202     // selectionStart and selectionEnd, WebKit somehow won't paint the selection
2203     // at all (see InlineTextBox::paint() function in InlineTextBox.cpp).
2204     // But the selection range actually takes effect.
2205     editor->setComposition(String(text),
2206                            CompositionUnderlineVectorBuilder(underlines),
2207                            selectionStart, selectionEnd);
2208
2209     return editor->hasComposition();
2210 }
2211
2212 bool WebViewImpl::confirmComposition()
2213 {
2214     return confirmComposition(WebString());
2215 }
2216
2217 bool WebViewImpl::confirmComposition(const WebString& text)
2218 {
2219     Frame* focused = focusedWebCoreFrame();
2220     if (!focused || !m_imeAcceptEvents)
2221         return false;
2222     Editor* editor = focused->editor();
2223     if (!editor || (!editor->hasComposition() && !text.length()))
2224         return false;
2225
2226     // We should verify the parent node of this IME composition node are
2227     // editable because JavaScript may delete a parent node of the composition
2228     // node. In this case, WebKit crashes while deleting texts from the parent
2229     // node, which doesn't exist any longer.
2230     PassRefPtr<Range> range = editor->compositionRange();
2231     if (range) {
2232         Node* node = range->startContainer();
2233         if (!node || !node->isContentEditable())
2234             return false;
2235     }
2236
2237     if (editor->hasComposition()) {
2238         if (text.length())
2239             editor->confirmComposition(String(text));
2240         else
2241             editor->confirmComposition();
2242     } else
2243         editor->insertText(String(text), 0);
2244
2245     return true;
2246 }
2247
2248 bool WebViewImpl::compositionRange(size_t* location, size_t* length)
2249 {
2250     Frame* focused = focusedWebCoreFrame();
2251     if (!focused || !focused->selection() || !m_imeAcceptEvents)
2252         return false;
2253     Editor* editor = focused->editor();
2254     if (!editor || !editor->hasComposition())
2255         return false;
2256
2257     RefPtr<Range> range = editor->compositionRange();
2258     if (!range)
2259         return false;
2260
2261     if (TextIterator::getLocationAndLengthFromRange(focused->selection()->rootEditableElementOrDocumentElement(), range.get(), *location, *length))
2262         return true;
2263     return false;
2264 }
2265
2266 WebTextInputInfo WebViewImpl::textInputInfo()
2267 {
2268     WebTextInputInfo info;
2269
2270     Frame* focused = focusedWebCoreFrame();
2271     if (!focused)
2272         return info;
2273
2274     Editor* editor = focused->editor();
2275     if (!editor || !editor->canEdit())
2276         return info;
2277
2278     FrameSelection* selection = focused->selection();
2279     if (!selection)
2280         return info;
2281
2282     Node* node = selection->selection().rootEditableElement();
2283     if (!node)
2284         return info;
2285
2286     info.type = textInputType();
2287     if (info.type == WebTextInputTypeNone)
2288         return info;
2289
2290     info.value = plainText(rangeOfContents(node).get());
2291
2292     if (info.value.isEmpty())
2293         return info;
2294
2295     size_t location;
2296     size_t length;
2297     RefPtr<Range> range = selection->selection().firstRange();
2298     if (range && TextIterator::getLocationAndLengthFromRange(selection->rootEditableElement(), range.get(), location, length)) {
2299         info.selectionStart = location;
2300         info.selectionEnd = location + length;
2301     }
2302     range = editor->compositionRange();
2303     if (range && TextIterator::getLocationAndLengthFromRange(selection->rootEditableElement(), range.get(), location, length)) {
2304         info.compositionStart = location;
2305         info.compositionEnd = location + length;
2306     }
2307
2308     return info;
2309 }
2310
2311 WebTextInputType WebViewImpl::textInputType()
2312 {
2313     Node* node = focusedWebCoreNode();
2314     if (!node)
2315         return WebTextInputTypeNone;
2316
2317     if (node->hasTagName(HTMLNames::inputTag)) {
2318         HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
2319
2320         if (input->isDisabledOrReadOnly())
2321             return WebTextInputTypeNone;
2322
2323         if (input->isPasswordField())
2324             return WebTextInputTypePassword;
2325         if (input->isSearchField())
2326             return WebTextInputTypeSearch;
2327         if (input->isEmailField())
2328             return WebTextInputTypeEmail;
2329         if (input->isNumberField())
2330             return WebTextInputTypeNumber;
2331         if (input->isTelephoneField())
2332             return WebTextInputTypeTelephone;
2333         if (input->isURLField())
2334             return WebTextInputTypeURL;
2335         if (input->isDateField())
2336             return WebTextInputTypeDate;
2337         if (input->isDateTimeField())
2338             return WebTextInputTypeDateTime;
2339         if (input->isDateTimeLocalField())
2340             return WebTextInputTypeDateTimeLocal;
2341         if (input->isMonthField())
2342             return WebTextInputTypeMonth;
2343         if (input->isTimeField())
2344             return WebTextInputTypeTime;
2345         if (input->isWeekField())
2346             return WebTextInputTypeWeek;
2347         if (input->isTextField())
2348             return WebTextInputTypeText;
2349
2350         return WebTextInputTypeNone;
2351     }
2352
2353     if (node->hasTagName(HTMLNames::textareaTag)) {
2354         if (static_cast<HTMLTextAreaElement*>(node)->isDisabledOrReadOnly())
2355             return WebTextInputTypeNone;
2356         return WebTextInputTypeTextArea;
2357     }
2358
2359     if (node->shouldUseInputMethod())
2360         return WebTextInputTypeContentEditable;
2361
2362     return WebTextInputTypeNone;
2363 }
2364
2365 bool WebViewImpl::selectionBounds(WebRect& anchor, WebRect& focus) const
2366 {
2367     const Frame* frame = focusedWebCoreFrame();
2368     if (!frame)
2369         return false;
2370     FrameSelection* selection = frame->selection();
2371     if (!selection)
2372         return false;
2373
2374     if (selection->isCaret()) {
2375         anchor = focus = frame->view()->contentsToWindow(selection->absoluteCaretBounds());
2376         return true;
2377     }
2378
2379     RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange();
2380     if (!selectedRange)
2381         return false;
2382
2383     RefPtr<Range> range(Range::create(selectedRange->startContainer()->document(),
2384                                       selectedRange->startContainer(),
2385                                       selectedRange->startOffset(),
2386                                       selectedRange->startContainer(),
2387                                       selectedRange->startOffset()));
2388     anchor = frame->editor()->firstRectForRange(range.get());
2389
2390     range = Range::create(selectedRange->endContainer()->document(),
2391                           selectedRange->endContainer(),
2392                           selectedRange->endOffset(),
2393                           selectedRange->endContainer(),
2394                           selectedRange->endOffset());
2395     focus = frame->editor()->firstRectForRange(range.get());
2396
2397     anchor = frame->view()->contentsToWindow(anchor);
2398     focus = frame->view()->contentsToWindow(focus);
2399
2400     if (!frame->selection()->selection().isBaseFirst())
2401         std::swap(anchor, focus);
2402     return true;
2403 }
2404
2405 bool WebViewImpl::selectionTextDirection(WebTextDirection& start, WebTextDirection& end) const
2406 {
2407     const Frame* frame = focusedWebCoreFrame();
2408     if (!frame)
2409         return false;
2410     FrameSelection* selection = frame->selection();
2411     if (!selection)
2412         return false;
2413     if (!selection->toNormalizedRange())
2414         return false;
2415     start = selection->start().primaryDirection() == RTL ? WebTextDirectionRightToLeft : WebTextDirectionLeftToRight;
2416     end = selection->end().primaryDirection() == RTL ? WebTextDirectionRightToLeft : WebTextDirectionLeftToRight;
2417     return true;
2418 }
2419
2420 bool WebViewImpl::setEditableSelectionOffsets(int start, int end)
2421 {
2422     const Frame* focused = focusedWebCoreFrame();
2423     if (!focused)
2424         return false;
2425
2426     Editor* editor = focused->editor();
2427     if (!editor || !editor->canEdit())
2428         return false;
2429
2430     return editor->setSelectionOffsets(start, end);
2431 }
2432
2433 bool WebViewImpl::setCompositionFromExistingText(int compositionStart, int compositionEnd, const WebVector<WebCompositionUnderline>& underlines)
2434 {
2435     const Frame* focused = focusedWebCoreFrame();
2436     if (!focused)
2437         return false;
2438
2439     Editor* editor = focused->editor();
2440     if (!editor || !editor->canEdit())
2441         return false;
2442
2443     editor->cancelComposition();
2444
2445     if (compositionStart == compositionEnd)
2446         return true;
2447
2448     size_t location;
2449     size_t length;
2450     caretOrSelectionRange(&location, &length);
2451     editor->setIgnoreCompositionSelectionChange(true);
2452     editor->setSelectionOffsets(compositionStart, compositionEnd);
2453     String text = editor->selectedText();
2454     focused->document()->execCommand("delete", true);
2455     editor->setComposition(text, CompositionUnderlineVectorBuilder(underlines), 0, 0);
2456     editor->setSelectionOffsets(location, location + length);
2457     editor->setIgnoreCompositionSelectionChange(false);
2458
2459     return true;
2460 }
2461
2462 void WebViewImpl::extendSelectionAndDelete(int before, int after)
2463 {
2464     const Frame* focused = focusedWebCoreFrame();
2465     if (!focused)
2466         return;
2467
2468     Editor* editor = focused->editor();
2469     if (!editor || !editor->canEdit())
2470         return;
2471
2472     FrameSelection* selection = focused->selection();
2473     if (!selection)
2474         return;
2475
2476     size_t location;
2477     size_t length;
2478     RefPtr<Range> range = selection->selection().firstRange();
2479     if (range && TextIterator::getLocationAndLengthFromRange(selection->rootEditableElement(), range.get(), location, length)) {
2480         editor->setSelectionOffsets(max(static_cast<int>(location) - before, 0), location + length + after);
2481         focused->document()->execCommand("delete", true);
2482     }
2483 }
2484
2485 bool WebViewImpl::isSelectionEditable() const
2486 {
2487     const Frame* frame = focusedWebCoreFrame();
2488     if (!frame)
2489         return false;
2490     return frame->selection()->isContentEditable();
2491 }
2492
2493 WebColor WebViewImpl::backgroundColor() const
2494 {
2495     if (!m_page)
2496         return Color::white;
2497     FrameView* view = m_page->mainFrame()->view();
2498     Color backgroundColor = view->documentBackgroundColor();
2499     if (!backgroundColor.isValid())
2500         return Color::white;
2501     return backgroundColor.rgb();
2502 }
2503
2504 bool WebViewImpl::caretOrSelectionRange(size_t* location, size_t* length)
2505 {
2506     const Frame* focused = focusedWebCoreFrame();
2507     if (!focused)
2508         return false;
2509
2510     FrameSelection* selection = focused->selection();
2511     if (!selection)
2512         return false;
2513
2514     RefPtr<Range> range = selection->selection().firstRange();
2515     if (!range)
2516         return false;
2517
2518     if (TextIterator::getLocationAndLengthFromRange(selection->rootEditableElementOrDocumentElement(), range.get(), *location, *length))
2519         return true;
2520     return false;
2521 }
2522
2523 void WebViewImpl::setTextDirection(WebTextDirection direction)
2524 {
2525     // The Editor::setBaseWritingDirection() function checks if we can change
2526     // the text direction of the selected node and updates its DOM "dir"
2527     // attribute and its CSS "direction" property.
2528     // So, we just call the function as Safari does.
2529     const Frame* focused = focusedWebCoreFrame();
2530     if (!focused)
2531         return;
2532
2533     Editor* editor = focused->editor();
2534     if (!editor || !editor->canEdit())
2535         return;
2536
2537     switch (direction) {
2538     case WebTextDirectionDefault:
2539         editor->setBaseWritingDirection(NaturalWritingDirection);
2540         break;
2541
2542     case WebTextDirectionLeftToRight:
2543         editor->setBaseWritingDirection(LeftToRightWritingDirection);
2544         break;
2545
2546     case WebTextDirectionRightToLeft:
2547         editor->setBaseWritingDirection(RightToLeftWritingDirection);
2548         break;
2549
2550     default:
2551         notImplemented();
2552         break;
2553     }
2554 }
2555
2556 bool WebViewImpl::isAcceleratedCompositingActive() const
2557 {
2558 #if USE(ACCELERATED_COMPOSITING)
2559     return m_isAcceleratedCompositingActive;
2560 #else
2561     return false;
2562 #endif
2563 }
2564
2565 void WebViewImpl::willCloseLayerTreeView()
2566 {
2567     setIsAcceleratedCompositingActive(false);
2568     m_layerTreeView = 0;
2569 }
2570
2571 void WebViewImpl::didAcquirePointerLock()
2572 {
2573 #if ENABLE(POINTER_LOCK)
2574     if (page())
2575         page()->pointerLockController()->didAcquirePointerLock();
2576 #endif
2577 }
2578
2579 void WebViewImpl::didNotAcquirePointerLock()
2580 {
2581 #if ENABLE(POINTER_LOCK)
2582     if (page())
2583         page()->pointerLockController()->didNotAcquirePointerLock();
2584 #endif
2585 }
2586
2587 void WebViewImpl::didLosePointerLock()
2588 {
2589 #if ENABLE(POINTER_LOCK)
2590     if (page())
2591         page()->pointerLockController()->didLosePointerLock();
2592 #endif
2593 }
2594
2595 void WebViewImpl::didChangeWindowResizerRect()
2596 {
2597     if (mainFrameImpl()->frameView())
2598         mainFrameImpl()->frameView()->windowResizerRectChanged();
2599 }
2600
2601 // WebView --------------------------------------------------------------------
2602
2603 WebSettingsImpl* WebViewImpl::settingsImpl()
2604 {
2605     if (!m_webSettings)
2606         m_webSettings = adoptPtr(new WebSettingsImpl(m_page->settings()));
2607     ASSERT(m_webSettings);
2608     return m_webSettings.get();
2609 }
2610
2611 WebSettings* WebViewImpl::settings()
2612 {
2613     return settingsImpl();
2614 }
2615
2616 WebString WebViewImpl::pageEncoding() const
2617 {
2618     if (!m_page)
2619         return WebString();
2620
2621     // FIXME: Is this check needed?
2622     if (!m_page->mainFrame()->document()->loader())
2623         return WebString();
2624
2625     return m_page->mainFrame()->document()->encoding();
2626 }
2627
2628 void WebViewImpl::setPageEncoding(const WebString& encodingName)
2629 {
2630     if (!m_page)
2631         return;
2632
2633     // Only change override encoding, don't change default encoding.
2634     // Note that the new encoding must be 0 if it isn't supposed to be set.
2635     String newEncodingName;
2636     if (!encodingName.isEmpty())
2637         newEncodingName = encodingName;
2638     m_page->mainFrame()->loader()->reloadWithOverrideEncoding(newEncodingName);
2639 }
2640
2641 bool WebViewImpl::dispatchBeforeUnloadEvent()
2642 {
2643     // FIXME: This should really cause a recursive depth-first walk of all
2644     // frames in the tree, calling each frame's onbeforeunload.  At the moment,
2645     // we're consistent with Safari 3.1, not IE/FF.
2646     Frame* frame = m_page->mainFrame();
2647     if (!frame)
2648         return true;
2649
2650     return frame->loader()->shouldClose();
2651 }
2652
2653 void WebViewImpl::dispatchUnloadEvent()
2654 {
2655     // Run unload handlers.
2656     m_page->mainFrame()->loader()->closeURL();
2657 }
2658
2659 WebFrame* WebViewImpl::mainFrame()
2660 {
2661     return mainFrameImpl();
2662 }
2663
2664 WebFrame* WebViewImpl::findFrameByName(
2665     const WebString& name, WebFrame* relativeToFrame)
2666 {
2667     if (!relativeToFrame)
2668         relativeToFrame = mainFrame();
2669     Frame* frame = static_cast<WebFrameImpl*>(relativeToFrame)->frame();
2670     frame = frame->tree()->find(name);
2671     return WebFrameImpl::fromFrame(frame);
2672 }
2673
2674 WebFrame* WebViewImpl::focusedFrame()
2675 {
2676     return WebFrameImpl::fromFrame(focusedWebCoreFrame());
2677 }
2678
2679 void WebViewImpl::setFocusedFrame(WebFrame* frame)
2680 {
2681     if (!frame) {
2682         // Clears the focused frame if any.
2683         Frame* frame = focusedWebCoreFrame();
2684         if (frame)
2685             frame->selection()->setFocused(false);
2686         return;
2687     }
2688     WebFrameImpl* frameImpl = static_cast<WebFrameImpl*>(frame);
2689     Frame* webcoreFrame = frameImpl->frame();
2690     webcoreFrame->page()->focusController()->setFocusedFrame(webcoreFrame);
2691 }
2692
2693 void WebViewImpl::setInitialFocus(bool reverse)
2694 {
2695     if (!m_page)
2696         return;
2697
2698     // Since we don't have a keyboard event, we'll create one.
2699     WebKeyboardEvent keyboardEvent;
2700     keyboardEvent.type = WebInputEvent::RawKeyDown;
2701     if (reverse)
2702         keyboardEvent.modifiers = WebInputEvent::ShiftKey;
2703
2704     // VK_TAB which is only defined on Windows.
2705     keyboardEvent.windowsKeyCode = 0x09;
2706     PlatformKeyboardEventBuilder platformEvent(keyboardEvent);
2707     RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0);
2708
2709     Frame* frame = page()->focusController()->focusedOrMainFrame();
2710     if (Document* document = frame->document())
2711         document->setFocusedNode(0);
2712     page()->focusController()->setInitialFocus(
2713         reverse ? FocusDirectionBackward : FocusDirectionForward,
2714         webkitEvent.get());
2715 }
2716
2717 void WebViewImpl::clearFocusedNode()
2718 {
2719     RefPtr<Frame> frame = focusedWebCoreFrame();
2720     if (!frame)
2721         return;
2722
2723     RefPtr<Document> document = frame->document();
2724     if (!document)
2725         return;
2726
2727     RefPtr<Node> oldFocusedNode = document->focusedNode();
2728
2729     // Clear the focused node.
2730     document->setFocusedNode(0);
2731
2732     if (!oldFocusedNode)
2733         return;
2734
2735     // If a text field has focus, we need to make sure the selection controller
2736     // knows to remove selection from it. Otherwise, the text field is still
2737     // processing keyboard events even though focus has been moved to the page and
2738     // keystrokes get eaten as a result.
2739     if (oldFocusedNode->isContentEditable()
2740         || (oldFocusedNode->isElementNode()
2741             && static_cast<Element*>(oldFocusedNode.get())->isTextFormControl())) {
2742         frame->selection()->clear();
2743     }
2744 }
2745
2746 void WebViewImpl::scrollFocusedNodeIntoView()
2747 {
2748     Node* focusedNode = focusedWebCoreNode();
2749     if (focusedNode && focusedNode->isElementNode()) {
2750         Element* elementNode = static_cast<Element*>(focusedNode);
2751         elementNode->scrollIntoViewIfNeeded(true);
2752     }
2753 }
2754
2755 void WebViewImpl::scrollFocusedNodeIntoRect(const WebRect& rect)
2756 {
2757     Frame* frame = page()->mainFrame();
2758     Node* focusedNode = focusedWebCoreNode();
2759     if (!frame || !frame->view() || !focusedNode || !focusedNode->isElementNode())
2760         return;
2761
2762     if (!m_webSettings->autoZoomFocusedNodeToLegibleScale()) {
2763         Element* elementNode = static_cast<Element*>(focusedNode);
2764         frame->view()->scrollElementToRect(elementNode, IntRect(rect.x, rect.y, rect.width, rect.height));
2765         return;
2766     }
2767
2768 #if ENABLE(GESTURE_EVENTS)
2769     focusedNode->document()->updateLayoutIgnorePendingStylesheets();
2770
2771     // 'caret' is rect encompassing the blinking cursor.
2772     IntRect textboxRect = focusedNode->document()->view()->contentsToWindow(pixelSnappedIntRect(focusedNode->Node::boundingBox()));
2773     WebRect caret, end;
2774     selectionBounds(caret, end);
2775
2776     // Pick a scale which is reasonably readable. This is the scale at which
2777     // the caret height will become minReadableCaretHeight (adjusted for dpi
2778     // and font scale factor).
2779     float targetScale = deviceScaleFactor();
2780 #if ENABLE(TEXT_AUTOSIZING)
2781     if (page() && page()->settings())
2782         targetScale *= page()->settings()->textAutosizingFontScaleFactor();
2783 #endif
2784     const float newScale = clampPageScaleFactorToLimits(pageScaleFactor() * minReadableCaretHeight * targetScale / caret.height);
2785     const float deltaScale = newScale / pageScaleFactor();
2786
2787     // Convert the rects to absolute space in the new scale.
2788     IntRect textboxRectInDocumentCoordinates = textboxRect;
2789     textboxRectInDocumentCoordinates.move(mainFrame()->scrollOffset());
2790     textboxRectInDocumentCoordinates.scale(deltaScale);
2791     IntRect caretInDocumentCoordinates = caret;
2792     caretInDocumentCoordinates.move(mainFrame()->scrollOffset());
2793     caretInDocumentCoordinates.scale(deltaScale);
2794
2795     IntPoint newOffset;
2796     if (textboxRectInDocumentCoordinates.width() <= m_size.width) {
2797         // Field is narrower than screen. Try to leave padding on left so field's
2798         // label is visible, but it's more important to ensure entire field is
2799         // onscreen.
2800         int idealLeftPadding = m_size.width * leftBoxRatio;
2801         int maxLeftPaddingKeepingBoxOnscreen = m_size.width - textboxRectInDocumentCoordinates.width();
2802         newOffset.setX(textboxRectInDocumentCoordinates.x() - min<int>(idealLeftPadding, maxLeftPaddingKeepingBoxOnscreen));
2803     } else {
2804         // Field is wider than screen. Try to left-align field, unless caret would
2805         // be offscreen, in which case right-align the caret.
2806         newOffset.setX(max<int>(textboxRectInDocumentCoordinates.x(), caretInDocumentCoordinates.x() + caretInDocumentCoordinates.width() + caretPadding - m_size.width));
2807     }
2808     if (textboxRectInDocumentCoordinates.height() <= m_size.height) {
2809         // Field is shorter than screen. Vertically center it.
2810         newOffset.setY(textboxRectInDocumentCoordinates.y() - (m_size.height - textboxRectInDocumentCoordinates.height()) / 2);
2811     } else {
2812         // Field is taller than screen. Try to top align field, unless caret would
2813         // be offscreen, in which case bottom-align the caret.
2814         newOffset.setY(max<int>(textboxRectInDocumentCoordinates.y(), caretInDocumentCoordinates.y() + caretInDocumentCoordinates.height() + caretPadding - m_size.height));
2815     }
2816
2817     bool needAnimation = false;
2818     // If we are at less than the target zoom level, zoom in.
2819     if (deltaScale > minScaleChangeToTriggerZoom)
2820         needAnimation = true;
2821     // If the caret is offscreen, then animate.
2822     IntRect sizeRect(0, 0, m_size.width, m_size.height);
2823     if (!sizeRect.contains(caret))
2824         needAnimation = true;
2825     // If the box is partially offscreen and it's possible to bring it fully
2826     // onscreen, then animate.
2827     if (sizeRect.contains(textboxRectInDocumentCoordinates.width(), textboxRectInDocumentCoordinates.height()) && !sizeRect.contains(textboxRect))
2828         needAnimation = true;
2829
2830     if (needAnimation)
2831         startPageScaleAnimation(newOffset, false, newScale, scrollAndScaleAnimationDurationInSeconds);
2832 #endif
2833 }
2834
2835 void WebViewImpl::advanceFocus(bool reverse)
2836 {
2837     page()->focusController()->advanceFocus(reverse ? FocusDirectionBackward : FocusDirectionForward, 0);
2838 }
2839
2840 double WebViewImpl::zoomLevel()
2841 {
2842     return m_zoomLevel;
2843 }
2844
2845 double WebViewImpl::setZoomLevel(bool textOnly, double zoomLevel)
2846 {
2847     if (zoomLevel < m_minimumZoomLevel)
2848         m_zoomLevel = m_minimumZoomLevel;
2849     else if (zoomLevel > m_maximumZoomLevel)
2850         m_zoomLevel = m_maximumZoomLevel;
2851     else
2852         m_zoomLevel = zoomLevel;
2853
2854     Frame* frame = mainFrameImpl()->frame();
2855     WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
2856     if (pluginContainer)
2857         pluginContainer->plugin()->setZoomLevel(m_zoomLevel, textOnly);
2858     else {
2859         float zoomFactor = static_cast<float>(zoomLevelToZoomFactor(m_zoomLevel));
2860         if (textOnly)
2861             frame->setPageAndTextZoomFactors(1, zoomFactor * m_emulatedTextZoomFactor);
2862         else
2863             frame->setPageAndTextZoomFactors(zoomFactor, m_emulatedTextZoomFactor);
2864     }
2865     return m_zoomLevel;
2866 }
2867
2868 void WebViewImpl::zoomLimitsChanged(double minimumZoomLevel,
2869                                     double maximumZoomLevel)
2870 {
2871     m_minimumZoomLevel = minimumZoomLevel;
2872     m_maximumZoomLevel = maximumZoomLevel;
2873     m_client->zoomLimitsChanged(m_minimumZoomLevel, m_maximumZoomLevel);
2874 }
2875
2876 void WebViewImpl::fullFramePluginZoomLevelChanged(double zoomLevel)
2877 {
2878     if (zoomLevel == m_zoomLevel)
2879         return;
2880
2881     m_zoomLevel = max(min(zoomLevel, m_maximumZoomLevel), m_minimumZoomLevel);
2882     m_client->zoomLevelChanged();
2883 }
2884
2885 double WebView::zoomLevelToZoomFactor(double zoomLevel)
2886 {
2887     return pow(textSizeMultiplierRatio, zoomLevel);
2888 }
2889
2890 double WebView::zoomFactorToZoomLevel(double factor)
2891 {
2892     // Since factor = 1.2^level, level = log(factor) / log(1.2)
2893     return log(factor) / log(textSizeMultiplierRatio);
2894 }
2895
2896 float WebViewImpl::pageScaleFactor() const
2897 {
2898     if (!page())
2899         return 1;
2900
2901     return page()->pageScaleFactor();
2902 }
2903
2904 bool WebViewImpl::isPageScaleFactorSet() const
2905 {
2906     return m_pageScaleFactorIsSet;
2907 }
2908
2909 float WebViewImpl::clampPageScaleFactorToLimits(float scaleFactor)
2910 {
2911     return min(max(scaleFactor, m_minimumPageScaleFactor), m_maximumPageScaleFactor);
2912 }
2913
2914 WebPoint WebViewImpl::clampOffsetAtScale(const WebPoint& offset, float scale)
2915 {
2916     // This is the scaled content size. We need to convert it to the new scale factor.
2917     WebSize contentSize = mainFrame()->contentsSize();
2918     float deltaScale = scale / pageScaleFactor();
2919     int docWidthAtNewScale = contentSize.width * deltaScale;
2920     int docHeightAtNewScale = contentSize.height * deltaScale;
2921     int viewWidth = m_size.width;
2922     int viewHeight = m_size.height;
2923
2924     // Enforce the maximum and minimum scroll positions at the new scale.
2925     IntPoint clampedOffset = offset;
2926     clampedOffset = clampedOffset.shrunkTo(IntPoint(docWidthAtNewScale - viewWidth, docHeightAtNewScale - viewHeight));
2927     clampedOffset.clampNegativeToZero();
2928     return clampedOffset;
2929 }
2930
2931 void WebViewImpl::setPageScaleFactorPreservingScrollOffset(float scaleFactor)
2932 {
2933     // Pick a scale factor that is within the expected limits
2934     scaleFactor = clampPageScaleFactorToLimits(scaleFactor);
2935
2936     IntPoint scrollOffsetAtNewScale(mainFrame()->scrollOffset().width, mainFrame()->scrollOffset().height);
2937     float deltaScale = scaleFactor / pageScaleFactor();
2938     scrollOffsetAtNewScale.scale(deltaScale, deltaScale);
2939
2940     WebPoint clampedOffsetAtNewScale = clampOffsetAtScale(scrollOffsetAtNewScale, scaleFactor);
2941     setPageScaleFactor(scaleFactor, clampedOffsetAtNewScale);
2942 }
2943
2944 void WebViewImpl::setPageScaleFactor(float scaleFactor, const WebPoint& origin)
2945 {
2946     if (!page())
2947         return;
2948
2949     if (!scaleFactor)
2950         scaleFactor = 1;
2951
2952     scaleFactor = clampPageScaleFactorToLimits(scaleFactor);
2953     WebPoint scrollOffset;
2954     if (!m_page->settings()->applyPageScaleFactorInCompositor()) {
2955         // If page scale is not applied in the compositor, then the scroll offsets should
2956         // be modified by the scale factor.
2957         scrollOffset = clampOffsetAtScale(origin, scaleFactor);
2958     } else {
2959         IntPoint offset = origin;
2960         WebSize contentSize = mainFrame()->contentsSize();
2961         offset.shrunkTo(IntPoint(contentSize.width - m_size.width, contentSize.height - m_size.height));
2962         offset.clampNegativeToZero();
2963         scrollOffset = offset;
2964     }
2965
2966     page()->setPageScaleFactor(scaleFactor, scrollOffset);
2967     m_pageScaleFactorIsSet = true;
2968 }
2969
2970 float WebViewImpl::deviceScaleFactor() const
2971 {
2972     if (!page())
2973         return 1;
2974
2975     return page()->deviceScaleFactor();
2976 }
2977
2978 void WebViewImpl::setDeviceScaleFactor(float scaleFactor)
2979 {
2980     if (!page())
2981         return;
2982
2983     page()->setDeviceScaleFactor(scaleFactor);
2984
2985     if (m_layerTreeView && m_webSettings->applyDeviceScaleFactorInCompositor())
2986         m_layerTreeView->setDeviceScaleFactor(scaleFactor);
2987 }
2988
2989 bool WebViewImpl::isFixedLayoutModeEnabled() const
2990 {
2991     if (!page())
2992         return false;
2993
2994     Frame* frame = page()->mainFrame();
2995     if (!frame || !frame->view())
2996         return false;
2997
2998     return frame->view()->useFixedLayout();
2999 }
3000
3001 void WebViewImpl::enableFixedLayoutMode(bool enable)
3002 {
3003     if (!page())
3004         return;
3005
3006     Frame* frame = page()->mainFrame();
3007     if (!frame || !frame->view())
3008         return;
3009
3010     frame->view()->setUseFixedLayout(enable);
3011
3012 #if USE(ACCELERATED_COMPOSITING)
3013     // Also notify the base layer, which RenderLayerCompositor does not see.
3014     if (m_nonCompositedContentHost)
3015         updateLayerTreeViewport();
3016 #endif
3017 }
3018
3019
3020 void WebViewImpl::enableAutoResizeMode(const WebSize& minSize, const WebSize& maxSize)
3021 {
3022     m_shouldAutoResize = true;
3023     m_minAutoSize = minSize;
3024     m_maxAutoSize = maxSize;
3025     configureAutoResizeMode();
3026 }
3027
3028 void WebViewImpl::disableAutoResizeMode()
3029 {
3030     m_shouldAutoResize = false;
3031     configureAutoResizeMode();
3032 }
3033
3034 void WebViewImpl::setPageScaleFactorLimits(float minPageScale, float maxPageScale)
3035 {
3036     m_pageDefinedMinimumPageScaleFactor = minPageScale;
3037     m_pageDefinedMaximumPageScaleFactor = maxPageScale;
3038     computePageScaleFactorLimits();
3039 }
3040
3041 void WebViewImpl::setIgnoreViewportTagMaximumScale(bool flag)
3042 {
3043     m_ignoreViewportTagMaximumScale = flag;
3044
3045     if (!page() || !page()->mainFrame())
3046         return;
3047
3048     m_page->chrome()->client()->dispatchViewportPropertiesDidChange(page()->mainFrame()->document()->viewportArguments());
3049 }
3050
3051 static IntSize unscaledContentsSize(Frame* frame)
3052 {
3053     RenderView* root = frame->contentRenderer();
3054     if (!root)
3055         return IntSize();
3056     return root->unscaledDocumentRect().size();
3057 }
3058
3059 IntSize WebViewImpl::layoutSize() const
3060 {
3061     if (!isFixedLayoutModeEnabled())
3062         return m_size;
3063
3064     IntSize contentSize = unscaledContentsSize(page()->mainFrame());
3065     if (fixedLayoutSize().width >= contentSize.width())
3066         return fixedLayoutSize();
3067
3068     float aspectRatio = static_cast<float>(m_size.height) / m_size.width;
3069     return IntSize(contentSize.width(), contentSize.width() * aspectRatio);
3070 }
3071
3072 bool WebViewImpl::computePageScaleFactorLimits()
3073 {
3074     if (m_pageDefinedMinimumPageScaleFactor == -1 || m_pageDefinedMaximumPageScaleFactor == -1)
3075         return false;
3076
3077     if (!mainFrame() || !page() || !page()->mainFrame() || !page()->mainFrame()->view())
3078         return false;
3079
3080     FrameView* view = page()->mainFrame()->view();
3081
3082     m_minimumPageScaleFactor = min(max(m_pageDefinedMinimumPageScaleFactor, minPageScaleFactor), maxPageScaleFactor);
3083     m_maximumPageScaleFactor = max(min(m_pageDefinedMaximumPageScaleFactor, maxPageScaleFactor), minPageScaleFactor);
3084     if (!m_webSettings->applyDeviceScaleFactorInCompositor()) {
3085         m_minimumPageScaleFactor *= deviceScaleFactor();
3086         m_maximumPageScaleFactor *= deviceScaleFactor();
3087     }
3088
3089     int viewWidthNotIncludingScrollbars = m_size.width;
3090     if (viewWidthNotIncludingScrollbars && view->verticalScrollbar() && !view->verticalScrollbar()->isOverlayScrollbar())
3091         viewWidthNotIncludingScrollbars -= view->verticalScrollbar()->width();
3092     int unscaledContentsWidth = unscaledContentsSize(page()->mainFrame()).width();
3093     if (viewWidthNotIncludingScrollbars && unscaledContentsWidth) {
3094         // Limit page scaling down to the document width.
3095         m_minimumPageScaleFactor = max(m_minimumPageScaleFactor, static_cast<float>(viewWidthNotIncludingScrollbars) / unscaledContentsWidth);
3096         m_maximumPageScaleFactor = max(m_minimumPageScaleFactor, m_maximumPageScaleFactor);
3097     }
3098     ASSERT(m_minimumPageScaleFactor <= m_maximumPageScaleFactor);
3099
3100     float clampedScale = clampPageScaleFactorToLimits(pageScaleFactor());
3101 #if USE(ACCELERATED_COMPOSITING)
3102     if (m_layerTreeView)
3103         m_layerTreeView->setPageScaleFactorAndLimits(clampedScale, m_minimumPageScaleFactor, m_maximumPageScaleFactor);
3104 #endif
3105     if (clampedScale != pageScaleFactor()) {
3106         setPageScaleFactorPreservingScrollOffset(clampedScale);
3107         return true;
3108     }
3109
3110     return false;
3111 }
3112
3113 float WebViewImpl::minimumPageScaleFactor() const
3114 {
3115     return m_minimumPageScaleFactor;
3116 }
3117
3118 float WebViewImpl::maximumPageScaleFactor() const
3119 {
3120     return m_maximumPageScaleFactor;
3121 }
3122
3123 void WebViewImpl::saveScrollAndScaleState()
3124 {
3125     m_savedPageScaleFactor = pageScaleFactor();
3126     m_savedScrollOffset = mainFrame()->scrollOffset();
3127 }
3128
3129 void WebViewImpl::restoreScrollAndScaleState()
3130 {
3131     if (!m_savedPageScaleFactor)
3132         return;
3133
3134 #if ENABLE(GESTURE_EVENTS)
3135     startPageScaleAnimation(IntPoint(m_savedScrollOffset), false, m_savedPageScaleFactor, scrollAndScaleAnimationDurationInSeconds);
3136 #else
3137     setPageScaleFactor(m_savedPageScaleFactor, WebPoint());
3138     mainFrame()->setScrollOffset(m_savedScrollOffset);
3139 #endif
3140
3141     resetSavedScrollAndScaleState();
3142 }
3143
3144 void WebViewImpl::resetSavedScrollAndScaleState()
3145 {
3146     m_savedPageScaleFactor = 0;
3147     m_savedScrollOffset = IntSize();
3148 }
3149
3150 void WebViewImpl::resetScrollAndScaleState()
3151 {
3152     page()->setPageScaleFactor(1, IntPoint());
3153
3154     // Clear out the values for the current history item. This will prevent the history item from clobbering the
3155     // value determined during page scale initialization, which may be less than 1.
3156     page()->mainFrame()->loader()->history()->saveDocumentAndScrollState();
3157     page()->mainFrame()->loader()->history()->clearScrollPositionAndViewState();
3158     m_pageScaleFactorIsSet = false;
3159
3160     // Clobber saved scales and scroll offsets.
3161     if (FrameView* view = page()->mainFrame()->document()->view())
3162         view->cacheCurrentScrollPosition();
3163     resetSavedScrollAndScaleState();
3164 }
3165
3166 WebSize WebViewImpl::fixedLayoutSize() const
3167 {
3168     if (!page())
3169         return WebSize();
3170
3171     Frame* frame = page()->mainFrame();
3172     if (!frame || !frame->view())
3173         return WebSize();
3174
3175     return frame->view()->fixedLayoutSize();
3176 }
3177
3178 void WebViewImpl::setFixedLayoutSize(const WebSize& layoutSize)
3179 {
3180     if (!page())
3181         return;
3182
3183     Frame* frame = page()->mainFrame();
3184     if (!frame || !frame->view())
3185         return;
3186
3187     frame->view()->setFixedLayoutSize(layoutSize);
3188 }
3189
3190 WebCore::IntSize WebViewImpl::dipSize() const
3191 {
3192     IntSize dipSize = m_size;
3193     if (!m_webSettings->applyDeviceScaleFactorInCompositor())
3194         dipSize.scale(1 / m_client->screenInfo().deviceScaleFactor);
3195     return dipSize;
3196 }
3197
3198 void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action,
3199                                            const WebPoint& location)
3200 {
3201     HitTestResult result = hitTestResultForWindowPos(location);
3202     RefPtr<Node> node = result.innerNonSharedNode();
3203     if (!node->hasTagName(HTMLNames::videoTag) && !node->hasTagName(HTMLNames::audioTag))
3204         return;
3205
3206     RefPtr<HTMLMediaElement> mediaElement =
3207         static_pointer_cast<HTMLMediaElement>(node);
3208     switch (action.type) {
3209     case WebMediaPlayerAction::Play:
3210         if (action.enable)
3211             mediaElement->play();
3212         else
3213             mediaElement->pause();
3214         break;
3215     case WebMediaPlayerAction::Mute:
3216         mediaElement->setMuted(action.enable);
3217         break;
3218     case WebMediaPlayerAction::Loop:
3219         mediaElement->setLoop(action.enable);
3220         break;
3221     case WebMediaPlayerAction::Controls:
3222         mediaElement->setControls(action.enable);
3223         break;
3224     default:
3225         ASSERT_NOT_REACHED();
3226     }
3227 }
3228
3229 void WebViewImpl::performPluginAction(const WebPluginAction& action,
3230                                       const WebPoint& location)
3231 {
3232     HitTestResult result = hitTestResultForWindowPos(location);
3233     RefPtr<Node> node = result.innerNonSharedNode();
3234     if (!node->hasTagName(HTMLNames::objectTag) && !node->hasTagName(HTMLNames::embedTag))
3235         return;
3236
3237     RenderObject* object = node->renderer();
3238     if (object && object->isWidget()) {
3239         Widget* widget = toRenderWidget(object)->widget();
3240         if (widget && widget->isPluginContainer()) {
3241             WebPluginContainerImpl* plugin = static_cast<WebPluginContainerImpl*>(widget);
3242             switch (action.type) {
3243             case WebPluginAction::Rotate90Clockwise:
3244                 plugin->plugin()->rotateView(WebPlugin::RotationType90Clockwise);
3245                 break;
3246             case WebPluginAction::Rotate90Counterclockwise:
3247                 plugin->plugin()->rotateView(WebPlugin::RotationType90Counterclockwise);
3248                 break;
3249             default:
3250                 ASSERT_NOT_REACHED();
3251             }
3252         }
3253     }
3254 }
3255
3256 WebHitTestResult WebViewImpl::hitTestResultAt(const WebPoint& point)
3257 {
3258     return hitTestResultForWindowPos(point);
3259 }
3260
3261 void WebViewImpl::copyImageAt(const WebPoint& point)
3262 {
3263     if (!m_page)
3264         return;
3265
3266     HitTestResult result = hitTestResultForWindowPos(point);
3267
3268     if (result.absoluteImageURL().isEmpty()) {
3269         // There isn't actually an image at these coordinates.  Might be because
3270         // the window scrolled while the context menu was open or because the page
3271         // changed itself between when we thought there was an image here and when
3272         // we actually tried to retreive the image.
3273         //
3274         // FIXME: implement a cache of the most recent HitTestResult to avoid having
3275         //        to do two hit tests.
3276         return;
3277     }
3278
3279     m_page->mainFrame()->editor()->copyImage(result);
3280 }
3281
3282 void WebViewImpl::dragSourceEndedAt(
3283     const WebPoint& clientPoint,
3284     const WebPoint& screenPoint,
3285     WebDragOperation operation)
3286 {
3287     PlatformMouseEvent pme(clientPoint,
3288                            screenPoint,
3289                            LeftButton, PlatformEvent::MouseMoved, 0, false, false, false,
3290                            false, 0);
3291     m_page->mainFrame()->eventHandler()->dragSourceEndedAt(pme,
3292         static_cast<DragOperation>(operation));
3293 }
3294
3295 void WebViewImpl::dragSourceMovedTo(
3296     const WebPoint& clientPoint,
3297     const WebPoint& screenPoint,
3298     WebDragOperation operation)
3299 {
3300 }
3301
3302 void WebViewImpl::dragSourceSystemDragEnded()
3303 {
3304     // It's possible for us to get this callback while not doing a drag if
3305     // it's from a previous page that got unloaded.
3306     if (m_doingDragAndDrop) {
3307         m_page->dragController()->dragEnded();
3308         m_doingDragAndDrop = false;
3309     }
3310 }
3311
3312 WebDragOperation WebViewImpl::dragTargetDragEnter(
3313     const WebDragData& webDragData,
3314     const WebPoint& clientPoint,
3315     const WebPoint& screenPoint,
3316     WebDragOperationsMask operationsAllowed,
3317     int keyModifiers)
3318 {
3319     ASSERT(!m_currentDragData);
3320
3321     m_currentDragData = webDragData;
3322     m_operationsAllowed = operationsAllowed;
3323
3324     return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragEnter, keyModifiers);
3325 }
3326
3327 WebDragOperation WebViewImpl::dragTargetDragOver(
3328     const WebPoint& clientPoint,
3329     const WebPoint& screenPoint,
3330     WebDragOperationsMask operationsAllowed,
3331     int keyModifiers)
3332 {
3333     m_operationsAllowed = operationsAllowed;
3334
3335     return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragOver, keyModifiers);
3336 }
3337
3338 void WebViewImpl::dragTargetDragLeave()
3339 {
3340     ASSERT(m_currentDragData);
3341
3342     DragData dragData(
3343         m_currentDragData.get(),
3344         IntPoint(),
3345         IntPoint(),
3346         static_cast<DragOperation>(m_operationsAllowed));
3347
3348     m_page->dragController()->dragExited(&dragData);
3349
3350     // FIXME: why is the drag scroll timer not stopped here?
3351
3352     m_dragOperation = WebDragOperationNone;
3353     m_currentDragData = 0;
3354 }
3355
3356 void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint,
3357                                  const WebPoint& screenPoint,
3358                                  int keyModifiers)
3359 {
3360     ASSERT(m_currentDragData);
3361
3362     // If this webview transitions from the "drop accepting" state to the "not
3363     // accepting" state, then our IPC message reply indicating that may be in-
3364     // flight, or else delayed by javascript processing in this webview.  If a
3365     // drop happens before our IPC reply has reached the browser process, then
3366     // the browser forwards the drop to this webview.  So only allow a drop to
3367     // proceed if our webview m_dragOperation state is not DragOperationNone.
3368
3369     if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop.
3370         dragTargetDragLeave();
3371         return;
3372     }
3373
3374     m_currentDragData->setModifierKeyState(webInputEventKeyStateToPlatformEventKeyState(keyModifiers));
3375     DragData dragData(
3376         m_currentDragData.get(),
3377         clientPoint,
3378         screenPoint,
3379         static_cast<DragOperation>(m_operationsAllowed));
3380
3381     m_page->dragController()->performDrag(&dragData);
3382
3383     m_dragOperation = WebDragOperationNone;
3384     m_currentDragData = 0;
3385 }
3386
3387 WebDragOperation WebViewImpl::dragTargetDragEnterOrOver(const WebPoint& clientPoint, const WebPoint& screenPoint, DragAction dragAction, int keyModifiers)
3388 {
3389     ASSERT(m_currentDragData);
3390
3391     m_currentDragData->setModifierKeyState(webInputEventKeyStateToPlatformEventKeyState(keyModifiers));
3392     DragData dragData(
3393         m_currentDragData.get(),
3394         clientPoint,
3395         screenPoint,
3396         static_cast<DragOperation>(m_operationsAllowed));
3397
3398     DragSession dragSession;
3399     if (dragAction == DragEnter)
3400         dragSession = m_page->dragController()->dragEntered(&dragData);
3401     else
3402         dragSession = m_page->dragController()->dragUpdated(&dragData);
3403
3404     DragOperation dropEffect = dragSession.operation;
3405
3406     // Mask the drop effect operation against the drag source's allowed operations.
3407     if (!(dropEffect & dragData.draggingSourceOperationMask()))
3408         dropEffect = DragOperationNone;
3409
3410      m_dragOperation = static_cast<WebDragOperation>(dropEffect);
3411
3412     return m_dragOperation;
3413 }
3414
3415 void WebViewImpl::sendResizeEventAndRepaint()
3416 {
3417     if (mainFrameImpl()->frameView()) {
3418         // Enqueues the resize event.
3419         mainFrameImpl()->frame()->eventHandler()->sendResizeEvent();
3420     }
3421
3422     if (m_client) {
3423         if (isAcceleratedCompositingActive()) {
3424 #if USE(ACCELERATED_COMPOSITING)
3425             updateLayerTreeViewport();
3426 #endif
3427         } else {
3428             WebRect damagedRect(0, 0, m_size.width, m_size.height);
3429             m_client->didInvalidateRect(damagedRect);
3430         }
3431     }
3432     if (m_pageOverlays)
3433         m_pageOverlays->update();
3434 }
3435
3436 void WebViewImpl::configureAutoResizeMode()
3437 {
3438     if (!mainFrameImpl() || !mainFrameImpl()->frame() || !mainFrameImpl()->frame()->view())
3439         return;
3440
3441     mainFrameImpl()->frame()->view()->enableAutoSizeMode(m_shouldAutoResize, m_minAutoSize, m_maxAutoSize);
3442 }
3443
3444 unsigned long WebViewImpl::createUniqueIdentifierForRequest()
3445 {
3446     if (m_page)
3447         return m_page->progress()->createUniqueIdentifier();
3448     return 0;
3449 }
3450
3451 void WebViewImpl::inspectElementAt(const WebPoint& point)
3452 {
3453     if (!m_page)
3454         return;
3455
3456     if (point.x == -1 || point.y == -1)
3457         m_page->inspectorController()->inspect(0);
3458     else {
3459         HitTestResult result = hitTestResultForWindowPos(point);
3460
3461         if (!result.innerNonSharedNode())
3462             return;
3463
3464         m_page->inspectorController()->inspect(result.innerNonSharedNode());
3465     }
3466 }
3467
3468 WebString WebViewImpl::inspectorSettings() const
3469 {
3470     return m_inspectorSettings;
3471 }
3472
3473 void WebViewImpl::setInspectorSettings(const WebString& settings)
3474 {
3475     m_inspectorSettings = settings;
3476 }
3477
3478 bool WebViewImpl::inspectorSetting(const WebString& key, WebString* value) const
3479 {
3480     if (!m_inspectorSettingsMap->contains(key))
3481         return false;
3482     *value = m_inspectorSettingsMap->get(key);
3483     return true;
3484 }
3485
3486 void WebViewImpl::setInspectorSetting(const WebString& key,
3487                                       const WebString& value)
3488 {
3489     m_inspectorSettingsMap->set(key, value);
3490     client()->didUpdateInspectorSetting(key, value);
3491 }
3492
3493 WebDevToolsAgent* WebViewImpl::devToolsAgent()
3494 {
3495     return m_devToolsAgent.get();
3496 }
3497
3498 WebAccessibilityObject WebViewImpl::accessibilityObject()