Collapse OS(UNIX)||OS(ANDROID) to OS(UNIX)
[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)
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 void WebViewImpl::setContinuousPaintingEnabled(bool enabled)
887 {
888     if (isAcceleratedCompositingActive()) {
889         TRACE_EVENT0("webkit", "WebViewImpl::setContinuousPaintingEnabled");
890         m_layerTreeView->setContinuousPaintingEnabled(enabled);
891     }
892     m_continuousPaintingEnabled = enabled;
893 }
894
895 bool WebViewImpl::handleKeyEvent(const WebKeyboardEvent& event)
896 {
897     ASSERT((event.type == WebInputEvent::RawKeyDown)
898         || (event.type == WebInputEvent::KeyDown)
899         || (event.type == WebInputEvent::KeyUp));
900
901     // Halt an in-progress fling on a key event.
902     if (m_gestureAnimation) {
903         m_gestureAnimation.clear();
904         if (m_layerTreeView)
905             m_layerTreeView->didStopFlinging();
906     }
907
908     // Please refer to the comments explaining the m_suppressNextKeypressEvent
909     // member.
910     // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
911     // Webkit. A keyDown event is typically associated with a keyPress(char)
912     // event and a keyUp event. We reset this flag here as this is a new keyDown
913     // event.
914     m_suppressNextKeypressEvent = false;
915
916     // If there is a select popup, it should be the one processing the event,
917     // not the page.
918     if (m_selectPopup)
919         return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
920 #if ENABLE(PAGE_POPUP)
921     if (m_pagePopup) {
922         m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
923         // We need to ignore the next Char event after this otherwise pressing
924         // enter when selecting an item in the popup will go to the page.
925         if (WebInputEvent::RawKeyDown == event.type)
926             m_suppressNextKeypressEvent = true;
927         return true;
928     }
929 #endif
930
931     // Give Autocomplete a chance to consume the key events it is interested in.
932     if (autocompleteHandleKeyEvent(event))
933         return true;
934
935     RefPtr<Frame> frame = focusedWebCoreFrame();
936     if (!frame)
937         return false;
938
939     EventHandler* handler = frame->eventHandler();
940     if (!handler)
941         return keyEventDefault(event);
942
943 #if !OS(DARWIN)
944     const WebInputEvent::Type contextMenuTriggeringEventType =
945 #if OS(WINDOWS)
946         WebInputEvent::KeyUp;
947 #elif OS(UNIX)
948         WebInputEvent::RawKeyDown;
949 #endif
950
951     bool isUnmodifiedMenuKey = !(event.modifiers & WebInputEvent::InputModifiers) && event.windowsKeyCode == VKEY_APPS;
952     bool isShiftF10 = event.modifiers == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10;
953     if ((isUnmodifiedMenuKey || isShiftF10) && event.type == contextMenuTriggeringEventType) {
954         sendContextMenuEvent(event);
955         return true;
956     }
957 #endif // !OS(DARWIN)
958
959     PlatformKeyboardEventBuilder evt(event);
960
961     if (handler->keyEvent(evt)) {
962         if (WebInputEvent::RawKeyDown == event.type) {
963             // Suppress the next keypress event unless the focused node is a plug-in node.
964             // (Flash needs these keypress events to handle non-US keyboards.)
965             Node* node = focusedWebCoreNode();
966             if (!node || !node->renderer() || !node->renderer()->isEmbeddedObject())
967                 m_suppressNextKeypressEvent = true;
968         }
969         return true;
970     }
971
972     return keyEventDefault(event);
973 }
974
975 bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event)
976 {
977     if (!m_autofillPopupShowing
978         // Home and End should be left to the text field to process.
979         || event.windowsKeyCode == VKEY_HOME
980         || event.windowsKeyCode == VKEY_END)
981       return false;
982
983     // Pressing delete triggers the removal of the selected suggestion from the DB.
984     if (event.windowsKeyCode == VKEY_DELETE
985         && m_autofillPopup->selectedIndex() != -1) {
986         Node* node = focusedWebCoreNode();
987         if (!node || (node->nodeType() != Node::ELEMENT_NODE)) {
988             ASSERT_NOT_REACHED();
989             return false;
990         }
991         Element* element = static_cast<Element*>(node);
992         if (!element->hasLocalName(HTMLNames::inputTag)) {
993             ASSERT_NOT_REACHED();
994             return false;
995         }
996
997         int selectedIndex = m_autofillPopup->selectedIndex();
998
999         if (!m_autofillPopupClient->canRemoveSuggestionAtIndex(selectedIndex))
1000             return false;
1001
1002         WebString name = WebInputElement(static_cast<HTMLInputElement*>(element)).nameForAutofill();
1003         WebString value = m_autofillPopupClient->itemText(selectedIndex);
1004         m_autofillClient->removeAutocompleteSuggestion(name, value);
1005         // Update the entries in the currently showing popup to reflect the
1006         // deletion.
1007         m_autofillPopupClient->removeSuggestionAtIndex(selectedIndex);
1008         refreshAutofillPopup();
1009         return false;
1010     }
1011
1012     if (!m_autofillPopup->isInterestedInEventForKey(event.windowsKeyCode))
1013         return false;
1014
1015     if (m_autofillPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) {
1016         // We need to ignore the next Char event after this otherwise pressing
1017         // enter when selecting an item in the menu will go to the page.
1018         if (WebInputEvent::RawKeyDown == event.type)
1019             m_suppressNextKeypressEvent = true;
1020         return true;
1021     }
1022
1023     return false;
1024 }
1025
1026 bool WebViewImpl::handleCharEvent(const WebKeyboardEvent& event)
1027 {
1028     ASSERT(event.type == WebInputEvent::Char);
1029
1030     // Please refer to the comments explaining the m_suppressNextKeypressEvent
1031     // member.  The m_suppressNextKeypressEvent is set if the KeyDown is
1032     // handled by Webkit. A keyDown event is typically associated with a
1033     // keyPress(char) event and a keyUp event. We reset this flag here as it
1034     // only applies to the current keyPress event.
1035     bool suppress = m_suppressNextKeypressEvent;
1036     m_suppressNextKeypressEvent = false;
1037
1038     // If there is a select popup, it should be the one processing the event,
1039     // not the page.
1040     if (m_selectPopup)
1041         return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
1042 #if ENABLE(PAGE_POPUP)
1043     if (m_pagePopup)
1044         return m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
1045 #endif
1046
1047     Frame* frame = focusedWebCoreFrame();
1048     if (!frame)
1049         return suppress;
1050
1051     EventHandler* handler = frame->eventHandler();
1052     if (!handler)
1053         return suppress || keyEventDefault(event);
1054
1055     PlatformKeyboardEventBuilder evt(event);
1056     if (!evt.isCharacterKey())
1057         return true;
1058
1059     // Accesskeys are triggered by char events and can't be suppressed.
1060     if (handler->handleAccessKey(evt))
1061         return true;
1062
1063     // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
1064     // the eventHandler::keyEvent. We mimic this behavior on all platforms since
1065     // for now we are converting other platform's key events to windows key
1066     // events.
1067     if (evt.isSystemKey())
1068         return false;
1069
1070     if (!suppress && !handler->keyEvent(evt))
1071         return keyEventDefault(event);
1072
1073     return true;
1074 }
1075
1076 #if ENABLE(GESTURE_EVENTS)
1077 WebRect WebViewImpl::computeBlockBounds(const WebRect& rect, AutoZoomType zoomType)
1078 {
1079     if (!mainFrameImpl())
1080         return WebRect();
1081
1082     // Use the rect-based hit test to find the node.
1083     IntPoint point = mainFrameImpl()->frameView()->windowToContents(IntPoint(rect.x, rect.y));
1084     HitTestResult result = mainFrameImpl()->frame()->eventHandler()->hitTestResultAtPoint(point,
1085             false, zoomType == FindInPage, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly,
1086             IntSize(rect.width, rect.height));
1087
1088     Node* node = result.innerNonSharedNode();
1089     if (!node)
1090         return WebRect();
1091
1092     // Find the block type node based on the hit node.
1093     while (node && (!node->renderer() || node->renderer()->isInline()))
1094         node = node->parentNode();
1095
1096     // Return the bounding box in the window coordinate system.
1097     if (node) {
1098         IntRect rect = node->Node::pixelSnappedBoundingBox();
1099         Frame* frame = node->document()->frame();
1100         return frame->view()->contentsToWindow(rect);
1101     }
1102     return WebRect();
1103 }
1104
1105 WebRect WebViewImpl::widenRectWithinPageBounds(const WebRect& source, int targetMargin, int minimumMargin)
1106 {
1107     WebSize maxSize;
1108     if (mainFrame())
1109         maxSize = mainFrame()->contentsSize();
1110     IntSize scrollOffset;
1111     if (mainFrame())
1112         scrollOffset = mainFrame()->scrollOffset();
1113     int leftMargin = targetMargin;
1114     int rightMargin = targetMargin;
1115
1116     const int absoluteSourceX = source.x + scrollOffset.width();
1117     if (leftMargin > absoluteSourceX) {
1118         leftMargin = absoluteSourceX;
1119         rightMargin = max(leftMargin, minimumMargin);
1120     }
1121
1122     const int maximumRightMargin = maxSize.width - (source.width + absoluteSourceX);
1123     if (rightMargin > maximumRightMargin) {
1124         rightMargin = maximumRightMargin;
1125         leftMargin = min(leftMargin, max(rightMargin, minimumMargin));
1126     }
1127
1128     const int newWidth = source.width + leftMargin + rightMargin;
1129     const int newX = source.x - leftMargin;
1130
1131     ASSERT(newWidth >= 0);
1132     ASSERT(scrollOffset.width() + newX + newWidth <= maxSize.width);
1133
1134     return WebRect(newX, source.y, newWidth, source.height);
1135 }
1136
1137 void WebViewImpl::shouldUseAnimateDoubleTapTimeZeroForTesting(bool setToZero)
1138 {
1139     m_shouldUseDoubleTapTimeZero = setToZero;
1140 }
1141
1142 void WebViewImpl::computeScaleAndScrollForHitRect(const WebRect& hitRect, AutoZoomType zoomType, float& scale, WebPoint& scroll, bool& isAnchor)
1143 {
1144     scale = pageScaleFactor();
1145     scroll.x = scroll.y = 0;
1146     WebRect targetRect = hitRect;
1147     // Padding only depends on page scale when triggered by manually tapping
1148     int padding = (zoomType == DoubleTap) ? touchPointPadding : nonUserInitiatedPointPadding;
1149     if (targetRect.isEmpty())
1150         targetRect.width = targetRect.height = padding;
1151     WebRect rect = computeBlockBounds(targetRect, zoomType);
1152     if (zoomType == FindInPage && rect.isEmpty()) {
1153         // Keep current scale (no need to scroll as x,y will normally already
1154         // be visible). FIXME: Revisit this if it isn't always true.
1155         return;
1156     }
1157
1158     bool scaleUnchanged = true;
1159     if (!rect.isEmpty()) {
1160         // Pages should be as legible as on desktop when at dpi scale, so no
1161         // need to zoom in further when automatically determining zoom level
1162         // (after double tap, find in page, etc), though the user should still
1163         // be allowed to manually pinch zoom in further if they desire.
1164         const float defaultScaleWhenAlreadyLegible = m_minimumPageScaleFactor * doubleTapZoomAlreadyLegibleRatio;
1165         float legibleScale = deviceScaleFactor();
1166 #if ENABLE(TEXT_AUTOSIZING)
1167         if (page() && page()->settings())
1168             legibleScale *= page()->settings()->textAutosizingFontScaleFactor();
1169 #endif
1170         if (legibleScale < defaultScaleWhenAlreadyLegible)
1171             legibleScale = (scale == m_minimumPageScaleFactor) ? defaultScaleWhenAlreadyLegible : m_minimumPageScaleFactor;
1172
1173         const float defaultMargin = doubleTapZoomContentDefaultMargin * deviceScaleFactor();
1174         const float minimumMargin = doubleTapZoomContentMinimumMargin * deviceScaleFactor();
1175         // We want the margins to have the same physical size, which means we
1176         // need to express them in post-scale size. To do that we'd need to know
1177         // the scale we're scaling to, but that depends on the margins. Instead
1178         // we express them as a fraction of the target rectangle: this will be
1179         // correct if we end up fully zooming to it, and won't matter if we
1180         // don't.
1181         rect = widenRectWithinPageBounds(rect,
1182                 static_cast<int>(defaultMargin * rect.width / m_size.width),
1183                 static_cast<int>(minimumMargin * rect.width / m_size.width));
1184         // Fit block to screen, respecting limits.
1185         scale *= static_cast<float>(m_size.width) / rect.width;
1186         scale = min(scale, legibleScale);
1187         scale = clampPageScaleFactorToLimits(scale);
1188
1189         scaleUnchanged = fabs(pageScaleFactor() - scale) < minScaleDifference;
1190     }
1191
1192     if (zoomType == DoubleTap && (rect.isEmpty() || scaleUnchanged || m_doubleTapZoomInEffect)) {
1193         // Zoom out to minimum scale.
1194         scale = m_minimumPageScaleFactor;
1195         scroll = WebPoint(hitRect.x, hitRect.y);
1196         isAnchor = true;
1197         m_doubleTapZoomInEffect = false;
1198     } else {
1199         if (zoomType == DoubleTap && scale != m_minimumPageScaleFactor)
1200             m_doubleTapZoomInEffect = true;
1201         else
1202             m_doubleTapZoomInEffect = false;
1203         // FIXME: If this is being called for auto zoom during find in page,
1204         // then if the user manually zooms in it'd be nice to preserve the
1205         // relative increase in zoom they caused (if they zoom out then it's ok
1206         // to zoom them back in again). This isn't compatible with our current
1207         // double-tap zoom strategy (fitting the containing block to the screen)
1208         // though.
1209
1210         float screenHeight = m_size.height / scale * pageScaleFactor();
1211         float screenWidth = m_size.width / scale * pageScaleFactor();
1212
1213         // Scroll to vertically align the block.
1214         if (rect.height < screenHeight) {
1215             // Vertically center short blocks.
1216             rect.y -= 0.5 * (screenHeight - rect.height);
1217         } else {
1218             // Ensure position we're zooming to (+ padding) isn't off the bottom of
1219             // the screen.
1220             rect.y = max<float>(rect.y, hitRect.y + padding - screenHeight);
1221         } // Otherwise top align the block.
1222
1223         // Do the same thing for horizontal alignment.
1224         if (rect.width < screenWidth)
1225             rect.x -= 0.5 * (screenWidth - rect.width);
1226         else
1227             rect.x = max<float>(rect.x, hitRect.x + padding - screenWidth);
1228         scroll.x = rect.x;
1229         scroll.y = rect.y;
1230         isAnchor = false;
1231     }
1232
1233     scale = clampPageScaleFactorToLimits(scale);
1234     scroll = mainFrameImpl()->frameView()->windowToContents(scroll);
1235     float scaleDelta = scale / pageScaleFactor();
1236     scroll = WebPoint(scroll.x * scaleDelta, scroll.y * scaleDelta);
1237     if (!isAnchor)
1238         scroll = clampOffsetAtScale(scroll, scale);
1239 }
1240
1241 static bool invokesHandCursor(Node* node, bool shiftKey, Frame* frame)
1242 {
1243     if (!node || !node->renderer())
1244         return false;
1245
1246     ECursor cursor = node->renderer()->style()->cursor();
1247     return cursor == CURSOR_POINTER
1248         || (cursor == CURSOR_AUTO && frame->eventHandler()->useHandCursor(node, node->isLink(), shiftKey));
1249 }
1250
1251 Node* WebViewImpl::bestTouchLinkNode(const WebGestureEvent& touchEvent)
1252 {
1253     if (!m_page || !m_page->mainFrame())
1254         return 0;
1255
1256     Node* bestTouchNode = 0;
1257
1258     IntSize touchEventSearchRegionSize(touchEvent.data.tapDown.width / 2, touchEvent.data.tapDown.height / 2);
1259     IntPoint touchEventLocation(touchEvent.x, touchEvent.y);
1260 #if ENABLE(TOUCH_ADJUSTMENT)
1261     m_page->mainFrame()->eventHandler()->adjustGesturePosition(PlatformGestureEventBuilder(mainFrameImpl()->frameView(), touchEvent), touchEventLocation);
1262 #endif
1263
1264     IntPoint hitTestPoint = m_page->mainFrame()->view()->windowToContents(touchEventLocation);
1265     HitTestResult result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(
1266         hitTestPoint, false, false, DontHitTestScrollbars, HitTestRequest::TouchEvent);
1267     bestTouchNode = result.targetNode();
1268
1269     // Make sure our highlight candidate uses a hand cursor as a heuristic to
1270     // choose appropriate targets.
1271     bool shiftKey = touchEvent.modifiers & WebGestureEvent::ShiftKey;
1272     while (bestTouchNode && !invokesHandCursor(bestTouchNode, shiftKey, m_page->mainFrame()))
1273         bestTouchNode = bestTouchNode->parentNode();
1274
1275     // We should pick the largest enclosing node with hand cursor set.
1276     while (bestTouchNode && bestTouchNode->parentNode() && invokesHandCursor(bestTouchNode->parentNode(), shiftKey, m_page->mainFrame()))
1277         bestTouchNode = bestTouchNode->parentNode();
1278
1279     return bestTouchNode;
1280 }
1281
1282 void WebViewImpl::enableTouchHighlight(const WebGestureEvent& touchEvent)
1283 {
1284     // Always clear any existing highlight when this is invoked, even if we don't get a new target to highlight.
1285     m_linkHighlight.clear();
1286
1287     Node* touchNode = bestTouchLinkNode(touchEvent);
1288
1289     if (!touchNode || !touchNode->renderer() || !touchNode->renderer()->enclosingLayer())
1290         return;
1291
1292     Color highlightColor = touchNode->renderer()->style()->tapHighlightColor();
1293     // Safari documentation for -webkit-tap-highlight-color says if the specified color has 0 alpha,
1294     // then tap highlighting is disabled.
1295     // http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safaricssref/articles/standardcssproperties.html
1296     if (!highlightColor.alpha())
1297         return;
1298
1299     m_linkHighlight = LinkHighlight::create(touchNode, this);
1300 }
1301
1302 #endif
1303
1304 void WebViewImpl::animateZoomAroundPoint(const IntPoint& point, AutoZoomType zoomType)
1305 {
1306 #if ENABLE(GESTURE_EVENTS)
1307     if (!mainFrameImpl())
1308         return;
1309
1310     float scale;
1311     WebPoint scroll;
1312     bool isAnchor;
1313     WebPoint webPoint = point;
1314     computeScaleAndScrollForHitRect(WebRect(webPoint.x, webPoint.y, 0, 0), zoomType, scale, scroll, isAnchor);
1315
1316     bool isDoubleTap = (zoomType == DoubleTap);
1317     double durationInSeconds = (isDoubleTap && !m_shouldUseDoubleTapTimeZero) ? doubleTapZoomAnimationDurationInSeconds : 0;
1318     startPageScaleAnimation(scroll, isAnchor, scale, durationInSeconds);
1319 #endif
1320 }
1321
1322 void WebViewImpl::zoomToFindInPageRect(const WebRect& rect)
1323 {
1324     animateZoomAroundPoint(IntRect(rect).center(), FindInPage);
1325 }
1326
1327 void WebViewImpl::numberOfWheelEventHandlersChanged(unsigned numberOfWheelHandlers)
1328 {
1329     if (m_client)
1330         m_client->numberOfWheelEventHandlersChanged(numberOfWheelHandlers);
1331 }
1332
1333 void WebViewImpl::hasTouchEventHandlers(bool hasTouchHandlers)
1334 {
1335     if (m_client)
1336         m_client->hasTouchEventHandlers(hasTouchHandlers);
1337 }
1338
1339 bool WebViewImpl::hasTouchEventHandlersAt(const WebPoint& point)
1340 {
1341     return true;
1342 }
1343
1344 #if !OS(DARWIN)
1345 // Mac has no way to open a context menu based on a keyboard event.
1346 bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event)
1347 {
1348     // The contextMenuController() holds onto the last context menu that was
1349     // popped up on the page until a new one is created. We need to clear
1350     // this menu before propagating the event through the DOM so that we can
1351     // detect if we create a new menu for this event, since we won't create
1352     // a new menu if the DOM swallows the event and the defaultEventHandler does
1353     // not run.
1354     page()->contextMenuController()->clearContextMenu();
1355
1356     m_contextMenuAllowed = true;
1357     Frame* focusedFrame = page()->focusController()->focusedOrMainFrame();
1358     bool handled = focusedFrame->eventHandler()->sendContextMenuEventForKey();
1359     m_contextMenuAllowed = false;
1360     return handled;
1361 }
1362 #endif
1363
1364 bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event)
1365 {
1366     Frame* frame = focusedWebCoreFrame();
1367     if (!frame)
1368         return false;
1369
1370     switch (event.type) {
1371     case WebInputEvent::Char:
1372         if (event.windowsKeyCode == VKEY_SPACE) {
1373             int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT);
1374             return scrollViewWithKeyboard(keyCode, event.modifiers);
1375         }
1376         break;
1377     case WebInputEvent::RawKeyDown:
1378         if (event.modifiers == WebInputEvent::ControlKey) {
1379             switch (event.windowsKeyCode) {
1380 #if !OS(DARWIN)
1381             case 'A':
1382                 focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll"));
1383                 return true;
1384             case VKEY_INSERT:
1385             case 'C':
1386                 focusedFrame()->executeCommand(WebString::fromUTF8("Copy"));
1387                 return true;
1388 #endif
1389             // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
1390             // key combinations which affect scrolling. Safari is buggy in the
1391             // sense that it scrolls the page for all Ctrl+scrolling key
1392             // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
1393             case VKEY_HOME:
1394             case VKEY_END:
1395                 break;
1396             default:
1397                 return false;
1398             }
1399         }
1400         if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey))
1401             return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers);
1402         break;
1403     default:
1404         break;
1405     }
1406     return false;
1407 }
1408
1409 bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers)
1410 {
1411     ScrollDirection scrollDirection;
1412     ScrollGranularity scrollGranularity;
1413 #if OS(DARWIN)
1414     // Control-Up/Down should be PageUp/Down on Mac.
1415     if (modifiers & WebMouseEvent::ControlKey) {
1416       if (keyCode == VKEY_UP)
1417         keyCode = VKEY_PRIOR;
1418       else if (keyCode == VKEY_DOWN)
1419         keyCode = VKEY_NEXT;
1420     }
1421 #endif
1422     if (!mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity))
1423         return false;
1424     return propagateScroll(scrollDirection, scrollGranularity);
1425 }
1426
1427 bool WebViewImpl::mapKeyCodeForScroll(int keyCode,
1428                                       WebCore::ScrollDirection* scrollDirection,
1429                                       WebCore::ScrollGranularity* scrollGranularity)
1430 {
1431     switch (keyCode) {
1432     case VKEY_LEFT:
1433         *scrollDirection = ScrollLeft;
1434         *scrollGranularity = ScrollByLine;
1435         break;
1436     case VKEY_RIGHT:
1437         *scrollDirection = ScrollRight;
1438         *scrollGranularity = ScrollByLine;
1439         break;
1440     case VKEY_UP:
1441         *scrollDirection = ScrollUp;
1442         *scrollGranularity = ScrollByLine;
1443         break;
1444     case VKEY_DOWN:
1445         *scrollDirection = ScrollDown;
1446         *scrollGranularity = ScrollByLine;
1447         break;
1448     case VKEY_HOME:
1449         *scrollDirection = ScrollUp;
1450         *scrollGranularity = ScrollByDocument;
1451         break;
1452     case VKEY_END:
1453         *scrollDirection = ScrollDown;
1454         *scrollGranularity = ScrollByDocument;
1455         break;
1456     case VKEY_PRIOR:  // page up
1457         *scrollDirection = ScrollUp;
1458         *scrollGranularity = ScrollByPage;
1459         break;
1460     case VKEY_NEXT:  // page down
1461         *scrollDirection = ScrollDown;
1462         *scrollGranularity = ScrollByPage;
1463         break;
1464     default:
1465         return false;
1466     }
1467
1468     return true;
1469 }
1470
1471 void WebViewImpl::hideSelectPopup()
1472 {
1473     if (m_selectPopup)
1474         m_selectPopup->hidePopup();
1475 }
1476
1477 bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection,
1478                                   ScrollGranularity scrollGranularity)
1479 {
1480     Frame* frame = focusedWebCoreFrame();
1481     if (!frame)
1482         return false;
1483
1484     bool scrollHandled = frame->eventHandler()->scrollOverflow(scrollDirection, scrollGranularity);
1485     Frame* currentFrame = frame;
1486     while (!scrollHandled && currentFrame) {
1487         scrollHandled = currentFrame->view()->scroll(scrollDirection, scrollGranularity);
1488         currentFrame = currentFrame->tree()->parent();
1489     }
1490     return scrollHandled;
1491 }
1492
1493 void  WebViewImpl::popupOpened(WebCore::PopupContainer* popupContainer)
1494 {
1495     if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
1496         ASSERT(!m_selectPopup);
1497         m_selectPopup = popupContainer;
1498     }
1499 }
1500
1501 void  WebViewImpl::popupClosed(WebCore::PopupContainer* popupContainer)
1502 {
1503     if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
1504         ASSERT(m_selectPopup);
1505         m_selectPopup = 0;
1506     }
1507 }
1508
1509 #if ENABLE(PAGE_POPUP)
1510 PagePopup* WebViewImpl::openPagePopup(PagePopupClient* client, const IntRect& originBoundsInRootView)
1511 {
1512     ASSERT(client);
1513     if (hasOpenedPopup())
1514         hidePopups();
1515     ASSERT(!m_pagePopup);
1516
1517     WebWidget* popupWidget = m_client->createPopupMenu(WebPopupTypePage);
1518     ASSERT(popupWidget);
1519     m_pagePopup = static_cast<WebPagePopupImpl*>(popupWidget);
1520     if (!m_pagePopup->initialize(this, client, originBoundsInRootView)) {
1521         m_pagePopup->closePopup();
1522         m_pagePopup = 0;
1523     }
1524     return m_pagePopup.get();
1525 }
1526
1527 void WebViewImpl::closePagePopup(PagePopup* popup)
1528 {
1529     ASSERT(popup);
1530     WebPagePopupImpl* popupImpl = static_cast<WebPagePopupImpl*>(popup);
1531     ASSERT(m_pagePopup.get() == popupImpl);
1532     if (m_pagePopup.get() != popupImpl)
1533         return;
1534     m_pagePopup->closePopup();
1535     m_pagePopup = 0;
1536 }
1537 #endif
1538
1539 void WebViewImpl::hideAutofillPopup()
1540 {
1541     if (m_autofillPopupShowing) {
1542         m_autofillPopup->hidePopup();
1543         m_autofillPopupShowing = false;
1544     }
1545 }
1546
1547 WebHelperPluginImpl* WebViewImpl::createHelperPlugin(const String& pluginType)
1548 {
1549     WebWidget* popupWidget = m_client->createPopupMenu(WebPopupTypeHelperPlugin);
1550     ASSERT(popupWidget);
1551     WebHelperPluginImpl* helperPlugin = static_cast<WebHelperPluginImpl*>(popupWidget);
1552
1553     if (!helperPlugin->initialize(this, pluginType)) {
1554         helperPlugin->closeHelperPlugin();
1555         helperPlugin = 0;
1556     }
1557     return helperPlugin;
1558 }
1559
1560 Frame* WebViewImpl::focusedWebCoreFrame() const
1561 {
1562     return m_page ? m_page->focusController()->focusedOrMainFrame() : 0;
1563 }
1564
1565 WebViewImpl* WebViewImpl::fromPage(Page* page)
1566 {
1567     if (!page)
1568         return 0;
1569
1570     ChromeClientImpl* chromeClient = static_cast<ChromeClientImpl*>(page->chrome()->client());
1571     return static_cast<WebViewImpl*>(chromeClient->webView());
1572 }
1573
1574 PageGroup* WebViewImpl::defaultPageGroup()
1575 {
1576     return PageGroup::pageGroup(pageGroupName);
1577 }
1578
1579 // WebWidget ------------------------------------------------------------------
1580
1581 void WebViewImpl::close()
1582 {
1583     if (m_page) {
1584         // Initiate shutdown for the entire frameset.  This will cause a lot of
1585         // notifications to be sent.
1586         if (m_page->mainFrame())
1587             m_page->mainFrame()->loader()->frameDetached();
1588
1589         m_page.clear();
1590     }
1591
1592     // Should happen after m_page.clear().
1593     if (m_devToolsAgent)
1594         m_devToolsAgent.clear();
1595
1596     // Reset the delegate to prevent notifications being sent as we're being
1597     // deleted.
1598     m_client = 0;
1599
1600     deref();  // Balances ref() acquired in WebView::create
1601 }
1602
1603 void WebViewImpl::willStartLiveResize()
1604 {
1605     if (mainFrameImpl() && mainFrameImpl()->frameView())
1606         mainFrameImpl()->frameView()->willStartLiveResize();
1607
1608     Frame* frame = mainFrameImpl()->frame();
1609     WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
1610     if (pluginContainer)
1611         pluginContainer->willStartLiveResize();
1612 }
1613
1614 WebSize WebViewImpl::size()
1615 {
1616     if (isFixedLayoutModeEnabled() && settingsImpl()->applyPageScaleFactorInCompositor())
1617         return layoutSize();
1618
1619     return m_size;
1620 }
1621
1622 void WebViewImpl::resize(const WebSize& newSize)
1623 {
1624     if (m_shouldAutoResize || m_size == newSize)
1625         return;
1626
1627     FrameView* view = mainFrameImpl()->frameView();
1628     if (!view)
1629         return;
1630
1631     WebSize oldSize = m_size;
1632     float oldPageScaleFactor = pageScaleFactor();
1633     IntSize oldScrollOffset = view->scrollOffset();
1634     int oldFixedLayoutWidth = fixedLayoutSize().width;
1635
1636     m_size = newSize;
1637
1638 #if ENABLE(VIEWPORT)
1639     ViewportArguments viewportArguments = mainFrameImpl()->frame()->document()->viewportArguments();
1640     m_page->chrome()->client()->dispatchViewportPropertiesDidChange(viewportArguments);
1641 #endif
1642
1643     WebDevToolsAgentPrivate* agentPrivate = devToolsAgentPrivate();
1644     if (agentPrivate)
1645         agentPrivate->webViewResized(newSize);
1646     if (!agentPrivate || !agentPrivate->metricsOverridden()) {
1647         WebFrameImpl* webFrame = mainFrameImpl();
1648         if (webFrame->frameView())
1649             webFrame->frameView()->resize(size());
1650     }
1651
1652 #if ENABLE(VIEWPORT)
1653     if (settings()->viewportEnabled()) {
1654         computePageScaleFactorLimits();
1655
1656         // When the device rotates:
1657         // - If the page width is unchanged, then zoom by new width/old width
1658         //   such as to keep the same content horizontally onscreen.
1659         // - If the page width stretches proportionally to the change in
1660         //   screen width, then don't zoom at all (assuming the content has
1661         //   scaled uniformly, then the same content will be horizontally
1662         //   onscreen).
1663         //   - If the page width partially stretches, then zoom partially to
1664         //   make up the difference.
1665         // In all cases try to keep the same content at the top of the screen.
1666         float viewportWidthRatio = !oldSize.width ? 1 : newSize.width / (float) oldSize.width;
1667         float fixedLayoutWidthRatio = !oldFixedLayoutWidth ? 1 : fixedLayoutSize().width / (float) oldFixedLayoutWidth;
1668         float scaleMultiplier = viewportWidthRatio / fixedLayoutWidthRatio;
1669         if (scaleMultiplier != 1) {
1670             IntSize scrollOffsetAtNewScale = oldScrollOffset;
1671             if (!settingsImpl()->applyPageScaleFactorInCompositor())
1672                 scrollOffsetAtNewScale.scale(scaleMultiplier);
1673             setPageScaleFactor(oldPageScaleFactor * scaleMultiplier, IntPoint(scrollOffsetAtNewScale));
1674         }
1675     }
1676 #endif
1677
1678     sendResizeEventAndRepaint();
1679 }
1680
1681 void WebViewImpl::willEndLiveResize()
1682 {
1683     if (mainFrameImpl() && mainFrameImpl()->frameView())
1684         mainFrameImpl()->frameView()->willEndLiveResize();
1685
1686     Frame* frame = mainFrameImpl()->frame();
1687     WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
1688     if (pluginContainer)
1689         pluginContainer->willEndLiveResize();
1690 }
1691
1692 void WebViewImpl::willEnterFullScreen()
1693 {
1694 #if ENABLE(FULLSCREEN_API)
1695     if (!m_provisionalFullScreenElement)
1696         return;
1697
1698     // Ensure that this element's document is still attached.
1699     Document* doc = m_provisionalFullScreenElement->document();
1700     if (doc->frame()) {
1701         doc->webkitWillEnterFullScreenForElement(m_provisionalFullScreenElement.get());
1702         m_fullScreenFrame = doc->frame();
1703     }
1704     m_provisionalFullScreenElement.clear();
1705 #endif
1706 }
1707
1708 void WebViewImpl::didEnterFullScreen()
1709 {
1710 #if ENABLE(FULLSCREEN_API)
1711     if (!m_fullScreenFrame)
1712         return;
1713
1714     if (Document* doc = m_fullScreenFrame->document()) {
1715         if (doc->webkitIsFullScreen())
1716             doc->webkitDidEnterFullScreenForElement(0);
1717     }
1718 #endif
1719 }
1720
1721 void WebViewImpl::willExitFullScreen()
1722 {
1723 #if ENABLE(FULLSCREEN_API)
1724     if (!m_fullScreenFrame)
1725         return;
1726
1727     if (Document* doc = m_fullScreenFrame->document()) {
1728         if (doc->webkitIsFullScreen()) {
1729             // When the client exits from full screen we have to call webkitCancelFullScreen to
1730             // notify the document. While doing that, suppress notifications back to the client.
1731             m_isCancelingFullScreen = true;
1732             doc->webkitCancelFullScreen();
1733             m_isCancelingFullScreen = false;
1734             doc->webkitWillExitFullScreenForElement(0);
1735         }
1736     }
1737 #endif
1738 }
1739
1740 void WebViewImpl::didExitFullScreen()
1741 {
1742 #if ENABLE(FULLSCREEN_API)
1743     if (!m_fullScreenFrame)
1744         return;
1745
1746     if (Document* doc = m_fullScreenFrame->document()) {
1747         if (doc->webkitIsFullScreen())
1748             doc->webkitDidExitFullScreenForElement(0);
1749     }
1750
1751     m_fullScreenFrame.clear();
1752 #endif
1753 }
1754
1755 void WebViewImpl::instrumentBeginFrame()
1756 {
1757     InspectorInstrumentation::didBeginFrame(m_page.get());
1758 }
1759
1760 void WebViewImpl::instrumentCancelFrame()
1761 {
1762     InspectorInstrumentation::didCancelFrame(m_page.get());
1763 }
1764
1765 #if ENABLE(BATTERY_STATUS)
1766 void WebViewImpl::updateBatteryStatus(const WebBatteryStatus& status)
1767 {
1768     m_batteryClient->updateBatteryStatus(status);
1769 }
1770 #endif
1771
1772 void WebViewImpl::setCompositorSurfaceReady()
1773 {
1774     m_compositorSurfaceReady = true;
1775     if (m_layerTreeView)
1776         m_layerTreeView->setSurfaceReady();
1777 }
1778
1779 void WebViewImpl::animate(double)
1780 {
1781 #if ENABLE(REQUEST_ANIMATION_FRAME)
1782     double monotonicFrameBeginTime = monotonicallyIncreasingTime();
1783
1784 #if USE(ACCELERATED_COMPOSITING)
1785     // In composited mode, we always go through the compositor so it can apply
1786     // appropriate flow-control mechanisms.
1787     if (isAcceleratedCompositingActive())
1788         m_layerTreeView->updateAnimations(monotonicFrameBeginTime);
1789     else
1790 #endif
1791         updateAnimations(monotonicFrameBeginTime);
1792 #endif
1793 }
1794
1795 void WebViewImpl::willBeginFrame()
1796 {
1797     instrumentBeginFrame();
1798     m_client->willBeginCompositorFrame();
1799 }
1800
1801 void WebViewImpl::didBeginFrame()
1802 {
1803     InspectorInstrumentation::didComposite(m_page.get());
1804
1805     if (m_continuousPaintingEnabled)
1806         ContinuousPainter::setNeedsDisplayRecursive(m_rootGraphicsLayer, m_pageOverlays.get());
1807 }
1808
1809 void WebViewImpl::updateAnimations(double monotonicFrameBeginTime)
1810 {
1811 #if ENABLE(REQUEST_ANIMATION_FRAME)
1812     TRACE_EVENT0("webkit", "WebViewImpl::updateAnimations");
1813
1814     // Create synthetic wheel events as necessary for fling.
1815     if (m_gestureAnimation) {
1816         if (m_gestureAnimation->animate(monotonicFrameBeginTime))
1817             scheduleAnimation();
1818         else {
1819             m_gestureAnimation.clear();
1820             if (m_layerTreeView)
1821                 m_layerTreeView->didStopFlinging();
1822         }
1823     }
1824
1825     if (!m_page)
1826         return;
1827
1828     PageWidgetDelegate::animate(m_page.get(), monotonicFrameBeginTime);
1829 #endif
1830 }
1831
1832 void WebViewImpl::layout()
1833 {
1834     TRACE_EVENT0("webkit", "WebViewImpl::layout");
1835     PageWidgetDelegate::layout(m_page.get());
1836
1837     if (m_linkHighlight)
1838         m_linkHighlight->updateGeometry();
1839 }
1840
1841 void WebViewImpl::enterForceCompositingMode(bool enter)
1842 {
1843     TRACE_EVENT1("webkit", "WebViewImpl::enterForceCompositingMode", "enter", enter);
1844     settingsImpl()->setForceCompositingMode(enter);
1845     if (enter) {
1846         if (!m_page)
1847             return;
1848         Frame* mainFrame = m_page->mainFrame();
1849         if (!mainFrame)
1850             return;
1851         mainFrame->view()->updateCompositingLayersAfterStyleChange();
1852     }
1853 }
1854
1855 #if USE(ACCELERATED_COMPOSITING)
1856 void WebViewImpl::doPixelReadbackToCanvas(WebCanvas* canvas, const IntRect& rect)
1857 {
1858     ASSERT(m_layerTreeView);
1859
1860     SkBitmap target;
1861     target.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height(), rect.width() * 4);
1862     target.allocPixels();
1863     m_layerTreeView->compositeAndReadback(target.getPixels(), rect);
1864 #if (!SK_R32_SHIFT && SK_B32_SHIFT == 16)
1865     // The compositor readback always gives back pixels in BGRA order, but for
1866     // example Android's Skia uses RGBA ordering so the red and blue channels
1867     // need to be swapped.
1868     uint8_t* pixels = reinterpret_cast<uint8_t*>(target.getPixels());
1869     for (size_t i = 0; i < target.getSize(); i += 4)
1870         std::swap(pixels[i], pixels[i + 2]);
1871 #endif
1872     canvas->writePixels(target, rect.x(), rect.y());
1873 }
1874 #endif
1875
1876 void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect, PaintOptions option)
1877 {
1878 #if !OS(ANDROID)
1879     // ReadbackFromCompositorIfAvailable is the only option available on non-Android.
1880     // Ideally, Android would always use ReadbackFromCompositorIfAvailable as well.
1881     ASSERT(option == ReadbackFromCompositorIfAvailable);
1882 #endif
1883
1884     if (option == ReadbackFromCompositorIfAvailable && isAcceleratedCompositingActive()) {
1885 #if USE(ACCELERATED_COMPOSITING)
1886         // If a canvas was passed in, we use it to grab a copy of the
1887         // freshly-rendered pixels.
1888         if (canvas) {
1889             // Clip rect to the confines of the rootLayerTexture.
1890             IntRect resizeRect(rect);
1891             resizeRect.intersect(IntRect(IntPoint(0, 0), m_layerTreeView->deviceViewportSize()));
1892             doPixelReadbackToCanvas(canvas, resizeRect);
1893         }
1894 #endif
1895     } else {
1896         FrameView* view = page()->mainFrame()->view();
1897         PaintBehavior oldPaintBehavior = view->paintBehavior();
1898         if (isAcceleratedCompositingActive()) {
1899             ASSERT(option == ForceSoftwareRenderingAndIgnoreGPUResidentContent);            
1900             view->setPaintBehavior(oldPaintBehavior | PaintBehaviorFlattenCompositingLayers);
1901         }
1902
1903         double paintStart = currentTime();
1904         PageWidgetDelegate::paint(m_page.get(), pageOverlays(), canvas, rect, isTransparent() ? PageWidgetDelegate::Translucent : PageWidgetDelegate::Opaque, m_webSettings->applyDeviceScaleFactorInCompositor());
1905         double paintEnd = currentTime();
1906         double pixelsPerSec = (rect.width * rect.height) / (paintEnd - paintStart);
1907         WebKit::Platform::current()->histogramCustomCounts("Renderer4.SoftwarePaintDurationMS", (paintEnd - paintStart) * 1000, 0, 120, 30);
1908         WebKit::Platform::current()->histogramCustomCounts("Renderer4.SoftwarePaintMegapixPerSecond", pixelsPerSec / 1000000, 10, 210, 30);
1909
1910         if (isAcceleratedCompositingActive()) {
1911             ASSERT(option == ForceSoftwareRenderingAndIgnoreGPUResidentContent);            
1912             view->setPaintBehavior(oldPaintBehavior);
1913         }
1914     }
1915 }
1916
1917 bool WebViewImpl::isTrackingRepaints() const
1918 {
1919     if (!page())
1920         return false;
1921     FrameView* view = page()->mainFrame()->view();
1922     return view->isTrackingRepaints();
1923 }
1924
1925 void WebViewImpl::themeChanged()
1926 {
1927     if (!page())
1928         return;
1929     FrameView* view = page()->mainFrame()->view();
1930
1931     WebRect damagedRect(0, 0, m_size.width, m_size.height);
1932     view->invalidateRect(damagedRect);
1933 }
1934
1935 void WebViewImpl::composite(bool)
1936 {
1937 #if USE(ACCELERATED_COMPOSITING)
1938     if (Platform::current()->compositorSupport()->isThreadingEnabled())
1939         m_layerTreeView->setNeedsRedraw();
1940     else {
1941         ASSERT(isAcceleratedCompositingActive());
1942         if (!page())
1943             return;
1944
1945         m_layerTreeView->composite();
1946     }
1947 #endif
1948 }
1949
1950 void WebViewImpl::setNeedsRedraw()
1951 {
1952 #if USE(ACCELERATED_COMPOSITING)
1953     if (m_layerTreeView && isAcceleratedCompositingActive())
1954         m_layerTreeView->setNeedsRedraw();
1955 #endif
1956 }
1957
1958 bool WebViewImpl::isInputThrottled() const
1959 {
1960 #if USE(ACCELERATED_COMPOSITING)
1961     if (m_layerTreeView && isAcceleratedCompositingActive())
1962         return m_layerTreeView->commitRequested();
1963 #endif
1964     return false;
1965 }
1966
1967 void WebViewImpl::enterFullScreenForElement(WebCore::Element* element)
1968 {
1969     // We are already transitioning to fullscreen for a different element.
1970     if (m_provisionalFullScreenElement) {
1971         m_provisionalFullScreenElement = element;
1972         return;
1973     }
1974
1975     // We are already in fullscreen mode.
1976     if (m_fullScreenFrame) {
1977         m_provisionalFullScreenElement = element;
1978         willEnterFullScreen();
1979         didEnterFullScreen();
1980         return;
1981     }
1982
1983 #if USE(NATIVE_FULLSCREEN_VIDEO)
1984     if (element && element->isMediaElement()) {
1985         HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(element);
1986         if (mediaElement->player() && mediaElement->player()->canEnterFullscreen()) {
1987             mediaElement->player()->enterFullscreen();
1988             m_provisionalFullScreenElement = element;
1989         }
1990         return;
1991     }
1992 #endif
1993
1994     // We need to transition to fullscreen mode.
1995     if (m_client && m_client->enterFullScreen())
1996         m_provisionalFullScreenElement = element;
1997 }
1998
1999 void WebViewImpl::exitFullScreenForElement(WebCore::Element* element)
2000 {
2001     // The client is exiting full screen, so don't send a notification.
2002     if (m_isCancelingFullScreen)
2003         return;
2004 #if USE(NATIVE_FULLSCREEN_VIDEO)
2005     if (element && element->isMediaElement()) {
2006         HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(element);
2007         if (mediaElement->player())
2008             mediaElement->player()->exitFullscreen();
2009         return;
2010     }
2011 #endif
2012     if (m_client)
2013         m_client->exitFullScreen();
2014 }
2015
2016 bool WebViewImpl::hasHorizontalScrollbar()
2017 {
2018     return mainFrameImpl()->frameView()->horizontalScrollbar();
2019 }
2020
2021 bool WebViewImpl::hasVerticalScrollbar()
2022 {
2023     return mainFrameImpl()->frameView()->verticalScrollbar();
2024 }
2025
2026 const WebInputEvent* WebViewImpl::m_currentInputEvent = 0;
2027
2028 bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
2029 {
2030     // If we've started a drag and drop operation, ignore input events until
2031     // we're done.
2032     if (m_doingDragAndDrop)
2033         return true;
2034
2035     // Report the event to be NOT processed by WebKit, so that the browser can handle it appropriately.
2036     if (m_ignoreInputEvents)
2037         return false;
2038
2039     TemporaryChange<const WebInputEvent*> currentEventChange(m_currentInputEvent, &inputEvent);
2040
2041 #if ENABLE(POINTER_LOCK)
2042     if (isPointerLocked() && WebInputEvent::isMouseEventType(inputEvent.type)) {
2043       pointerLockMouseEvent(inputEvent);
2044       return true;
2045     }
2046 #endif
2047
2048     if (m_mouseCaptureNode && WebInputEvent::isMouseEventType(inputEvent.type)) {
2049         // Save m_mouseCaptureNode since mouseCaptureLost() will clear it.
2050         RefPtr<Node> node = m_mouseCaptureNode;
2051
2052         // Not all platforms call mouseCaptureLost() directly.
2053         if (inputEvent.type == WebInputEvent::MouseUp)
2054             mouseCaptureLost();
2055
2056         AtomicString eventType;
2057         switch (inputEvent.type) {
2058         case WebInputEvent::MouseMove:
2059             eventType = eventNames().mousemoveEvent;
2060             break;
2061         case WebInputEvent::MouseLeave:
2062             eventType = eventNames().mouseoutEvent;
2063             break;
2064         case WebInputEvent::MouseDown:
2065             eventType = eventNames().mousedownEvent;
2066             break;
2067         case WebInputEvent::MouseUp:
2068             eventType = eventNames().mouseupEvent;
2069             break;
2070         default:
2071             ASSERT_NOT_REACHED();
2072         }
2073
2074         node->dispatchMouseEvent(
2075               PlatformMouseEventBuilder(mainFrameImpl()->frameView(), *static_cast<const WebMouseEvent*>(&inputEvent)),
2076               eventType, static_cast<const WebMouseEvent*>(&inputEvent)->clickCount);
2077         return true;
2078     }
2079
2080     if (!m_layerTreeView)
2081         return PageWidgetDelegate::handleInputEvent(m_page.get(), *this, inputEvent);
2082
2083     const WebInputEvent* inputEventTransformed = &inputEvent;
2084     WebMouseEvent mouseEvent;
2085     WebGestureEvent gestureEvent;
2086     if (WebInputEvent::isMouseEventType(inputEvent.type)) {
2087         mouseEvent = *static_cast<const WebMouseEvent*>(&inputEvent);
2088
2089         IntPoint transformedLocation = roundedIntPoint(m_layerTreeView->adjustEventPointForPinchZoom(WebFloatPoint(mouseEvent.x, mouseEvent.y)));
2090         mouseEvent.x = transformedLocation.x();
2091         mouseEvent.y = transformedLocation.y();
2092         inputEventTransformed = static_cast<const WebInputEvent*>(&mouseEvent);
2093     } else if (WebInputEvent::isGestureEventType(inputEvent.type)) {
2094         gestureEvent = *static_cast<const WebGestureEvent*>(&inputEvent);
2095
2096         IntPoint transformedLocation = roundedIntPoint(m_layerTreeView->adjustEventPointForPinchZoom(WebFloatPoint(gestureEvent.x, gestureEvent.y)));
2097         gestureEvent.x = transformedLocation.x();
2098         gestureEvent.y = transformedLocation.y();
2099         inputEventTransformed = static_cast<const WebInputEvent*>(&gestureEvent);
2100     }
2101
2102     bool handled = PageWidgetDelegate::handleInputEvent(m_page.get(), *this, *inputEventTransformed);
2103     return handled;
2104 }
2105
2106 void WebViewImpl::mouseCaptureLost()
2107 {
2108     m_mouseCaptureNode = 0;
2109 }
2110
2111 void WebViewImpl::setFocus(bool enable)
2112 {
2113     m_page->focusController()->setFocused(enable);
2114     if (enable) {
2115         m_page->focusController()->setActive(true);
2116         RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
2117         if (focusedFrame) {
2118             Node* focusedNode = focusedFrame->document()->focusedNode();
2119             if (focusedNode && focusedNode->isElementNode()
2120                 && focusedFrame->selection()->selection().isNone()) {
2121                 // If the selection was cleared while the WebView was not
2122                 // focused, then the focus element shows with a focus ring but
2123                 // no caret and does respond to keyboard inputs.
2124                 Element* element = static_cast<Element*>(focusedNode);
2125                 if (element->isTextFormControl())
2126                     element->updateFocusAppearance(true);
2127                 else if (focusedNode->isContentEditable()) {
2128                     // updateFocusAppearance() selects all the text of
2129                     // contentseditable DIVs. So we set the selection explicitly
2130                     // instead. Note that this has the side effect of moving the
2131                     // caret back to the beginning of the text.
2132                     Position position(focusedNode, 0,
2133                                       Position::PositionIsOffsetInAnchor);
2134                     focusedFrame->selection()->setSelection(
2135                         VisibleSelection(position, SEL_DEFAULT_AFFINITY));
2136                 }
2137             }
2138         }
2139         m_imeAcceptEvents = true;
2140     } else {
2141         hidePopups();
2142
2143         // Clear focus on the currently focused frame if any.
2144         if (!m_page)
2145             return;
2146
2147         Frame* frame = m_page->mainFrame();
2148         if (!frame)
2149             return;
2150
2151         RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
2152         if (focusedFrame) {
2153             // Finish an ongoing composition to delete the composition node.
2154             Editor* editor = focusedFrame->editor();
2155             if (editor && editor->hasComposition())
2156                 editor->confirmComposition();
2157             m_imeAcceptEvents = false;
2158         }
2159     }
2160 }
2161
2162 bool WebViewImpl::setComposition(
2163     const WebString& text,
2164     const WebVector<WebCompositionUnderline>& underlines,
2165     int selectionStart,
2166     int selectionEnd)
2167 {
2168     Frame* focused = focusedWebCoreFrame();
2169     if (!focused || !m_imeAcceptEvents)
2170         return false;
2171     Editor* editor = focused->editor();
2172     if (!editor)
2173         return false;
2174
2175     // The input focus has been moved to another WebWidget object.
2176     // We should use this |editor| object only to complete the ongoing
2177     // composition.
2178     if (!editor->canEdit() && !editor->hasComposition())
2179         return false;
2180
2181     // We should verify the parent node of this IME composition node are
2182     // editable because JavaScript may delete a parent node of the composition
2183     // node. In this case, WebKit crashes while deleting texts from the parent
2184     // node, which doesn't exist any longer.
2185     PassRefPtr<Range> range = editor->compositionRange();
2186     if (range) {
2187         Node* node = range->startContainer();
2188         if (!node || !node->isContentEditable())
2189             return false;
2190     }
2191
2192     // If we're not going to fire a keypress event, then the keydown event was
2193     // canceled.  In that case, cancel any existing composition.
2194     if (text.isEmpty() || m_suppressNextKeypressEvent) {
2195         // A browser process sent an IPC message which does not contain a valid
2196         // string, which means an ongoing composition has been canceled.
2197         // If the ongoing composition has been canceled, replace the ongoing
2198         // composition string with an empty string and complete it.
2199         String emptyString;
2200         Vector<CompositionUnderline> emptyUnderlines;
2201         editor->setComposition(emptyString, emptyUnderlines, 0, 0);
2202         return text.isEmpty();
2203     }
2204
2205     // When the range of composition underlines overlap with the range between
2206     // selectionStart and selectionEnd, WebKit somehow won't paint the selection
2207     // at all (see InlineTextBox::paint() function in InlineTextBox.cpp).
2208     // But the selection range actually takes effect.
2209     editor->setComposition(String(text),
2210                            CompositionUnderlineVectorBuilder(underlines),
2211                            selectionStart, selectionEnd);
2212
2213     return editor->hasComposition();
2214 }
2215
2216 bool WebViewImpl::confirmComposition()
2217 {
2218     return confirmComposition(WebString());
2219 }
2220
2221 bool WebViewImpl::confirmComposition(const WebString& text)
2222 {
2223     Frame* focused = focusedWebCoreFrame();
2224     if (!focused || !m_imeAcceptEvents)
2225         return false;
2226     Editor* editor = focused->editor();
2227     if (!editor || (!editor->hasComposition() && !text.length()))
2228         return false;
2229
2230     // We should verify the parent node of this IME composition node are
2231     // editable because JavaScript may delete a parent node of the composition
2232     // node. In this case, WebKit crashes while deleting texts from the parent
2233     // node, which doesn't exist any longer.
2234     PassRefPtr<Range> range = editor->compositionRange();
2235     if (range) {
2236         Node* node = range->startContainer();
2237         if (!node || !node->isContentEditable())
2238             return false;
2239     }
2240
2241     if (editor->hasComposition()) {
2242         if (text.length())
2243             editor->confirmComposition(String(text));
2244         else
2245             editor->confirmComposition();
2246     } else
2247         editor->insertText(String(text), 0);
2248
2249     return true;
2250 }
2251
2252 bool WebViewImpl::compositionRange(size_t* location, size_t* length)
2253 {
2254     Frame* focused = focusedWebCoreFrame();
2255     if (!focused || !focused->selection() || !m_imeAcceptEvents)
2256         return false;
2257     Editor* editor = focused->editor();
2258     if (!editor || !editor->hasComposition())
2259         return false;
2260
2261     RefPtr<Range> range = editor->compositionRange();
2262     if (!range)
2263         return false;
2264
2265     if (TextIterator::getLocationAndLengthFromRange(focused->selection()->rootEditableElementOrDocumentElement(), range.get(), *location, *length))
2266         return true;
2267     return false;
2268 }
2269
2270 WebTextInputInfo WebViewImpl::textInputInfo()
2271 {
2272     WebTextInputInfo info;
2273
2274     Frame* focused = focusedWebCoreFrame();
2275     if (!focused)
2276         return info;
2277
2278     Editor* editor = focused->editor();
2279     if (!editor || !editor->canEdit())
2280         return info;
2281
2282     FrameSelection* selection = focused->selection();
2283     if (!selection)
2284         return info;
2285
2286     Node* node = selection->selection().rootEditableElement();
2287     if (!node)
2288         return info;
2289
2290     info.type = textInputType();
2291     if (info.type == WebTextInputTypeNone)
2292         return info;
2293
2294     info.value = plainText(rangeOfContents(node).get());
2295
2296     if (info.value.isEmpty())
2297         return info;
2298
2299     size_t location;
2300     size_t length;
2301     RefPtr<Range> range = selection->selection().firstRange();
2302     if (range && TextIterator::getLocationAndLengthFromRange(selection->rootEditableElement(), range.get(), location, length)) {
2303         info.selectionStart = location;
2304         info.selectionEnd = location + length;
2305     }
2306     range = editor->compositionRange();
2307     if (range && TextIterator::getLocationAndLengthFromRange(selection->rootEditableElement(), range.get(), location, length)) {
2308         info.compositionStart = location;
2309         info.compositionEnd = location + length;
2310     }
2311
2312     return info;
2313 }
2314
2315 WebTextInputType WebViewImpl::textInputType()
2316 {
2317     Node* node = focusedWebCoreNode();
2318     if (!node)
2319         return WebTextInputTypeNone;
2320
2321     if (node->hasTagName(HTMLNames::inputTag)) {
2322         HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
2323
2324         if (input->isDisabledOrReadOnly())
2325             return WebTextInputTypeNone;
2326
2327         if (input->isPasswordField())
2328             return WebTextInputTypePassword;
2329         if (input->isSearchField())
2330             return WebTextInputTypeSearch;
2331         if (input->isEmailField())
2332             return WebTextInputTypeEmail;
2333         if (input->isNumberField())
2334             return WebTextInputTypeNumber;
2335         if (input->isTelephoneField())
2336             return WebTextInputTypeTelephone;
2337         if (input->isURLField())
2338             return WebTextInputTypeURL;
2339         if (input->isDateField())
2340             return WebTextInputTypeDate;
2341         if (input->isDateTimeField())
2342             return WebTextInputTypeDateTime;
2343         if (input->isDateTimeLocalField())
2344             return WebTextInputTypeDateTimeLocal;
2345         if (input->isMonthField())
2346             return WebTextInputTypeMonth;
2347         if (input->isTimeField())
2348             return WebTextInputTypeTime;
2349         if (input->isWeekField())
2350             return WebTextInputTypeWeek;
2351         if (input->isTextField())
2352             return WebTextInputTypeText;
2353
2354         return WebTextInputTypeNone;
2355     }
2356
2357     if (node->hasTagName(HTMLNames::textareaTag)) {
2358         if (static_cast<HTMLTextAreaElement*>(node)->isDisabledOrReadOnly())
2359             return WebTextInputTypeNone;
2360         return WebTextInputTypeTextArea;
2361     }
2362
2363     if (node->shouldUseInputMethod())
2364         return WebTextInputTypeContentEditable;
2365
2366     return WebTextInputTypeNone;
2367 }
2368
2369 bool WebViewImpl::selectionBounds(WebRect& anchor, WebRect& focus) const
2370 {
2371     const Frame* frame = focusedWebCoreFrame();
2372     if (!frame)
2373         return false;
2374     FrameSelection* selection = frame->selection();
2375     if (!selection)
2376         return false;
2377
2378     if (selection->isCaret()) {
2379         anchor = focus = frame->view()->contentsToWindow(selection->absoluteCaretBounds());
2380         return true;
2381     }
2382
2383     RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange();
2384     if (!selectedRange)
2385         return false;
2386
2387     RefPtr<Range> range(Range::create(selectedRange->startContainer()->document(),
2388                                       selectedRange->startContainer(),
2389                                       selectedRange->startOffset(),
2390                                       selectedRange->startContainer(),
2391                                       selectedRange->startOffset()));
2392     anchor = frame->editor()->firstRectForRange(range.get());
2393
2394     range = Range::create(selectedRange->endContainer()->document(),
2395                           selectedRange->endContainer(),
2396                           selectedRange->endOffset(),
2397                           selectedRange->endContainer(),
2398                           selectedRange->endOffset());
2399     focus = frame->editor()->firstRectForRange(range.get());
2400
2401     anchor = frame->view()->contentsToWindow(anchor);
2402     focus = frame->view()->contentsToWindow(focus);
2403
2404     if (!frame->selection()->selection().isBaseFirst())
2405         std::swap(anchor, focus);
2406     return true;
2407 }
2408
2409 bool WebViewImpl::selectionTextDirection(WebTextDirection& start, WebTextDirection& end) const
2410 {
2411     const Frame* frame = focusedWebCoreFrame();
2412     if (!frame)
2413         return false;
2414     FrameSelection* selection = frame->selection();
2415     if (!selection)
2416         return false;
2417     if (!selection->toNormalizedRange())
2418         return false;
2419     start = selection->start().primaryDirection() == RTL ? WebTextDirectionRightToLeft : WebTextDirectionLeftToRight;
2420     end = selection->end().primaryDirection() == RTL ? WebTextDirectionRightToLeft : WebTextDirectionLeftToRight;
2421     return true;
2422 }
2423
2424 bool WebViewImpl::setEditableSelectionOffsets(int start, int end)
2425 {
2426     const Frame* focused = focusedWebCoreFrame();
2427     if (!focused)
2428         return false;
2429
2430     Editor* editor = focused->editor();
2431     if (!editor || !editor->canEdit())
2432         return false;
2433
2434     return editor->setSelectionOffsets(start, end);
2435 }
2436
2437 bool WebViewImpl::setCompositionFromExistingText(int compositionStart, int compositionEnd, const WebVector<WebCompositionUnderline>& underlines)
2438 {
2439     const Frame* focused = focusedWebCoreFrame();
2440     if (!focused)
2441         return false;
2442
2443     Editor* editor = focused->editor();
2444     if (!editor || !editor->canEdit())
2445         return false;
2446
2447     editor->cancelComposition();
2448
2449     if (compositionStart == compositionEnd)
2450         return true;
2451
2452     size_t location;
2453     size_t length;
2454     caretOrSelectionRange(&location, &length);
2455     editor->setIgnoreCompositionSelectionChange(true);
2456     editor->setSelectionOffsets(compositionStart, compositionEnd);
2457     String text = editor->selectedText();
2458     focused->document()->execCommand("delete", true);
2459     editor->setComposition(text, CompositionUnderlineVectorBuilder(underlines), 0, 0);
2460     editor->setSelectionOffsets(location, location + length);
2461     editor->setIgnoreCompositionSelectionChange(false);
2462
2463     return true;
2464 }
2465
2466 void WebViewImpl::extendSelectionAndDelete(int before, int after)
2467 {
2468     const Frame* focused = focusedWebCoreFrame();
2469     if (!focused)
2470         return;
2471
2472     Editor* editor = focused->editor();
2473     if (!editor || !editor->canEdit())
2474         return;
2475
2476     FrameSelection* selection = focused->selection();
2477     if (!selection)
2478         return;
2479
2480     size_t location;
2481     size_t length;
2482     RefPtr<Range> range = selection->selection().firstRange();
2483     if (range && TextIterator::getLocationAndLengthFromRange(selection->rootEditableElement(), range.get(), location, length)) {
2484         editor->setSelectionOffsets(max(static_cast<int>(location) - before, 0), location + length + after);
2485         focused->document()->execCommand("delete", true);
2486     }
2487 }
2488
2489 bool WebViewImpl::isSelectionEditable() const
2490 {
2491     const Frame* frame = focusedWebCoreFrame();
2492     if (!frame)
2493         return false;
2494     return frame->selection()->isContentEditable();
2495 }
2496
2497 WebColor WebViewImpl::backgroundColor() const
2498 {
2499     if (!m_page)
2500         return Color::white;
2501     FrameView* view = m_page->mainFrame()->view();
2502     Color backgroundColor = view->documentBackgroundColor();
2503     if (!backgroundColor.isValid())
2504         return Color::white;
2505     return backgroundColor.rgb();
2506 }
2507
2508 bool WebViewImpl::caretOrSelectionRange(size_t* location, size_t* length)
2509 {
2510     const Frame* focused = focusedWebCoreFrame();
2511     if (!focused)
2512         return false;
2513
2514     FrameSelection* selection = focused->selection();
2515     if (!selection)
2516         return false;
2517
2518     RefPtr<Range> range = selection->selection().firstRange();
2519     if (!range)
2520         return false;
2521
2522     if (TextIterator::getLocationAndLengthFromRange(selection->rootEditableElementOrDocumentElement(), range.get(), *location, *length))
2523         return true;
2524     return false;
2525 }
2526
2527 void WebViewImpl::setTextDirection(WebTextDirection direction)
2528 {
2529     // The Editor::setBaseWritingDirection() function checks if we can change
2530     // the text direction of the selected node and updates its DOM "dir"
2531     // attribute and its CSS "direction" property.
2532     // So, we just call the function as Safari does.
2533     const Frame* focused = focusedWebCoreFrame();
2534     if (!focused)
2535         return;
2536
2537     Editor* editor = focused->editor();
2538     if (!editor || !editor->canEdit())
2539         return;
2540
2541     switch (direction) {
2542     case WebTextDirectionDefault:
2543         editor->setBaseWritingDirection(NaturalWritingDirection);
2544         break;
2545
2546     case WebTextDirectionLeftToRight:
2547         editor->setBaseWritingDirection(LeftToRightWritingDirection);
2548         break;
2549
2550     case WebTextDirectionRightToLeft:
2551         editor->setBaseWritingDirection(RightToLeftWritingDirection);
2552         break;
2553
2554     default:
2555         notImplemented();
2556         break;
2557     }
2558 }
2559
2560 bool WebViewImpl::isAcceleratedCompositingActive() const
2561 {
2562 #if USE(ACCELERATED_COMPOSITING)
2563     return m_isAcceleratedCompositingActive;
2564 #else
2565     return false;
2566 #endif
2567 }
2568
2569 void WebViewImpl::willCloseLayerTreeView()
2570 {
2571     setIsAcceleratedCompositingActive(false);
2572     m_layerTreeView = 0;
2573 }
2574
2575 void WebViewImpl::didAcquirePointerLock()
2576 {
2577 #if ENABLE(POINTER_LOCK)
2578     if (page())
2579         page()->pointerLockController()->didAcquirePointerLock();
2580 #endif
2581 }
2582
2583 void WebViewImpl::didNotAcquirePointerLock()
2584 {
2585 #if ENABLE(POINTER_LOCK)
2586     if (page())
2587         page()->pointerLockController()->didNotAcquirePointerLock();
2588 #endif
2589 }
2590
2591 void WebViewImpl::didLosePointerLock()
2592 {
2593 #if ENABLE(POINTER_LOCK)
2594     if (page())
2595         page()->pointerLockController()->didLosePointerLock();
2596 #endif
2597 }
2598
2599 void WebViewImpl::didChangeWindowResizerRect()
2600 {
2601     if (mainFrameImpl()->frameView())
2602         mainFrameImpl()->frameView()->windowResizerRectChanged();
2603 }
2604
2605 // WebView --------------------------------------------------------------------
2606
2607 WebSettingsImpl* WebViewImpl::settingsImpl()
2608 {
2609     if (!m_webSettings)
2610         m_webSettings = adoptPtr(new WebSettingsImpl(m_page->settings()));
2611     ASSERT(m_webSettings);
2612     return m_webSettings.get();
2613 }
2614
2615 WebSettings* WebViewImpl::settings()
2616 {
2617     return settingsImpl();
2618 }
2619
2620 WebString WebViewImpl::pageEncoding() const
2621 {
2622     if (!m_page)
2623         return WebString();
2624
2625     // FIXME: Is this check needed?
2626     if (!m_page->mainFrame()->document()->loader())
2627         return WebString();
2628
2629     return m_page->mainFrame()->document()->encoding();
2630 }
2631
2632 void WebViewImpl::setPageEncoding(const WebString& encodingName)
2633 {
2634     if (!m_page)
2635         return;
2636
2637     // Only change override encoding, don't change default encoding.
2638     // Note that the new encoding must be 0 if it isn't supposed to be set.
2639     String newEncodingName;
2640     if (!encodingName.isEmpty())
2641         newEncodingName = encodingName;
2642     m_page->mainFrame()->loader()->reloadWithOverrideEncoding(newEncodingName);
2643 }
2644
2645 bool WebViewImpl::dispatchBeforeUnloadEvent()
2646 {
2647     // FIXME: This should really cause a recursive depth-first walk of all
2648     // frames in the tree, calling each frame's onbeforeunload.  At the moment,
2649     // we're consistent with Safari 3.1, not IE/FF.
2650     Frame* frame = m_page->mainFrame();
2651     if (!frame)
2652         return true;
2653
2654     return frame->loader()->shouldClose();
2655 }
2656
2657 void WebViewImpl::dispatchUnloadEvent()
2658 {
2659     // Run unload handlers.
2660     m_page->mainFrame()->loader()->closeURL();
2661 }
2662
2663 WebFrame* WebViewImpl::mainFrame()
2664 {
2665     return mainFrameImpl();
2666 }
2667
2668 WebFrame* WebViewImpl::findFrameByName(
2669     const WebString& name, WebFrame* relativeToFrame)
2670 {
2671     if (!relativeToFrame)
2672         relativeToFrame = mainFrame();
2673     Frame* frame = static_cast<WebFrameImpl*>(relativeToFrame)->frame();
2674     frame = frame->tree()->find(name);
2675     return WebFrameImpl::fromFrame(frame);
2676 }
2677
2678 WebFrame* WebViewImpl::focusedFrame()
2679 {
2680     return WebFrameImpl::fromFrame(focusedWebCoreFrame());
2681 }
2682
2683 void WebViewImpl::setFocusedFrame(WebFrame* frame)
2684 {
2685     if (!frame) {
2686         // Clears the focused frame if any.
2687         Frame* frame = focusedWebCoreFrame();
2688         if (frame)
2689             frame->selection()->setFocused(false);
2690         return;
2691     }
2692     WebFrameImpl* frameImpl = static_cast<WebFrameImpl*>(frame);
2693     Frame* webcoreFrame = frameImpl->frame();
2694     webcoreFrame->page()->focusController()->setFocusedFrame(webcoreFrame);
2695 }
2696
2697 void WebViewImpl::setInitialFocus(bool reverse)
2698 {
2699     if (!m_page)
2700         return;
2701
2702     // Since we don't have a keyboard event, we'll create one.
2703     WebKeyboardEvent keyboardEvent;
2704     keyboardEvent.type = WebInputEvent::RawKeyDown;
2705     if (reverse)
2706         keyboardEvent.modifiers = WebInputEvent::ShiftKey;
2707
2708     // VK_TAB which is only defined on Windows.
2709     keyboardEvent.windowsKeyCode = 0x09;
2710     PlatformKeyboardEventBuilder platformEvent(keyboardEvent);
2711     RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0);
2712
2713     Frame* frame = page()->focusController()->focusedOrMainFrame();
2714     if (Document* document = frame->document())
2715         document->setFocusedNode(0);
2716     page()->focusController()->setInitialFocus(
2717         reverse ? FocusDirectionBackward : FocusDirectionForward,
2718         webkitEvent.get());
2719 }
2720
2721 void WebViewImpl::clearFocusedNode()
2722 {
2723     RefPtr<Frame> frame = focusedWebCoreFrame();
2724     if (!frame)
2725         return;
2726
2727     RefPtr<Document> document = frame->document();
2728     if (!document)
2729         return;
2730
2731     RefPtr<Node> oldFocusedNode = document->focusedNode();
2732
2733     // Clear the focused node.
2734     document->setFocusedNode(0);
2735
2736     if (!oldFocusedNode)
2737         return;
2738
2739     // If a text field has focus, we need to make sure the selection controller
2740     // knows to remove selection from it. Otherwise, the text field is still
2741     // processing keyboard events even though focus has been moved to the page and
2742     // keystrokes get eaten as a result.
2743     if (oldFocusedNode->isContentEditable()
2744         || (oldFocusedNode->isElementNode()
2745             && static_cast<Element*>(oldFocusedNode.get())->isTextFormControl())) {
2746         frame->selection()->clear();
2747     }
2748 }
2749
2750 void WebViewImpl::scrollFocusedNodeIntoView()
2751 {
2752     Node* focusedNode = focusedWebCoreNode();
2753     if (focusedNode && focusedNode->isElementNode()) {
2754         Element* elementNode = static_cast<Element*>(focusedNode);
2755         elementNode->scrollIntoViewIfNeeded(true);
2756     }
2757 }
2758
2759 void WebViewImpl::scrollFocusedNodeIntoRect(const WebRect& rect)
2760 {
2761     Frame* frame = page()->mainFrame();
2762     Node* focusedNode = focusedWebCoreNode();
2763     if (!frame || !frame->view() || !focusedNode || !focusedNode->isElementNode())
2764         return;
2765
2766     if (!m_webSettings->autoZoomFocusedNodeToLegibleScale()) {
2767         Element* elementNode = static_cast<Element*>(focusedNode);
2768         frame->view()->scrollElementToRect(elementNode, IntRect(rect.x, rect.y, rect.width, rect.height));
2769         return;
2770     }
2771
2772 #if ENABLE(GESTURE_EVENTS)
2773     focusedNode->document()->updateLayoutIgnorePendingStylesheets();
2774
2775     // 'caret' is rect encompassing the blinking cursor.
2776     IntRect textboxRect = focusedNode->document()->view()->contentsToWindow(pixelSnappedIntRect(focusedNode->Node::boundingBox()));
2777     WebRect caret, end;
2778     selectionBounds(caret, end);
2779
2780     // Pick a scale which is reasonably readable. This is the scale at which
2781     // the caret height will become minReadableCaretHeight (adjusted for dpi
2782     // and font scale factor).
2783     float targetScale = deviceScaleFactor();
2784 #if ENABLE(TEXT_AUTOSIZING)
2785     if (page() && page()->settings())
2786         targetScale *= page()->settings()->textAutosizingFontScaleFactor();
2787 #endif
2788     const float newScale = clampPageScaleFactorToLimits(pageScaleFactor() * minReadableCaretHeight * targetScale / caret.height);
2789     const float deltaScale = newScale / pageScaleFactor();
2790
2791     // Convert the rects to absolute space in the new scale.
2792     IntRect textboxRectInDocumentCoordinates = textboxRect;
2793     textboxRectInDocumentCoordinates.move(mainFrame()->scrollOffset());
2794     textboxRectInDocumentCoordinates.scale(deltaScale);
2795     IntRect caretInDocumentCoordinates = caret;
2796     caretInDocumentCoordinates.move(mainFrame()->scrollOffset());
2797     caretInDocumentCoordinates.scale(deltaScale);
2798
2799     IntPoint newOffset;
2800     if (textboxRectInDocumentCoordinates.width() <= m_size.width) {
2801         // Field is narrower than screen. Try to leave padding on left so field's
2802         // label is visible, but it's more important to ensure entire field is
2803         // onscreen.
2804         int idealLeftPadding = m_size.width * leftBoxRatio;
2805         int maxLeftPaddingKeepingBoxOnscreen = m_size.width - textboxRectInDocumentCoordinates.width();
2806         newOffset.setX(textboxRectInDocumentCoordinates.x() - min<int>(idealLeftPadding, maxLeftPaddingKeepingBoxOnscreen));
2807     } else {
2808         // Field is wider than screen. Try to left-align field, unless caret would
2809         // be offscreen, in which case right-align the caret.
2810         newOffset.setX(max<int>(textboxRectInDocumentCoordinates.x(), caretInDocumentCoordinates.x() + caretInDocumentCoordinates.width() + caretPadding - m_size.width));
2811     }
2812     if (textboxRectInDocumentCoordinates.height() <= m_size.height) {
2813         // Field is shorter than screen. Vertically center it.
2814         newOffset.setY(textboxRectInDocumentCoordinates.y() - (m_size.height - textboxRectInDocumentCoordinates.height()) / 2);
2815     } else {
2816         // Field is taller than screen. Try to top align field, unless caret would
2817         // be offscreen, in which case bottom-align the caret.
2818         newOffset.setY(max<int>(textboxRectInDocumentCoordinates.y(), caretInDocumentCoordinates.y() + caretInDocumentCoordinates.height() + caretPadding - m_size.height));
2819     }
2820
2821     bool needAnimation = false;
2822     // If we are at less than the target zoom level, zoom in.
2823     if (deltaScale > minScaleChangeToTriggerZoom)
2824         needAnimation = true;
2825     // If the caret is offscreen, then animate.
2826     IntRect sizeRect(0, 0, m_size.width, m_size.height);
2827     if (!sizeRect.contains(caret))
2828         needAnimation = true;
2829     // If the box is partially offscreen and it's possible to bring it fully
2830     // onscreen, then animate.
2831     if (sizeRect.contains(textboxRectInDocumentCoordinates.width(), textboxRectInDocumentCoordinates.height()) && !sizeRect.contains(textboxRect))
2832         needAnimation = true;
2833
2834     if (needAnimation)
2835         startPageScaleAnimation(newOffset, false, newScale, scrollAndScaleAnimationDurationInSeconds);
2836 #endif
2837 }
2838
2839 void WebViewImpl::advanceFocus(bool reverse)
2840 {
2841     page()->focusController()->advanceFocus(reverse ? FocusDirectionBackward : FocusDirectionForward, 0);
2842 }
2843
2844 double WebViewImpl::zoomLevel()
2845 {
2846     return m_zoomLevel;
2847 }
2848
2849 double WebViewImpl::setZoomLevel(bool textOnly, double zoomLevel)
2850 {
2851     if (zoomLevel < m_minimumZoomLevel)
2852         m_zoomLevel = m_minimumZoomLevel;
2853     else if (zoomLevel > m_maximumZoomLevel)
2854         m_zoomLevel = m_maximumZoomLevel;
2855     else
2856         m_zoomLevel = zoomLevel;
2857
2858     Frame* frame = mainFrameImpl()->frame();
2859     WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
2860     if (pluginContainer)
2861         pluginContainer->plugin()->setZoomLevel(m_zoomLevel, textOnly);
2862     else {
2863         float zoomFactor = static_cast<float>(zoomLevelToZoomFactor(m_zoomLevel));
2864         if (textOnly)
2865             frame->setPageAndTextZoomFactors(1, zoomFactor * m_emulatedTextZoomFactor);
2866         else
2867             frame->setPageAndTextZoomFactors(zoomFactor, m_emulatedTextZoomFactor);
2868     }
2869     return m_zoomLevel;
2870 }
2871
2872 void WebViewImpl::zoomLimitsChanged(double minimumZoomLevel,
2873                                     double maximumZoomLevel)
2874 {
2875     m_minimumZoomLevel = minimumZoomLevel;
2876     m_maximumZoomLevel = maximumZoomLevel;
2877     m_client->zoomLimitsChanged(m_minimumZoomLevel, m_maximumZoomLevel);
2878 }
2879
2880 void WebViewImpl::fullFramePluginZoomLevelChanged(double zoomLevel)
2881 {
2882     if (zoomLevel == m_zoomLevel)
2883         return;
2884
2885     m_zoomLevel = max(min(zoomLevel, m_maximumZoomLevel), m_minimumZoomLevel);
2886     m_client->zoomLevelChanged();
2887 }
2888
2889 double WebView::zoomLevelToZoomFactor(double zoomLevel)
2890 {
2891     return pow(textSizeMultiplierRatio, zoomLevel);
2892 }
2893
2894 double WebView::zoomFactorToZoomLevel(double factor)
2895 {
2896     // Since factor = 1.2^level, level = log(factor) / log(1.2)
2897     return log(factor) / log(textSizeMultiplierRatio);
2898 }
2899
2900 float WebViewImpl::pageScaleFactor() const
2901 {
2902     if (!page())
2903         return 1;
2904
2905     return page()->pageScaleFactor();
2906 }
2907
2908 bool WebViewImpl::isPageScaleFactorSet() const
2909 {
2910     return m_pageScaleFactorIsSet;
2911 }
2912
2913 float WebViewImpl::clampPageScaleFactorToLimits(float scaleFactor)
2914 {
2915     return min(max(scaleFactor, m_minimumPageScaleFactor), m_maximumPageScaleFactor);
2916 }
2917
2918 WebPoint WebViewImpl::clampOffsetAtScale(const WebPoint& offset, float scale)
2919 {
2920     // This is the scaled content size. We need to convert it to the new scale factor.
2921     WebSize contentSize = mainFrame()->contentsSize();
2922     float deltaScale = scale / pageScaleFactor();
2923     int docWidthAtNewScale = contentSize.width * deltaScale;
2924     int docHeightAtNewScale = contentSize.height * deltaScale;
2925     int viewWidth = m_size.width;
2926     int viewHeight = m_size.height;
2927
2928     // Enforce the maximum and minimum scroll positions at the new scale.
2929     IntPoint clampedOffset = offset;
2930     clampedOffset = clampedOffset.shrunkTo(IntPoint(docWidthAtNewScale - viewWidth, docHeightAtNewScale - viewHeight));
2931     clampedOffset.clampNegativeToZero();
2932     return clampedOffset;
2933 }
2934
2935 void WebViewImpl::setPageScaleFactorPreservingScrollOffset(float scaleFactor)
2936 {
2937     // Pick a scale factor that is within the expected limits
2938     scaleFactor = clampPageScaleFactorToLimits(scaleFactor);
2939
2940     IntPoint scrollOffsetAtNewScale(mainFrame()->scrollOffset().width, mainFrame()->scrollOffset().height);
2941     float deltaScale = scaleFactor / pageScaleFactor();
2942     scrollOffsetAtNewScale.scale(deltaScale, deltaScale);
2943
2944     WebPoint clampedOffsetAtNewScale = clampOffsetAtScale(scrollOffsetAtNewScale, scaleFactor);
2945     setPageScaleFactor(scaleFactor, clampedOffsetAtNewScale);
2946 }
2947
2948 void WebViewImpl::setPageScaleFactor(float scaleFactor, const WebPoint& origin)
2949 {
2950     if (!page())
2951         return;
2952
2953     if (!scaleFactor)
2954         scaleFactor = 1;
2955
2956     scaleFactor = clampPageScaleFactorToLimits(scaleFactor);
2957     WebPoint scrollOffset;
2958     if (!m_page->settings()->applyPageScaleFactorInCompositor()) {
2959         // If page scale is not applied in the compositor, then the scroll offsets should
2960         // be modified by the scale factor.
2961         scrollOffset = clampOffsetAtScale(origin, scaleFactor);
2962     } else {
2963         IntPoint offset = origin;
2964         WebSize contentSize = mainFrame()->contentsSize();
2965         offset.shrunkTo(IntPoint(contentSize.width - m_size.width, contentSize.height - m_size.height));
2966         offset.clampNegativeToZero();
2967         scrollOffset = offset;
2968     }
2969
2970     page()->setPageScaleFactor(scaleFactor, scrollOffset);
2971     m_pageScaleFactorIsSet = true;
2972 }
2973
2974 float WebViewImpl::deviceScaleFactor() const
2975 {
2976     if (!page())
2977         return 1;
2978
2979     return page()->deviceScaleFactor();
2980 }
2981
2982 void WebViewImpl::setDeviceScaleFactor(float scaleFactor)
2983 {
2984     if (!page())
2985         return;
2986
2987     page()->setDeviceScaleFactor(scaleFactor);
2988
2989     if (m_layerTreeView && m_webSettings->applyDeviceScaleFactorInCompositor())
2990         m_layerTreeView->setDeviceScaleFactor(scaleFactor);
2991 }
2992
2993 bool WebViewImpl::isFixedLayoutModeEnabled() const
2994 {
2995     if (!page())
2996         return false;
2997
2998     Frame* frame = page()->mainFrame();
2999     if (!frame || !frame->view())
3000         return false;
3001
3002     return frame->view()->useFixedLayout();
3003 }
3004
3005 void WebViewImpl::enableFixedLayoutMode(bool enable)
3006 {
3007     if (!page())
3008         return;
3009
3010     Frame* frame = page()->mainFrame();
3011     if (!frame || !frame->view())
3012         return;
3013
3014     frame->view()->setUseFixedLayout(enable);
3015
3016 #if USE(ACCELERATED_COMPOSITING)
3017     // Also notify the base layer, which RenderLayerCompositor does not see.
3018     if (m_nonCompositedContentHost)
3019         updateLayerTreeViewport();
3020 #endif
3021 }
3022
3023
3024 void WebViewImpl::enableAutoResizeMode(const WebSize& minSize, const WebSize& maxSize)
3025 {
3026     m_shouldAutoResize = true;
3027     m_minAutoSize = minSize;
3028     m_maxAutoSize = maxSize;
3029     configureAutoResizeMode();
3030 }
3031
3032 void WebViewImpl::disableAutoResizeMode()
3033 {
3034     m_shouldAutoResize = false;
3035     configureAutoResizeMode();
3036 }
3037
3038 void WebViewImpl::setPageScaleFactorLimits(float minPageScale, float maxPageScale)
3039 {
3040     m_pageDefinedMinimumPageScaleFactor = minPageScale;
3041     m_pageDefinedMaximumPageScaleFactor = maxPageScale;
3042     computePageScaleFactorLimits();
3043 }
3044
3045 void WebViewImpl::setIgnoreViewportTagMaximumScale(bool flag)
3046 {
3047     m_ignoreViewportTagMaximumScale = flag;
3048
3049     if (!page() || !page()->mainFrame())
3050         return;
3051
3052     m_page->chrome()->client()->dispatchViewportPropertiesDidChange(page()->mainFrame()->document()->viewportArguments());
3053 }
3054
3055 static IntSize unscaledContentsSize(Frame* frame)
3056 {
3057     RenderView* root = frame->contentRenderer();
3058     if (!root)
3059         return IntSize();
3060     return root->unscaledDocumentRect().size();
3061 }
3062
3063 IntSize WebViewImpl::layoutSize() const
3064 {
3065     if (!isFixedLayoutModeEnabled())
3066         return m_size;
3067
3068     IntSize contentSize = unscaledContentsSize(page()->mainFrame());
3069     if (fixedLayoutSize().width >= contentSize.width())
3070         return fixedLayoutSize();
3071
3072     float aspectRatio = static_cast<float>(m_size.height) / m_size.width;
3073     return IntSize(contentSize.width(), contentSize.width() * aspectRatio);
3074 }
3075
3076 bool WebViewImpl::computePageScaleFactorLimits()
3077 {
3078     if (m_pageDefinedMinimumPageScaleFactor == -1 || m_pageDefinedMaximumPageScaleFactor == -1)
3079         return false;
3080
3081     if (!mainFrame() || !page() || !page()->mainFrame() || !page()->mainFrame()->view())
3082         return false;
3083
3084     FrameView* view = page()->mainFrame()->view();
3085
3086     // Layout to refresh to the latest contents width.
3087     if (view->needsLayout())
3088         view->layout();
3089
3090     m_minimumPageScaleFactor = min(max(m_pageDefinedMinimumPageScaleFactor, minPageScaleFactor), maxPageScaleFactor);
3091     m_maximumPageScaleFactor = max(min(m_pageDefinedMaximumPageScaleFactor, maxPageScaleFactor), minPageScaleFactor);
3092     if (!m_webSettings->applyDeviceScaleFactorInCompositor()) {
3093         m_minimumPageScaleFactor *= deviceScaleFactor();
3094         m_maximumPageScaleFactor *= deviceScaleFactor();
3095     }
3096
3097     int viewWidthNotIncludingScrollbars = m_size.width;
3098     if (viewWidthNotIncludingScrollbars && view->verticalScrollbar() && !view->verticalScrollbar()->isOverlayScrollbar())
3099         viewWidthNotIncludingScrollbars -= view->verticalScrollbar()->width();
3100     int unscaledContentsWidth = unscaledContentsSize(page()->mainFrame()).width();
3101     if (viewWidthNotIncludingScrollbars && unscaledContentsWidth) {
3102         // Limit page scaling down to the document width.
3103         m_minimumPageScaleFactor = max(m_minimumPageScaleFactor, static_cast<float>(viewWidthNotIncludingScrollbars) / unscaledContentsWidth);
3104         m_maximumPageScaleFactor = max(m_minimumPageScaleFactor, m_maximumPageScaleFactor);
3105     }
3106     ASSERT(m_minimumPageScaleFactor <= m_maximumPageScaleFactor);
3107
3108     float clampedScale = clampPageScaleFactorToLimits(pageScaleFactor());
3109 #if USE(ACCELERATED_COMPOSITING)
3110     if (m_layerTreeView)
3111         m_layerTreeView->setPageScaleFactorAndLimits(clampedScale, m_minimumPageScaleFactor, m_maximumPageScaleFactor);
3112 #endif
3113     if (clampedScale != pageScaleFactor()) {
3114         setPageScaleFactorPreservingScrollOffset(clampedScale);
3115         return true;
3116     }
3117
3118     return false;
3119 }
3120
3121 float WebViewImpl::minimumPageScaleFactor() const
3122 {
3123     return m_minimumPageScaleFactor;
3124 }
3125
3126 float WebViewImpl::maximumPageScaleFactor() const
3127 {
3128     return m_maximumPageScaleFactor;
3129 }
3130
3131 void WebViewImpl::saveScrollAndScaleState()
3132 {
3133     m_savedPageScaleFactor = pageScaleFactor();
3134     m_savedScrollOffset = mainFrame()->scrollOffset();
3135 }
3136
3137 void WebViewImpl::restoreScrollAndScaleState()
3138 {
3139     if (!m_savedPageScaleFactor)
3140         return;
3141
3142 #if ENABLE(GESTURE_EVENTS)
3143     startPageScaleAnimation(IntPoint(m_savedScrollOffset), false, m_savedPageScaleFactor, scrollAndScaleAnimationDurationInSeconds);
3144 #else
3145     setPageScaleFactor(m_savedPageScaleFactor, WebPoint());
3146     mainFrame()->setScrollOffset(m_savedScrollOffset);
3147 #endif
3148
3149     resetSavedScrollAndScaleState();
3150 }
3151
3152 void WebViewImpl::resetSavedScrollAndScaleState()
3153 {
3154     m_savedPageScaleFactor = 0;
3155     m_savedScrollOffset = IntSize();
3156 }
3157
3158 void WebViewImpl::resetScrollAndScaleState()
3159 {
3160     page()->setPageScaleFactor(1, IntPoint());
3161
3162     // Clear out the values for the current history item. This will prevent the history item from clobbering the
3163     // value determined during page scale initialization, which may be less than 1.
3164     page()->mainFrame()->loader()->history()->saveDocumentAndScrollState();
3165     page()->mainFrame()->loader()->history()->clearScrollPositionAndViewState();
3166     m_pageScaleFactorIsSet = false;
3167
3168     // Clobber saved scales and scroll offsets.
3169     if (FrameView* view = page()->mainFrame()->document()->view())
3170         view->cacheCurrentScrollPosition();
3171     resetSavedScrollAndScaleState();
3172 }
3173
3174 WebSize WebViewImpl::fixedLayoutSize() const
3175 {
3176     if (!page())
3177         return WebSize();
3178
3179     Frame* frame = page()->mainFrame();
3180     if (!frame || !frame->view())
3181         return WebSize();
3182
3183     return frame->view()->fixedLayoutSize();
3184 }
3185
3186 void WebViewImpl::setFixedLayoutSize(const WebSize& layoutSize)
3187 {
3188     if (!page())
3189         return;
3190
3191     Frame* frame = page()->mainFrame();
3192     if (!frame || !frame->view())
3193         return;
3194
3195     frame->view()->setFixedLayoutSize(layoutSize);
3196 }
3197
3198 WebCore::IntSize WebViewImpl::dipSize() const
3199 {
3200     IntSize dipSize = m_size;
3201     if (!m_webSettings->applyDeviceScaleFactorInCompositor())
3202         dipSize.scale(1 / m_client->screenInfo().deviceScaleFactor);
3203     return dipSize;
3204 }
3205
3206 void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action,
3207                                            const WebPoint& location)
3208 {
3209     HitTestResult result = hitTestResultForWindowPos(location);
3210     RefPtr<Node> node = result.innerNonSharedNode();
3211     if (!node->hasTagName(HTMLNames::videoTag) && !node->hasTagName(HTMLNames::audioTag))
3212         return;
3213
3214     RefPtr<HTMLMediaElement> mediaElement =
3215         static_pointer_cast<HTMLMediaElement>(node);
3216     switch (action.type) {
3217     case WebMediaPlayerAction::Play:
3218         if (action.enable)
3219             mediaElement->play();
3220         else
3221             mediaElement->pause();
3222         break;
3223     case WebMediaPlayerAction::Mute:
3224         mediaElement->setMuted(action.enable);
3225         break;
3226     case WebMediaPlayerAction::Loop:
3227         mediaElement->setLoop(action.enable);
3228         break;
3229     case WebMediaPlayerAction::Controls:
3230         mediaElement->setControls(action.enable);
3231         break;
3232     default:
3233         ASSERT_NOT_REACHED();
3234     }
3235 }
3236
3237 void WebViewImpl::performPluginAction(const WebPluginAction& action,
3238                                       const WebPoint& location)
3239 {
3240     HitTestResult result = hitTestResultForWindowPos(location);
3241     RefPtr<Node> node = result.innerNonSharedNode();
3242     if (!node->hasTagName(HTMLNames::objectTag) && !node->hasTagName(HTMLNames::embedTag))
3243         return;
3244
3245     RenderObject* object = node->renderer();
3246     if (object && object->isWidget()) {
3247         Widget* widget = toRenderWidget(object)->widget();
3248         if (widget && widget->isPluginContainer()) {
3249             WebPluginContainerImpl* plugin = static_cast<WebPluginContainerImpl*>(widget);
3250             switch (action.type) {
3251             case WebPluginAction::Rotate90Clockwise:
3252                 plugin->plugin()->rotateView(WebPlugin::RotationType90Clockwise);
3253                 break;
3254             case WebPluginAction::Rotate90Counterclockwise:
3255                 plugin->plugin()->rotateView(WebPlugin::RotationType90Counterclockwise);
3256                 break;
3257             default:
3258                 ASSERT_NOT_REACHED();
3259             }
3260         }
3261     }
3262 }
3263
3264 WebHitTestResult WebViewImpl::hitTestResultAt(const WebPoint& point)
3265 {
3266     return hitTestResultForWindowPos(point);
3267 }
3268
3269 void WebViewImpl::copyImageAt(const WebPoint& point)
3270 {
3271     if (!m_page)
3272         return;
3273
3274     HitTestResult result = hitTestResultForWindowPos(point);
3275
3276     if (result.absoluteImageURL().isEmpty()) {
3277         // There isn't actually an image at these coordinates.  Might be because
3278         // the window scrolled while the context menu was open or because the page
3279         // changed itself between when we thought there was an image here and when
3280         // we actually tried to retreive the image.
3281         //
3282         // FIXME: implement a cache of the most recent HitTestResult to avoid having
3283         //        to do two hit tests.
3284         return;
3285     }
3286
3287     m_page->mainFrame()->editor()->copyImage(result);
3288 }
3289
3290 void WebViewImpl::dragSourceEndedAt(
3291     const WebPoint& clientPoint,
3292     const WebPoint& screenPoint,
3293     WebDragOperation operation)
3294 {
3295     PlatformMouseEvent pme(clientPoint,
3296                            screenPoint,
3297                            LeftButton, PlatformEvent::MouseMoved, 0, false, false, false,
3298                            false, 0);
3299     m_page->mainFrame()->eventHandler()->dragSourceEndedAt(pme,
3300         static_cast<DragOperation>(operation));
3301 }
3302
3303 void WebViewImpl::dragSourceMovedTo(
3304     const WebPoint& clientPoint,
3305     const WebPoint& screenPoint,
3306     WebDragOperation operation)
3307 {
3308 }
3309
3310 void WebViewImpl::dragSourceSystemDragEnded()
3311 {
3312     // It's possible for us to get this callback while not doing a drag if
3313     // it's from a previous page that got unloaded.
3314     if (m_doingDragAndDrop) {
3315         m_page->dragController()->dragEnded();
3316         m_doingDragAndDrop = false;
3317     }
3318 }
3319
3320 WebDragOperation WebViewImpl::dragTargetDragEnter(
3321     const WebDragData& webDragData,
3322     const WebPoint& clientPoint,
3323     const WebPoint& screenPoint,
3324     WebDragOperationsMask operationsAllowed,
3325     int keyModifiers)
3326 {
3327     ASSERT(!m_currentDragData);
3328
3329     m_currentDragData = webDragData;
3330     m_operationsAllowed = operationsAllowed;
3331
3332     return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragEnter, keyModifiers);
3333 }
3334
3335 WebDragOperation WebViewImpl::dragTargetDragOver(
3336     const WebPoint& clientPoint,
3337     const WebPoint& screenPoint,
3338     WebDragOperationsMask operationsAllowed,
3339     int keyModifiers)
3340 {
3341     m_operationsAllowed = operationsAllowed;
3342
3343     return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragOver, keyModifiers);
3344 }
3345
3346 void WebViewImpl::dragTargetDragLeave()
3347 {
3348     ASSERT(m_currentDragData);
3349
3350     DragData dragData(
3351         m_currentDragData.get(),
3352         IntPoint(),
3353         IntPoint(),
3354         static_cast<DragOperation>(m_operationsAllowed));
3355
3356     m_page->dragController()->dragExited(&dragData);
3357
3358     // FIXME: why is the drag scroll timer not stopped here?
3359
3360     m_dragOperation = WebDragOperationNone;
3361     m_currentDragData = 0;
3362 }
3363
3364 void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint,
3365                                  const WebPoint& screenPoint,
3366                                  int keyModifiers)
3367 {
3368     ASSERT(m_currentDragData);
3369
3370     // If this webview transitions from the "drop accepting" state to the "not
3371     // accepting" state, then our IPC message reply indicating that may be in-
3372     // flight, or else delayed by javascript processing in this webview.  If a
3373     // drop happens before our IPC reply has reached the browser process, then
3374     // the browser forwards the drop to this webview.  So only allow a drop to
3375     // proceed if our webview m_dragOperation state is not DragOperationNone.
3376
3377     if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop.
3378         dragTargetDragLeave();
3379         return;
3380     }
3381
3382     m_currentDragData->setModifierKeyState(webInputEventKeyStateToPlatformEventKeyState(keyModifiers));
3383     DragData dragData(
3384         m_currentDragData.get(),
3385         clientPoint,
3386         screenPoint,
3387         static_cast<DragOperation>(m_operationsAllowed));
3388
3389     m_page->dragController()->performDrag(&dragData);
3390
3391     m_dragOperation = WebDragOperationNone;
3392     m_currentDragData = 0;
3393 }
3394
3395 WebDragOperation WebViewImpl::dragTargetDragEnterOrOver(const WebPoint& clientPoint, const WebPoint& screenPoint, DragAction dragAction, int keyModifiers)
3396 {
3397     ASSERT(m_currentDragData);
3398
3399     m_currentDragData->setModifierKeyState(webInputEventKeyStateToPlatformEventKeyState(keyModifiers));
3400     DragData dragData(
3401         m_currentDragData.get(),
3402         clientPoint,
3403         screenPoint,
3404         static_cast<DragOperation>(m_operationsAllowed));
3405
3406     DragSession dragSession;
3407     if (dragAction == DragEnter)
3408         dragSession = m_page->dragController()->dragEntered(&dragData);
3409     else
3410         dragSession = m_page->dragController()->dragUpdated(&dragData);
3411
3412     DragOperation dropEffect = dragSession.operation;
3413
3414     // Mask the drop effect operation against the drag source's allowed operations.
3415     if (!(dropEffect & dragData.draggingSourceOperationMask()))
3416         dropEffect = DragOperationNone;
3417
3418      m_dragOperation = static_cast<WebDragOperation>(dropEffect);
3419
3420     return m_dragOperation;
3421 }
3422
3423 void WebViewImpl::sendResizeEventAndRepaint()
3424 {
3425     if (mainFrameImpl()->frameView()) {
3426         // Enqueues the resize event.
3427         mainFrameImpl()->frame()->eventHandler()->sendResizeEvent();
3428     }
3429
3430     if (m_client) {
3431         if (isAcceleratedCompositingActive()) {
3432 #if USE(ACCELERATED_COMPOSITING)
3433             updateLayerTreeViewport();
3434 #endif
3435         } else {
3436             WebRect damagedRect(0, 0, m_size.width, m_size.height);
3437             m_client->didInvalidateRect(damagedRect);
3438         }
3439     }
3440     if (m_pageOverlays)
3441         m_pageOverlays->update();
3442 }
3443
3444 void WebViewImpl::configureAutoResizeMode()
3445 {
3446     if (!mainFrameImpl() || !mainFrameImpl()->frame() || !mainFrameImpl()->frame()->view())
3447         return;
3448
3449     mainFrameImpl()->frame()->view()->enableAutoSizeMode(m_shouldAutoResize, m_minAutoSize, m_maxAutoSize);
3450 }
3451
3452 unsigned long WebViewImpl::createUniqueIdentifierForRequest()
3453 {
3454     if (m_page)
3455         return m_page->progress()->createUniqueIdentifier();
3456     return 0;
3457 }
3458
3459 void WebViewImpl::inspectElementAt(const WebPoint& point)
3460 {
3461     if (!m_page)
3462         return;
3463
3464     if (point.x == -1 || point.y == -1)
3465         m_page->inspectorController()->inspect(0);
3466     else {
3467         HitTestResult result = hitTestResultForWindowPos(point);
3468
3469         if (!result.innerNonSharedNode())
3470             return;
3471
3472         m_page->inspectorController()->inspect(result.innerNonSharedNode());
3473     }
3474 }
3475
3476 WebString WebViewImpl::inspectorSettings() const
3477 {
3478     return m_inspectorSettings;
3479 }
3480
3481 void WebViewImpl::setInspectorSettings(const WebString& settings)
3482 {
3483     m_inspectorSettings = settings;
3484 }
3485
3486 bool WebViewImpl::inspectorSetting(const WebString& key, WebString* value) const
3487 {
3488     if (!m_inspectorSettingsMap->contains(key))
3489         return false;
3490     *value = m_inspectorSettingsMap->get(key);
3491     return true;
3492 }
3493
3494 void WebViewImpl::setInspectorSetting(const WebString& key,
3495                                       const WebString& value)
3496 {
3497     m_inspectorSettingsMap->set(key, value);
3498     client()->didUpdateInspectorSetting(key, value);