WebViewImpl.cpp 137 KB
Newer Older
1
/*
2
 * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "WebViewImpl.h"

34
#include "AXObjectCache.h"
35
#include "ActivePlatformGestureAnimation.h"
36
#include "AutofillPopupMenuClient.h"
37
#include "BackForwardListChromium.h"
38
#include "BatteryClientImpl.h"
39
#include "BatteryController.h"
40
#include "CSSValueKeywords.h"
aroben@apple.com's avatar
aroben@apple.com committed
41
#include "Chrome.h"
42
#include "Color.h"
43
#include "ColorSpace.h"
44
#include "CompositionUnderlineVectorBuilder.h"
45
#include "CompositorHUDFontAtlas.h"
46
#include "ContextFeaturesClientImpl.h"
47 48 49
#include "ContextMenu.h"
#include "ContextMenuController.h"
#include "ContextMenuItem.h"
50
#include "Cursor.h"
51
#include "DOMUtilitiesPrivate.h"
52
#include "DeviceOrientationClientProxy.h"
53 54 55
#include "Document.h"
#include "DocumentLoader.h"
#include "DragController.h"
56
#include "DragData.h"
57
#include "DragScrollTimer.h"
58
#include "DragSession.h"
59 60
#include "Editor.h"
#include "EventHandler.h"
61
#include "Extensions3D.h"
62 63
#include "FocusController.h"
#include "FontDescription.h"
64
#include "Frame.h"
65
#include "FrameLoader.h"
66
#include "FrameSelection.h"
67 68
#include "FrameTree.h"
#include "FrameView.h"
69
#include "GeolocationClientProxy.h"
70
#include "GeolocationController.h"
71
#include "GraphicsContext.h"
72
#include "GraphicsContext3D.h"
73
#include "GraphicsContext3DPrivate.h"
74 75
#include "HTMLInputElement.h"
#include "HTMLMediaElement.h"
76
#include "HTMLNames.h"
77
#include "HTMLTextAreaElement.h"
78
#include "HitTestResult.h"
79
#include "Image.h"
80
#include "ImageBuffer.h"
81
#include "InspectorController.h"
82
#include "InspectorInstrumentation.h"
83 84
#include "KeyboardCodes.h"
#include "KeyboardEvent.h"
85
#include "LayerPainterChromium.h"
86
#include "LinkHighlight.h"
87 88
#include "MIMETypeRegistry.h"
#include "NodeRenderStyle.h"
89
#include "NonCompositedContentHost.h"
90 91
#include "Page.h"
#include "PageGroup.h"
92
#include "PageGroupLoadDeferrer.h"
93
#include "PagePopupClient.h"
94
#include "PageWidgetDelegate.h"
95 96 97 98
#include "Pasteboard.h"
#include "PlatformContextSkia.h"
#include "PlatformKeyboardEvent.h"
#include "PlatformMouseEvent.h"
99
#include "PlatformThemeChromiumLinux.h"
100
#include "PlatformWheelEvent.h"
101
#include "PointerLockController.h"
102
#include "PopupContainer.h"
103
#include "PopupMenuClient.h"
104
#include "PrerendererClientImpl.h"
105
#include "ProgressTracker.h"
106
#include "RenderLayerCompositor.h"
107
#include "RenderView.h"
108
#include "RenderWidget.h"
109
#include "ResourceHandle.h"
110
#include "SchemeRegistry.h"
111
#include "SecurityOrigin.h"
112
#include "SecurityPolicy.h"
113
#include "Settings.h"
114
#include "SharedGraphicsContext3D.h"
115
#include "SpeechInputClientImpl.h"
116
#include "SpeechRecognitionClientProxy.h"
117
#include "StyleResolver.h"
118
#include "Text.h"
119
#include "TextFieldDecoratorImpl.h"
120
#include "TextIterator.h"
121
#include "Timer.h"
122
#include "TouchpadFlingPlatformGestureCurve.h"
123
#include "TraceEvent.h"
124
#include "UserGestureIndicator.h"
125
#include "WebAccessibilityObject.h"
126
#include "WebActiveWheelFlingParameters.h"
127
#include "WebAutofillClient.h"
128
#include "WebCompositorImpl.h"
129
#include "WebDevToolsAgentImpl.h"
130
#include "WebDevToolsAgentPrivate.h"
131
#include "WebFrameImpl.h"
132
#include "WebHelperPluginImpl.h"
133
#include "WebHitTestResult.h"
134
#include "WebInputElement.h"
135 136 137 138
#include "WebInputEvent.h"
#include "WebInputEventConversion.h"
#include "WebMediaPlayerAction.h"
#include "WebNode.h"
139
#include "WebPagePopupImpl.h"
140
#include "WebPlugin.h"
141
#include "WebPluginAction.h"
142
#include "WebPluginContainerImpl.h"
143
#include "WebPopupMenuImpl.h"
144
#include "WebRange.h"
145
#include "WebRuntimeFeatures.h"
146
#include "WebSettingsImpl.h"
147
#include "WebTextInputInfo.h"
148
#include "WebViewClient.h"
149
#include "WheelEvent.h"
150
#include "painting/GraphicsContextBuilder.h"
151
#include <public/Platform.h>
152
#include <public/WebCompositor.h>
153
#include <public/WebCompositorOutputSurface.h>
154
#include <public/WebDragData.h>
155 156
#include <public/WebFloatPoint.h>
#include <public/WebGraphicsContext3D.h>
157
#include <public/WebImage.h>
158 159 160 161
#include <public/WebLayer.h>
#include <public/WebLayerTreeView.h>
#include <public/WebPoint.h>
#include <public/WebRect.h>
162 163
#include <public/WebString.h>
#include <public/WebVector.h>
164
#include <wtf/CurrentTime.h>
165
#include <wtf/MainThread.h>
166
#include <wtf/RefPtr.h>
167
#include <wtf/TemporaryChange.h>
168
#include <wtf/Uint8ClampedArray.h>
169

170 171
#if ENABLE(GESTURE_EVENTS)
#include "PlatformGestureEvent.h"
172
#include "TouchDisambiguation.h"
173 174
#endif

175
#if OS(WINDOWS)
176 177
#include "RenderThemeChromiumWin.h"
#else
178
#if OS(UNIX) && !OS(DARWIN)
179 180
#include "RenderThemeChromiumLinux.h"
#endif
181 182 183 184 185 186 187 188
#include "RenderTheme.h"
#endif

// Get rid of WTF's pow define so we can use std::pow.
#undef pow
#include <cmath> // for std::pow

using namespace WebCore;
189
using namespace std;
190

191 192 193 194
// The following constants control parameters for automated scaling of webpages
// (such as due to a double tap gesture or find in page etc.). These are
// experimentally determined.
static const int touchPointPadding = 32;
195
static const float minScaleDifference = 0.01f;
196 197
static const float doubleTapZoomContentDefaultMargin = 5;
static const float doubleTapZoomContentMinimumMargin = 2;
198
static const double doubleTapZoomAnimationDurationInSeconds = 0.25;
199

200 201
// Constants for zooming in on a focused text field.
static const double scrollAndScaleAnimationDurationInSeconds = 0.2;
202

203 204 205 206 207 208
namespace WebKit {

// Change the text zoom level by kTextSizeMultiplierRatio each time the user
// zooms text in or out (ie., change by 20%).  The min and max values limit
// text zoom to half and 3x the original text size.  These three values match
// those in Apple's port in WebKit/WebKit/WebView/WebView.mm
209 210 211
const double WebView::textSizeMultiplierRatio = 1.2;
const double WebView::minTextSizeMultiplier = 0.5;
const double WebView::maxTextSizeMultiplier = 3.0;
212 213
const float WebView::minPageScaleFactor = 0.25;
const float WebView::maxPageScaleFactor = 4.0;
214

215

216
// The group name identifies a namespace of pages. Page group is used on PLATFORM(MAC)
217 218 219 220 221
// for some programs that use HTML views to display things that don't seem like
// web pages to the user (so shouldn't have visited link coloring).  We only use
// one page group.
const char* pageGroupName = "default";

222
// Used to defer all page activity in cases where the embedder wishes to run
223
// a nested event loop. Using a stack enables nesting of message loop invocations.
224 225 226 227 228
static Vector<PageGroupLoadDeferrer*>& pageGroupLoadDeferrerStack()
{
    DEFINE_STATIC_LOCAL(Vector<PageGroupLoadDeferrer*>, deferrerStack, ());
    return deferrerStack;
}
229

230 231 232 233 234 235 236 237 238 239 240 241 242
// Ensure that the WebDragOperation enum values stay in sync with the original
// DragOperation constants.
#define COMPILE_ASSERT_MATCHING_ENUM(coreName) \
    COMPILE_ASSERT(int(coreName) == int(Web##coreName), dummy##coreName)
COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone);
COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy);
COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink);
COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric);
COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate);
COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove);
COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete);
COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery);

243
static const PopupContainerSettings autofillPopupSettings = {
244 245
    false, // setTextOnIndexChange
    false, // acceptOnAbandon
246 247 248
    true, // loopSelectionNavigation
    false // restrictWidthOfListBox (For security reasons show the entire entry
          // so the user doesn't enter information he did not intend to.)
249 250
};

251 252
static bool shouldUseExternalPopupMenus = false;

253 254 255 256 257 258 259 260 261 262 263 264 265 266
static int webInputEventKeyStateToPlatformEventKeyState(int webInputEventKeyState)
{
    int platformEventKeyState = 0;
    if (webInputEventKeyState & WebInputEvent::ShiftKey)
        platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::ShiftKey;
    if (webInputEventKeyState & WebInputEvent::ControlKey)
        platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::CtrlKey;
    if (webInputEventKeyState & WebInputEvent::AltKey)
        platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::AltKey;
    if (webInputEventKeyState & WebInputEvent::MetaKey)
        platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::MetaKey;
    return platformEventKeyState;
}

267 268
// WebView ----------------------------------------------------------------

269
WebView* WebView::create(WebViewClient* client)
270
{
271
    // Pass the WebViewImpl's self-reference to the caller.
272
    return adoptRef(new WebViewImpl(client)).leakRef();
273 274
}

275 276 277 278 279
void WebView::setUseExternalPopupMenus(bool useExternalPopupMenus)
{
    shouldUseExternalPopupMenus = useExternalPopupMenus;
}

280 281 282 283 284 285 286 287 288 289
void WebView::updateVisitedLinkState(unsigned long long linkHash)
{
    Page::visitedStateChanged(PageGroup::pageGroup(pageGroupName), linkHash);
}

void WebView::resetVisitedLinkState()
{
    Page::allVisitedStateChanged(PageGroup::pageGroup(pageGroupName));
}

290 291 292 293
void WebView::willEnterModalLoop()
{
    PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
    ASSERT(pageGroup);
294 295

    if (pageGroup->pages().isEmpty())
296
        pageGroupLoadDeferrerStack().append(static_cast<PageGroupLoadDeferrer*>(0));
297 298
    else {
        // Pick any page in the page group since we are deferring all pages.
299
        pageGroupLoadDeferrerStack().append(new PageGroupLoadDeferrer(*pageGroup->pages().begin(), true));
300
    }
301 302 303 304
}

void WebView::didExitModalLoop()
{
305
    ASSERT(pageGroupLoadDeferrerStack().size());
306

307 308
    delete pageGroupLoadDeferrerStack().last();
    pageGroupLoadDeferrerStack().removeLast();
309 310
}

311 312 313 314 315 316
void WebViewImpl::initializeMainFrame(WebFrameClient* frameClient)
{
    // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame
    // and releases that reference once the corresponding Frame is destroyed.
    RefPtr<WebFrameImpl> frame = WebFrameImpl::create(frameClient);

317
    frame->initializeAsMainFrame(page());
318 319 320

    // Restrict the access to the local file system
    // (see WebView.mm WebView::_commonInitializationWithFrameName).
321
    SecurityPolicy::setLocalLoadPolicy(SecurityPolicy::AllowLocalLoadsForLocalOnly);
322 323
}

324 325 326 327 328
void WebViewImpl::initializeHelperPluginFrame(WebFrameClient* client)
{
    RefPtr<WebFrameImpl> frame = WebFrameImpl::create(client);
}

329
void WebViewImpl::setAutofillClient(WebAutofillClient* autofillClient)
330
{
331
    m_autofillClient = autofillClient;
332 333
}

334
void WebViewImpl::setDevToolsAgentClient(WebDevToolsAgentClient* devToolsClient)
335 336
{
    if (devToolsClient)
337
        m_devToolsAgent = adoptPtr(new WebDevToolsAgentImpl(this, devToolsClient));
338 339 340 341
    else
        m_devToolsAgent.clear();
}

342
void WebViewImpl::setPermissionClient(WebPermissionClient* permissionClient)
343
{
344
    m_permissionClient = permissionClient;
345
    m_featureSwitchClient->setPermissionClient(permissionClient);
346 347
}

348 349 350 351 352
void WebViewImpl::setPrerendererClient(WebPrerendererClient* prerendererClient)
{
    providePrerendererClientTo(m_page.get(), new PrerendererClientImpl(prerendererClient));
}

353 354 355 356 357
void WebViewImpl::setSpellCheckClient(WebSpellCheckClient* spellCheckClient)
{
    m_spellCheckClient = spellCheckClient;
}

358 359 360 361 362 363 364 365 366 367 368 369
void WebViewImpl::addTextFieldDecoratorClient(WebTextFieldDecoratorClient* client)
{
    ASSERT(client);
    // We limit the number of decorators because it affects performance of text
    // field creation. If you'd like to add more decorators, consider moving
    // your decorator or existing decorators to WebCore.
    const unsigned maximumNumberOfDecorators = 8;
    if (m_textFieldDecorators.size() >= maximumNumberOfDecorators)
        CRASH();
    m_textFieldDecorators.append(TextFieldDecoratorImpl::create(client));
}

370
WebViewImpl::WebViewImpl(WebViewClient* client)
371
    : m_client(client)
372
    , m_autofillClient(0)
373
    , m_permissionClient(0)
374
    , m_spellCheckClient(0)
375 376 377 378
    , m_chromeClientImpl(this)
    , m_contextMenuClientImpl(this)
    , m_dragClientImpl(this)
    , m_editorClientImpl(this)
379
    , m_inspectorClientImpl(this)
380
    , m_shouldAutoResize(false)
381 382 383 384 385
    , m_observedNewNavigation(false)
#ifndef NDEBUG
    , m_newNavigationLoader(0)
#endif
    , m_zoomLevel(0)
386 387
    , m_minimumZoomLevel(zoomFactorToZoomLevel(minTextSizeMultiplier))
    , m_maximumZoomLevel(zoomFactorToZoomLevel(maxTextSizeMultiplier))
388 389
    , m_pageDefinedMinimumPageScaleFactor(-1)
    , m_pageDefinedMaximumPageScaleFactor(-1)
390 391
    , m_minimumPageScaleFactor(minPageScaleFactor)
    , m_maximumPageScaleFactor(maxPageScaleFactor)
392
    , m_ignoreViewportTagMaximumScale(false)
393
    , m_pageScaleFactorIsSet(false)
394
    , m_savedPageScaleFactor(0)
395 396 397 398 399 400 401 402
    , m_contextMenuAllowed(false)
    , m_doingDragAndDrop(false)
    , m_ignoreInputEvents(false)
    , m_suppressNextKeypressEvent(false)
    , m_initialNavigationPolicy(WebNavigationPolicyIgnore)
    , m_imeAcceptEvents(true)
    , m_operationsAllowed(WebDragOperationNone)
    , m_dragOperation(WebDragOperationNone)
403
    , m_featureSwitchClient(adoptPtr(new ContextFeaturesClientImpl()))
404 405
    , m_autofillPopupShowing(false)
    , m_autofillPopup(0)
406 407
    , m_isTransparent(false)
    , m_tabsToLinks(false)
408
    , m_dragScrollTimer(adoptPtr(new DragScrollTimer))
409
    , m_isCancelingFullScreen(false)
410
    , m_benchmarkSupport(this)
411
#if USE(ACCELERATED_COMPOSITING)
412
    , m_rootLayer(0)
413
    , m_rootGraphicsLayer(0)
414
    , m_isAcceleratedCompositingActive(false)
415
    , m_compositorCreationFailed(false)
416
    , m_recreatingGraphicsContext(false)
417
    , m_compositorSurfaceReady(false)
418
    , m_deviceScaleInCompositor(1)
419 420
#endif
#if ENABLE(INPUT_SPEECH)
421
    , m_speechInputClient(SpeechInputClientImpl::create(client))
422 423 424
#endif
#if ENABLE(SCRIPTED_SPEECH)
    , m_speechRecognitionClient(SpeechRecognitionClientProxy::create(client ? client->speechRecognizer() : 0))
425
#endif
426 427
    , m_deviceOrientationClientProxy(adoptPtr(new DeviceOrientationClientProxy(client ? client->deviceOrientationClient() : 0)))
    , m_geolocationClientProxy(adoptPtr(new GeolocationClientProxy(client ? client->geolocationClient() : 0)))
428 429 430
#if ENABLE(BATTERY_STATUS)
    , m_batteryClient(adoptPtr(new BatteryClientImpl(client ? client->batteryStatusClient() : 0)))
#endif
431
    , m_emulatedTextZoomFactor(1)
432 433
#if ENABLE(MEDIA_STREAM)
    , m_userMediaClientImpl(this)
434
#endif
435 436
#if ENABLE(NAVIGATOR_CONTENT_UTILS)
    , m_navigatorContentUtilsClient(NavigatorContentUtilsClientImpl::create(this))
437
#endif
438
    , m_flingModifier(0)
439 440 441 442 443
{
    // WebKit/win/WebView.cpp does the same thing, except they call the
    // KJS specific wrapper around this method. We need to have threading
    // initialized because CollatorICU requires it.
    WTF::initializeThreading();
444
    WTF::initializeMainThread();
445

446 447 448 449 450 451
    Page::PageClients pageClients;
    pageClients.chromeClient = &m_chromeClientImpl;
    pageClients.contextMenuClient = &m_contextMenuClientImpl;
    pageClients.editorClient = &m_editorClientImpl;
    pageClients.dragClient = &m_dragClientImpl;
    pageClients.inspectorClient = &m_inspectorClientImpl;
452
    pageClients.backForwardClient = BackForwardListChromium::create(this);
453

454
    m_page = adoptPtr(new Page(pageClients));
455 456 457
#if ENABLE(MEDIA_STREAM)
    provideUserMediaTo(m_page.get(), &m_userMediaClientImpl);
#endif
458 459 460
#if ENABLE(INPUT_SPEECH)
    provideSpeechInputTo(m_page.get(), m_speechInputClient.get());
#endif
461
#if ENABLE(SCRIPTED_SPEECH)
462
    provideSpeechRecognitionTo(m_page.get(), m_speechRecognitionClient.get());
463
#endif
464
#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
465 466
    provideNotification(m_page.get(), notificationPresenterImpl());
#endif
467 468
#if ENABLE(NAVIGATOR_CONTENT_UTILS)
    provideNavigatorContentUtilsTo(m_page.get(), m_navigatorContentUtilsClient.get());
469
#endif
470

471
    provideContextFeaturesTo(m_page.get(), m_featureSwitchClient.get());
472
    provideDeviceOrientationTo(m_page.get(), m_deviceOrientationClientProxy.get());
473 474
    provideGeolocationTo(m_page.get(), m_geolocationClientProxy.get());
    m_geolocationClientProxy->setController(GeolocationController::from(m_page.get()));
475 476 477

#if ENABLE(BATTERY_STATUS)
    provideBatteryTo(m_page.get(), m_batteryClient.get());
478
    m_batteryClient->setController(BatteryController::from(m_page.get()));
479
#endif
480

481
    m_page->setGroupName(pageGroupName);
482

483
#if ENABLE(PAGE_VISIBILITY_API)
484 485
    if (m_client)
        setVisibilityState(m_client->visibilityState(), true);
486 487
#endif

488
    m_inspectorSettingsMap = adoptPtr(new SettingsMap);
489 490 491 492 493 494 495 496 497
}

WebViewImpl::~WebViewImpl()
{
    ASSERT(!m_page);
}

RenderTheme* WebViewImpl::theme() const
{
498
    return m_page ? m_page->theme() : RenderTheme::defaultTheme().get();
499 500 501 502
}

WebFrameImpl* WebViewImpl::mainFrameImpl()
{
503
    return m_page ? WebFrameImpl::fromFrame(m_page->mainFrame()) : 0;
504 505 506 507
}

bool WebViewImpl::tabKeyCyclesThroughElements() const
{
508
    ASSERT(m_page);
509 510 511 512 513 514 515 516 517
    return m_page->tabKeyCyclesThroughElements();
}

void WebViewImpl::setTabKeyCyclesThroughElements(bool value)
{
    if (m_page)
        m_page->setTabKeyCyclesThroughElements(value);
}

518
void WebViewImpl::handleMouseLeave(Frame& mainFrame, const WebMouseEvent& event)
519 520
{
    m_client->setMouseOverURL(WebURL());
521
    PageWidgetEventHandler::handleMouseLeave(mainFrame, event);
522 523
}

524
void WebViewImpl::handleMouseDown(Frame& mainFrame, const WebMouseEvent& event)
525
{
526 527 528
    // If there is a popup open, close it as the user is clicking on the page (outside of the
    // popup). We also save it so we can prevent a click on an element from immediately
    // reopening the same popup.
529
    RefPtr<WebCore::PopupContainer> selectPopup;
530 531 532
#if ENABLE(PAGE_POPUP)
    RefPtr<WebPagePopupImpl> pagePopup;
#endif
533 534
    if (event.button == WebMouseEvent::ButtonLeft) {
        selectPopup = m_selectPopup;
535 536 537 538
#if ENABLE(PAGE_POPUP)
        pagePopup = m_pagePopup;
#endif
        hidePopups();
539
        ASSERT(!m_selectPopup);
540 541 542
#if ENABLE(PAGE_POPUP)
        ASSERT(!m_pagePopup);
#endif
543
    }
544

545 546 547
    m_lastMouseDownPoint = WebPoint(event.x, event.y);

    if (event.button == WebMouseEvent::ButtonLeft) {
548 549 550 551 552 553 554 555
        IntPoint point(event.x, event.y);
        point = m_page->mainFrame()->view()->windowToContents(point);
        HitTestResult result(m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, false));
        Node* hitNode = result.innerNonSharedNode();

        // Take capture on a mouse down on a plugin so we can send it mouse events.
        if (hitNode && hitNode->renderer() && hitNode->renderer()->isEmbeddedObject())
            m_mouseCaptureNode = hitNode;
556 557
    }

558
    PageWidgetEventHandler::handleMouseDown(mainFrame, event);
559

560 561 562 563 564 565 566
    if (m_selectPopup && m_selectPopup == selectPopup) {
        // That click triggered a select popup which is the same as the one that
        // was showing before the click.  It means the user clicked the select
        // while the popup was showing, and as a result we first closed then
        // immediately reopened the select popup.  It needs to be closed.
        hideSelectPopup();
    }
567

568 569 570 571 572 573 574 575
#if ENABLE(PAGE_POPUP)
    if (m_pagePopup && pagePopup && m_pagePopup->hasSamePopupClient(pagePopup.get())) {
        // That click triggered a page popup that is the same as the one we just closed.
        // It needs to be closed.
        closePagePopup(m_pagePopup.get());
    }
#endif

576 577
    // Dispatch the contextmenu event regardless of if the click was swallowed.
    // On Windows, we handle it on mouse up, not down.
578
#if OS(DARWIN)
579 580 581 582
    if (event.button == WebMouseEvent::ButtonRight
        || (event.button == WebMouseEvent::ButtonLeft
            && event.modifiers & WebMouseEvent::ControlKey))
        mouseContextMenu(event);
583
#elif OS(UNIX) || OS(ANDROID)
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
    if (event.button == WebMouseEvent::ButtonRight)
        mouseContextMenu(event);
#endif
}

void WebViewImpl::mouseContextMenu(const WebMouseEvent& event)
{
    if (!mainFrameImpl() || !mainFrameImpl()->frameView())
        return;

    m_page->contextMenuController()->clearContextMenu();

    PlatformMouseEventBuilder pme(mainFrameImpl()->frameView(), event);

    // Find the right target frame. See issue 1186900.
weinig@apple.com's avatar
weinig@apple.com committed
599
    HitTestResult result = hitTestResultForWindowPos(pme.position());
600 601 602 603 604 605
    Frame* targetFrame;
    if (result.innerNonSharedNode())
        targetFrame = result.innerNonSharedNode()->document()->frame();
    else
        targetFrame = m_page->focusController()->focusedOrMainFrame();

606
#if OS(WINDOWS)
607 608 609 610 611 612 613 614 615 616
    targetFrame->view()->setCursor(pointerCursor());
#endif

    m_contextMenuAllowed = true;
    targetFrame->eventHandler()->sendContextMenuEvent(pme);
    m_contextMenuAllowed = false;
    // Actually showing the context menu is handled by the ContextMenuClient
    // implementation...
}

617
void WebViewImpl::handleMouseUp(Frame& mainFrame, const WebMouseEvent& event)
618
{
619
#if OS(UNIX) && !OS(DARWIN)
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
    // If the event was a middle click, attempt to copy text into the focused
    // frame. We execute this before we let the page have a go at the event
    // because the page may change what is focused during in its event handler.
    //
    // This code is in the mouse up handler. There is some debate about putting
    // this here, as opposed to the mouse down handler.
    //   xterm: pastes on up.
    //   GTK: pastes on down.
    //   Firefox: pastes on up.
    //   Midori: couldn't paste at all with 0.1.2
    //
    // There is something of a webcompat angle to this well, as highlighted by
    // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
    // down then the text is pasted just before the onclick handler runs and
    // clears the text box. So it's important this happens after the
    // handleMouseReleaseEvent() earlier in this function
    if (event.button == WebMouseEvent::ButtonMiddle) {
        Frame* focused = focusedWebCoreFrame();
638
        FrameView* view = m_page->mainFrame()->view();
639
        IntPoint clickPoint(m_lastMouseDownPoint.x, m_lastMouseDownPoint.y);
640 641
        IntPoint contentPoint = view->windowToContents(clickPoint);
        HitTestResult hitTestResult = focused->eventHandler()->hitTestResultAtPoint(contentPoint, false, false, ShouldHitTestScrollbars);
642
        // We don't want to send a paste when middle clicking a scroll bar or a
643
        // link (which will navigate later in the code).  The main scrollbars
644 645
        // have to be handled separately.
        if (!hitTestResult.scrollbar() && !hitTestResult.isLiveLink() && focused && !view->scrollbarAtPoint(clickPoint)) {
646 647 648 649 650 651 652 653 654 655
            Editor* editor = focused->editor();
            Pasteboard* pasteboard = Pasteboard::generalPasteboard();
            bool oldSelectionMode = pasteboard->isSelectionMode();
            pasteboard->setSelectionMode(true);
            editor->command(AtomicString("Paste")).execute();
            pasteboard->setSelectionMode(oldSelectionMode);
        }
    }
#endif

656
    PageWidgetEventHandler::handleMouseUp(mainFrame, event);
657

658
#if OS(WINDOWS)
659 660 661 662 663 664 665
    // Dispatch the contextmenu event regardless of if the click was swallowed.
    // On Mac/Linux, we handle it on mouse down, not up.
    if (event.button == WebMouseEvent::ButtonRight)
        mouseContextMenu(event);
#endif
}

666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
void WebViewImpl::scrollBy(const WebCore::IntPoint& delta)
{
    WebMouseWheelEvent syntheticWheel;
    const float tickDivisor = WebCore::WheelEvent::tickMultiplier;

    syntheticWheel.deltaX = delta.x();
    syntheticWheel.deltaY = delta.y();
    syntheticWheel.wheelTicksX = delta.x() / tickDivisor;
    syntheticWheel.wheelTicksY = delta.y() / tickDivisor;
    syntheticWheel.hasPreciseScrollingDeltas = true;
    syntheticWheel.x = m_lastWheelPosition.x;
    syntheticWheel.y = m_lastWheelPosition.y;
    syntheticWheel.globalX = m_lastWheelGlobalPosition.x;
    syntheticWheel.globalY = m_lastWheelGlobalPosition.y;
    syntheticWheel.modifiers = m_flingModifier;

682 683
    if (m_page && m_page->mainFrame() && m_page->mainFrame()->view())
        handleMouseWheel(*m_page->mainFrame(), syntheticWheel);
684 685
}

686
#if ENABLE(GESTURE_EVENTS)
687
bool WebViewImpl::handleGestureEvent(const WebGestureEvent& event)
688
{
689 690
    switch (event.type) {
    case WebInputEvent::GestureFlingStart: {
691
        m_client->cancelScheduledContentIntents();
692 693 694 695
        m_lastWheelPosition = WebPoint(event.x, event.y);
        m_lastWheelGlobalPosition = WebPoint(event.globalX, event.globalY);
        m_flingModifier = event.modifiers;
        // FIXME: Make the curve parametrizable from the browser.
696
        m_gestureAnimation = ActivePlatformGestureAnimation::create(TouchpadFlingPlatformGestureCurve::create(FloatPoint(event.deltaX, event.deltaY)), this);
697 698 699 700
        scheduleAnimation();
        return true;
    }
    case WebInputEvent::GestureFlingCancel:
701 702 703 704 705
        if (m_gestureAnimation) {
            m_gestureAnimation.clear();
            return true;
        }
        return false;
706
    case WebInputEvent::GestureTap: {
707 708 709 710
        m_client->cancelScheduledContentIntents();
        if (detectContentOnTouch(WebPoint(event.x, event.y), event.type))
            return true;

711 712 713 714
        RefPtr<WebCore::PopupContainer> selectPopup;
        selectPopup = m_selectPopup;
        hideSelectPopup();
        ASSERT(!m_selectPopup);
715 716 717 718 719 720

        if (!event.boundingBox.isEmpty()) {
            Vector<IntRect> goodTargets;
            findGoodTouchTargets(event.boundingBox, mainFrameImpl()->frame(), pageScaleFactor(), goodTargets);
            // FIXME: replace touch adjustment code when numberOfGoodTargets == 1?
            // Single candidate case is currently handled by: https://bugs.webkit.org/show_bug.cgi?id=85101
721
            if (goodTargets.size() >= 2 && m_client && m_client->didTapMultipleTargets(event, goodTargets))
722 723 724 725
                return true;
        }

        PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
726
        bool gestureHandled = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
727

728 729 730 731 732 733 734
        if (m_selectPopup && m_selectPopup == selectPopup) {
            // That tap triggered a select popup which is the same as the one that
            // was showing before the tap. It means the user tapped the select
            // while the popup was showing, and as a result we first closed then
            // immediately reopened the select popup. It needs to be closed.
            hideSelectPopup();
        }
735

736 737
        return gestureHandled;
    }
738
    case WebInputEvent::GestureTwoFingerTap:
739 740 741 742
    case WebInputEvent::GestureLongPress: {
        if (!mainFrameImpl() || !mainFrameImpl()->frameView())
            return false;

743 744 745 746
        m_client->cancelScheduledContentIntents();
        if (detectContentOnTouch(WebPoint(event.x, event.y), event.type))
            return true;

747 748 749 750 751 752 753
        m_page->contextMenuController()->clearContextMenu();
        m_contextMenuAllowed = true;
        PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
        bool handled = mainFrameImpl()->frame()->eventHandler()->sendContextMenuEventForGesture(platformEvent);
        m_contextMenuAllowed = false;
        return handled;
    }
754
    case WebInputEvent::GestureTapDown: {
755
        m_client->cancelScheduledContentIntents();
756 757
        // Queue a highlight animation, then hand off to regular handler.
#if OS(LINUX)
758 759
        if (settingsImpl()->gestureTapHighlightEnabled())
            enableTouchHighlight(IntPoint(event.x, event.y));
760 761 762 763
#endif
        PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
        return mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
    }
764
    case WebInputEvent::GestureDoubleTap:
765
    case WebInputEvent::GestureScrollBegin:
766 767
    case WebInputEvent::GesturePinchBegin:
        m_client->cancelScheduledContentIntents();
768 769 770 771 772 773 774 775 776 777 778
    case WebInputEvent::GestureScrollEnd:
    case WebInputEvent::GestureScrollUpdate:
    case WebInputEvent::GesturePinchEnd:
    case WebInputEvent::GesturePinchUpdate: {
        PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
        return mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
    }
    default:
        ASSERT_NOT_REACHED();
    }
    return false;
779
}
780

781 782 783 784 785 786 787 788 789 790 791 792
void WebViewImpl::transferActiveWheelFlingAnimation(const WebActiveWheelFlingParameters& parameters)
{
    TRACE_EVENT0("webkit", "WebViewImpl::transferActiveWheelFlingAnimation");
    ASSERT(!m_gestureAnimation);
    m_lastWheelPosition = parameters.point;
    m_lastWheelGlobalPosition = parameters.globalPoint;
    m_flingModifier = parameters.modifiers;
    OwnPtr<PlatformGestureCurve> curve = TouchpadFlingPlatformGestureCurve::create(parameters.delta, IntPoint(parameters.cumulativeScroll));
    m_gestureAnimation = ActivePlatformGestureAnimation::create(curve.release(), this, parameters.startTime);
    scheduleAnimation();
}

793 794
void WebViewImpl::renderingStats(WebRenderingStats& stats) const
{
795 796
    if (m_layerTreeView)
        m_layerTreeView->renderingStats(stats);
797 798
}

799
void WebViewImpl::startPageScaleAnimation(const IntPoint& targetPosition, bool useAnchor, float newScale, double durationInSeconds)
800
{
801
    if (!m_layerTreeView)
802 803 804 805 806 807 808 809 810 811 812
        return;

    IntPoint clampedPoint = targetPosition;
    if (!useAnchor)
        clampedPoint = clampOffsetAtScale(targetPosition, newScale);

    if (!durationInSeconds && !useAnchor) {
        setPageScaleFactor(newScale, clampedPoint);
        return;
    }

813
    m_layerTreeView->startPageScaleAnimation(targetPosition, useAnchor, newScale, durationInSeconds);
814
}
815 816
#endif

817 818 819 820 821
WebViewBenchmarkSupport* WebViewImpl::benchmarkSupport()
{
    return &m_benchmarkSupport;
}

822
bool WebViewImpl::handleKeyEvent(const WebKeyboardEvent& event)
823 824 825 826 827
{
    ASSERT((event.type == WebInputEvent::RawKeyDown)
        || (event.type == WebInputEvent::KeyDown)
        || (event.type == WebInputEvent::KeyUp));

828 829 830 831
    // Halt an in-progress fling on a key event.
    if (m_gestureAnimation)
        m_gestureAnimation.clear();

832 833 834 835 836 837 838 839
    // Please refer to the comments explaining the m_suppressNextKeypressEvent
    // member.
    // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
    // Webkit. A keyDown event is typically associated with a keyPress(char)
    // event and a keyUp event. We reset this flag here as this is a new keyDown
    // event.
    m_suppressNextKeypressEvent = false;

840 841 842 843
    // If there is a select popup, it should be the one processing the event,
    // not the page.
    if (m_selectPopup)
        return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
844 845 846 847 848 849 850 851 852 853
#if ENABLE(PAGE_POPUP)
    if (m_pagePopup) {
        m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
        // We need to ignore the next Char event after this otherwise pressing
        // enter when selecting an item in the popup will go to the page.
        if (WebInputEvent::RawKeyDown == event.type)
            m_suppressNextKeypressEvent = true;
        return true;
    }
#endif
854

855
    // Give Autocomplete a chance to consume the key events it is interested in.
856 857 858
    if (autocompleteHandleKeyEvent(event))
        return true;

859
    RefPtr<Frame> frame = focusedWebCoreFrame();
860 861 862 863 864 865 866
    if (!frame)
        return false;

    EventHandler* handler = frame->eventHandler();
    if (!handler)
        return keyEventDefault(event);

867
#if !OS(DARWIN)
868
    const WebInputEvent::Type contextMenuTriggeringEventType =
869
#if OS(WINDOWS)
870
        WebInputEvent::KeyUp;
871
#elif OS(UNIX)
872 873 874
        WebInputEvent::RawKeyDown;
#endif

875 876 877
    bool isUnmodifiedMenuKey = !(event.modifiers & WebInputEvent::InputModifiers) && event.windowsKeyCode == VKEY_APPS;
    bool isShiftF10 = event.modifiers == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10;
    if ((isUnmodifiedMenuKey || isShiftF10) && event.type == contextMenuTriggeringEventType) {
878 879 880
        sendContextMenuEvent(event);
        return true;
    }
881
#endif // !OS(DARWIN)
882 883 884 885

    PlatformKeyboardEventBuilder evt(event);

    if (handler->keyEvent(evt)) {
886 887 888
        if (WebI