• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 "AutoFillPopupMenuClient.h"
35 #include "AXObjectCache.h"
36 #include "BackForwardListChromium.h"
37 #include "CSSStyleSelector.h"
38 #include "CSSValueKeywords.h"
39 #include "Chrome.h"
40 #include "ColorSpace.h"
41 #include "CompositionUnderlineVectorBuilder.h"
42 #include "ContextMenu.h"
43 #include "ContextMenuController.h"
44 #include "ContextMenuItem.h"
45 #include "Cursor.h"
46 #include "DOMUtilitiesPrivate.h"
47 #include "DeviceOrientationClientProxy.h"
48 #include "Document.h"
49 #include "DocumentLoader.h"
50 #include "DragController.h"
51 #include "DragData.h"
52 #include "DragScrollTimer.h"
53 #include "Editor.h"
54 #include "EventHandler.h"
55 #include "Extensions3D.h"
56 #include "FocusController.h"
57 #include "FontDescription.h"
58 #include "FrameLoader.h"
59 #include "FrameTree.h"
60 #include "FrameView.h"
61 #include "GeolocationClientProxy.h"
62 #include "GraphicsContext.h"
63 #include "GraphicsContext3D.h"
64 #include "GraphicsContext3DInternal.h"
65 #include "HTMLInputElement.h"
66 #include "HTMLMediaElement.h"
67 #include "HTMLNames.h"
68 #include "HitTestResult.h"
69 #include "Image.h"
70 #include "ImageBuffer.h"
71 #include "InspectorController.h"
72 #include "KeyboardCodes.h"
73 #include "KeyboardEvent.h"
74 #include "MIMETypeRegistry.h"
75 #include "NodeRenderStyle.h"
76 #include "Page.h"
77 #include "PageGroup.h"
78 #include "PageGroupLoadDeferrer.h"
79 #include "Pasteboard.h"
80 #include "PlatformContextSkia.h"
81 #include "PlatformKeyboardEvent.h"
82 #include "PlatformMouseEvent.h"
83 #include "PlatformThemeChromiumGtk.h"
84 #include "PlatformWheelEvent.h"
85 #include "PopupMenuChromium.h"
86 #include "PopupMenuClient.h"
87 #include "ProgressTracker.h"
88 #include "RenderView.h"
89 #include "ResourceHandle.h"
90 #include "SecurityOrigin.h"
91 #include "SelectionController.h"
92 #include "Settings.h"
93 #include "SpeechInputClientImpl.h"
94 #include "Timer.h"
95 #include "TraceEvent.h"
96 #include "TypingCommand.h"
97 #include "UserGestureIndicator.h"
98 #include "Vector.h"
99 #include "WebAccessibilityObject.h"
100 #include "WebAutoFillClient.h"
101 #include "WebDevToolsAgentImpl.h"
102 #include "WebDevToolsAgentPrivate.h"
103 #include "WebDragData.h"
104 #include "WebFrameImpl.h"
105 #include "WebGraphicsContext3D.h"
106 #include "WebImage.h"
107 #include "WebInputElement.h"
108 #include "WebInputEvent.h"
109 #include "WebInputEventConversion.h"
110 #include "WebKit.h"
111 #include "WebKitClient.h"
112 #include "WebMediaPlayerAction.h"
113 #include "WebNode.h"
114 #include "WebPlugin.h"
115 #include "WebPluginContainerImpl.h"
116 #include "WebPoint.h"
117 #include "WebPopupMenuImpl.h"
118 #include "WebRect.h"
119 #include "WebRuntimeFeatures.h"
120 #include "WebSettingsImpl.h"
121 #include "WebString.h"
122 #include "WebVector.h"
123 #include "WebViewClient.h"
124 #include "cc/CCHeadsUpDisplay.h"
125 #include <wtf/ByteArray.h>
126 #include <wtf/CurrentTime.h>
127 #include <wtf/RefPtr.h>
128 
129 #if USE(CG)
130 #include <CoreGraphics/CGBitmapContext.h>
131 #include <CoreGraphics/CGContext.h>
132 #endif
133 
134 #if OS(WINDOWS)
135 #include "RenderThemeChromiumWin.h"
136 #else
137 #if OS(LINUX) || OS(FREEBSD)
138 #include "RenderThemeChromiumLinux.h"
139 #endif
140 #include "RenderTheme.h"
141 #endif
142 
143 // Get rid of WTF's pow define so we can use std::pow.
144 #undef pow
145 #include <cmath> // for std::pow
146 
147 using namespace WebCore;
148 
149 namespace {
150 
getCompositorContextAttributes()151 GraphicsContext3D::Attributes getCompositorContextAttributes()
152 {
153     // Explicitly disable antialiasing for the compositor. As of the time of
154     // this writing, the only platform that supported antialiasing for the
155     // compositor was Mac OS X, because the on-screen OpenGL context creation
156     // code paths on Windows and Linux didn't yet have multisampling support.
157     // Mac OS X essentially always behaves as though it's rendering offscreen.
158     // Multisampling has a heavy cost especially on devices with relatively low
159     // fill rate like most notebooks, and the Mac implementation would need to
160     // be optimized to resolve directly into the IOSurface shared between the
161     // GPU and browser processes. For these reasons and to avoid platform
162     // disparities we explicitly disable antialiasing.
163     GraphicsContext3D::Attributes attributes;
164     attributes.antialias = false;
165     return attributes;
166 }
167 
168 } // anonymous namespace
169 
170 namespace WebKit {
171 
172 // Change the text zoom level by kTextSizeMultiplierRatio each time the user
173 // zooms text in or out (ie., change by 20%).  The min and max values limit
174 // text zoom to half and 3x the original text size.  These three values match
175 // those in Apple's port in WebKit/WebKit/WebView/WebView.mm
176 const double WebView::textSizeMultiplierRatio = 1.2;
177 const double WebView::minTextSizeMultiplier = 0.5;
178 const double WebView::maxTextSizeMultiplier = 3.0;
179 
180 
181 // The group name identifies a namespace of pages.  Page group is used on OSX
182 // for some programs that use HTML views to display things that don't seem like
183 // web pages to the user (so shouldn't have visited link coloring).  We only use
184 // one page group.
185 const char* pageGroupName = "default";
186 
187 // Used to defer all page activity in cases where the embedder wishes to run
188 // a nested event loop. Using a stack enables nesting of message loop invocations.
189 static Vector<PageGroupLoadDeferrer*> pageGroupLoadDeferrerStack;
190 
191 // Ensure that the WebDragOperation enum values stay in sync with the original
192 // DragOperation constants.
193 #define COMPILE_ASSERT_MATCHING_ENUM(coreName) \
194     COMPILE_ASSERT(int(coreName) == int(Web##coreName), dummy##coreName)
195 COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone);
196 COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy);
197 COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink);
198 COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric);
199 COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate);
200 COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove);
201 COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete);
202 COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery);
203 
204 static const PopupContainerSettings autoFillPopupSettings = {
205     false, // setTextOnIndexChange
206     false, // acceptOnAbandon
207     true, // loopSelectionNavigation
208     false // restrictWidthOfListBox (For security reasons show the entire entry
209           // so the user doesn't enter information he did not intend to.)
210 };
211 
212 static bool shouldUseExternalPopupMenus = false;
213 
214 // WebView ----------------------------------------------------------------
215 
create(WebViewClient * client)216 WebView* WebView::create(WebViewClient* client)
217 {
218     // Keep runtime flag for device motion turned off until it's implemented.
219     WebRuntimeFeatures::enableDeviceMotion(false);
220 
221     // Pass the WebViewImpl's self-reference to the caller.
222     return adoptRef(new WebViewImpl(client)).leakRef();
223 }
224 
setUseExternalPopupMenus(bool useExternalPopupMenus)225 void WebView::setUseExternalPopupMenus(bool useExternalPopupMenus)
226 {
227     shouldUseExternalPopupMenus = useExternalPopupMenus;
228 }
229 
updateVisitedLinkState(unsigned long long linkHash)230 void WebView::updateVisitedLinkState(unsigned long long linkHash)
231 {
232     Page::visitedStateChanged(PageGroup::pageGroup(pageGroupName), linkHash);
233 }
234 
resetVisitedLinkState()235 void WebView::resetVisitedLinkState()
236 {
237     Page::allVisitedStateChanged(PageGroup::pageGroup(pageGroupName));
238 }
239 
willEnterModalLoop()240 void WebView::willEnterModalLoop()
241 {
242     PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
243     ASSERT(pageGroup);
244 
245     if (pageGroup->pages().isEmpty())
246         pageGroupLoadDeferrerStack.append(static_cast<PageGroupLoadDeferrer*>(0));
247     else {
248         // Pick any page in the page group since we are deferring all pages.
249         pageGroupLoadDeferrerStack.append(new PageGroupLoadDeferrer(*pageGroup->pages().begin(), true));
250     }
251 }
252 
didExitModalLoop()253 void WebView::didExitModalLoop()
254 {
255     ASSERT(pageGroupLoadDeferrerStack.size());
256 
257     delete pageGroupLoadDeferrerStack.last();
258     pageGroupLoadDeferrerStack.removeLast();
259 }
260 
initializeMainFrame(WebFrameClient * frameClient)261 void WebViewImpl::initializeMainFrame(WebFrameClient* frameClient)
262 {
263     // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame
264     // and releases that reference once the corresponding Frame is destroyed.
265     RefPtr<WebFrameImpl> frame = WebFrameImpl::create(frameClient);
266 
267     frame->initializeAsMainFrame(this);
268 
269     // Restrict the access to the local file system
270     // (see WebView.mm WebView::_commonInitializationWithFrameName).
271     SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForLocalOnly);
272 }
273 
setDevToolsAgentClient(WebDevToolsAgentClient * devToolsClient)274 void WebViewImpl::setDevToolsAgentClient(WebDevToolsAgentClient* devToolsClient)
275 {
276     if (devToolsClient)
277         m_devToolsAgent = new WebDevToolsAgentImpl(this, devToolsClient);
278     else
279         m_devToolsAgent.clear();
280 }
281 
setAutoFillClient(WebAutoFillClient * autoFillClient)282 void WebViewImpl::setAutoFillClient(WebAutoFillClient* autoFillClient)
283 {
284     m_autoFillClient = autoFillClient;
285 }
286 
setSpellCheckClient(WebSpellCheckClient * spellCheckClient)287 void WebViewImpl::setSpellCheckClient(WebSpellCheckClient* spellCheckClient)
288 {
289     m_spellCheckClient = spellCheckClient;
290 }
291 
WebViewImpl(WebViewClient * client)292 WebViewImpl::WebViewImpl(WebViewClient* client)
293     : m_client(client)
294     , m_autoFillClient(0)
295     , m_spellCheckClient(0)
296     , m_chromeClientImpl(this)
297     , m_contextMenuClientImpl(this)
298     , m_dragClientImpl(this)
299     , m_editorClientImpl(this)
300     , m_inspectorClientImpl(this)
301     , m_observedNewNavigation(false)
302 #ifndef NDEBUG
303     , m_newNavigationLoader(0)
304 #endif
305     , m_zoomLevel(0)
306     , m_minimumZoomLevel(zoomFactorToZoomLevel(minTextSizeMultiplier))
307     , m_maximumZoomLevel(zoomFactorToZoomLevel(maxTextSizeMultiplier))
308     , m_contextMenuAllowed(false)
309     , m_doingDragAndDrop(false)
310     , m_ignoreInputEvents(false)
311     , m_suppressNextKeypressEvent(false)
312     , m_initialNavigationPolicy(WebNavigationPolicyIgnore)
313     , m_imeAcceptEvents(true)
314     , m_operationsAllowed(WebDragOperationNone)
315     , m_dragOperation(WebDragOperationNone)
316     , m_autoFillPopupShowing(false)
317     , m_autoFillPopupClient(0)
318     , m_autoFillPopup(0)
319     , m_isTransparent(false)
320     , m_tabsToLinks(false)
321     , m_dragScrollTimer(new DragScrollTimer())
322 #if USE(ACCELERATED_COMPOSITING)
323     , m_layerRenderer(0)
324     , m_isAcceleratedCompositingActive(false)
325     , m_compositorCreationFailed(false)
326     , m_recreatingGraphicsContext(false)
327 #endif
328 #if ENABLE(INPUT_SPEECH)
329     , m_speechInputClient(SpeechInputClientImpl::create(client))
330 #endif
331     , m_deviceOrientationClientProxy(new DeviceOrientationClientProxy(client ? client->deviceOrientationClient() : 0))
332     , m_geolocationClientProxy(new GeolocationClientProxy(client ? client->geolocationClient() : 0))
333 {
334     // WebKit/win/WebView.cpp does the same thing, except they call the
335     // KJS specific wrapper around this method. We need to have threading
336     // initialized because CollatorICU requires it.
337     WTF::initializeThreading();
338     WTF::initializeMainThread();
339 
340     // set to impossible point so we always get the first mouse pos
341     m_lastMousePosition = WebPoint(-1, -1);
342 
343     Page::PageClients pageClients;
344     pageClients.chromeClient = &m_chromeClientImpl;
345     pageClients.contextMenuClient = &m_contextMenuClientImpl;
346     pageClients.editorClient = &m_editorClientImpl;
347     pageClients.dragClient = &m_dragClientImpl;
348     pageClients.inspectorClient = &m_inspectorClientImpl;
349 #if ENABLE(INPUT_SPEECH)
350     pageClients.speechInputClient = m_speechInputClient.get();
351 #endif
352     pageClients.deviceOrientationClient = m_deviceOrientationClientProxy.get();
353     pageClients.geolocationClient = m_geolocationClientProxy.get();
354     pageClients.backForwardClient = BackForwardListChromium::create(this);
355 
356     m_page.set(new Page(pageClients));
357 
358     m_geolocationClientProxy->setController(m_page->geolocationController());
359 
360     m_page->setGroupName(pageGroupName);
361 
362     m_inspectorSettingsMap.set(new SettingsMap);
363 }
364 
~WebViewImpl()365 WebViewImpl::~WebViewImpl()
366 {
367     ASSERT(!m_page);
368 }
369 
theme() const370 RenderTheme* WebViewImpl::theme() const
371 {
372     return m_page.get() ? m_page->theme() : RenderTheme::defaultTheme().get();
373 }
374 
mainFrameImpl()375 WebFrameImpl* WebViewImpl::mainFrameImpl()
376 {
377     return m_page.get() ? WebFrameImpl::fromFrame(m_page->mainFrame()) : 0;
378 }
379 
tabKeyCyclesThroughElements() const380 bool WebViewImpl::tabKeyCyclesThroughElements() const
381 {
382     ASSERT(m_page.get());
383     return m_page->tabKeyCyclesThroughElements();
384 }
385 
setTabKeyCyclesThroughElements(bool value)386 void WebViewImpl::setTabKeyCyclesThroughElements(bool value)
387 {
388     if (m_page)
389         m_page->setTabKeyCyclesThroughElements(value);
390 }
391 
mouseMove(const WebMouseEvent & event)392 void WebViewImpl::mouseMove(const WebMouseEvent& event)
393 {
394     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
395         return;
396 
397     m_lastMousePosition = WebPoint(event.x, event.y);
398 
399     // We call mouseMoved here instead of handleMouseMovedEvent because we need
400     // our ChromeClientImpl to receive changes to the mouse position and
401     // tooltip text, and mouseMoved handles all of that.
402     mainFrameImpl()->frame()->eventHandler()->mouseMoved(
403         PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
404 }
405 
mouseLeave(const WebMouseEvent & event)406 void WebViewImpl::mouseLeave(const WebMouseEvent& event)
407 {
408     // This event gets sent as the main frame is closing.  In that case, just
409     // ignore it.
410     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
411         return;
412 
413     m_client->setMouseOverURL(WebURL());
414 
415     mainFrameImpl()->frame()->eventHandler()->handleMouseMoveEvent(
416         PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
417 }
418 
mouseDown(const WebMouseEvent & event)419 void WebViewImpl::mouseDown(const WebMouseEvent& event)
420 {
421     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
422         return;
423 
424     // If there is a select popup open, close it as the user is clicking on
425     // the page (outside of the popup).  We also save it so we can prevent a
426     // click on the select element from immediately reopening the popup.
427     RefPtr<WebCore::PopupContainer> selectPopup;
428     if (event.button == WebMouseEvent::ButtonLeft) {
429         selectPopup = m_selectPopup;
430         hideSelectPopup();
431         ASSERT(!m_selectPopup);
432     }
433 
434     m_lastMouseDownPoint = WebPoint(event.x, event.y);
435 
436     RefPtr<Node> clickedNode;
437     if (event.button == WebMouseEvent::ButtonLeft) {
438         IntPoint point(event.x, event.y);
439         point = m_page->mainFrame()->view()->windowToContents(point);
440         HitTestResult result(m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, false));
441         Node* hitNode = result.innerNonSharedNode();
442 
443         // Take capture on a mouse down on a plugin so we can send it mouse events.
444         if (hitNode && hitNode->renderer() && hitNode->renderer()->isEmbeddedObject())
445             m_mouseCaptureNode = hitNode;
446 
447         // If a text field that has focus is clicked again, we should display the
448         // AutoFill popup.
449         RefPtr<Node> focusedNode = focusedWebCoreNode();
450         if (focusedNode.get() && toHTMLInputElement(focusedNode.get())) {
451             if (hitNode == focusedNode) {
452                 // Already focused text field was clicked, let's remember this.  If
453                 // focus has not changed after the mouse event is processed, we'll
454                 // trigger the autocomplete.
455                 clickedNode = focusedNode;
456             }
457         }
458     }
459 
460     mainFrameImpl()->frame()->loader()->resetMultipleFormSubmissionProtection();
461 
462     mainFrameImpl()->frame()->eventHandler()->handleMousePressEvent(
463         PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
464 
465     if (clickedNode.get() && clickedNode == focusedWebCoreNode()) {
466         // Focus has not changed, show the AutoFill popup.
467         static_cast<EditorClientImpl*>(m_page->editorClient())->
468             showFormAutofillForNode(clickedNode.get());
469     }
470     if (m_selectPopup && m_selectPopup == selectPopup) {
471         // That click triggered a select popup which is the same as the one that
472         // was showing before the click.  It means the user clicked the select
473         // while the popup was showing, and as a result we first closed then
474         // immediately reopened the select popup.  It needs to be closed.
475         hideSelectPopup();
476     }
477 
478     // Dispatch the contextmenu event regardless of if the click was swallowed.
479     // On Windows, we handle it on mouse up, not down.
480 #if OS(DARWIN)
481     if (event.button == WebMouseEvent::ButtonRight
482         || (event.button == WebMouseEvent::ButtonLeft
483             && event.modifiers & WebMouseEvent::ControlKey))
484         mouseContextMenu(event);
485 #elif OS(LINUX) || OS(FREEBSD)
486     if (event.button == WebMouseEvent::ButtonRight)
487         mouseContextMenu(event);
488 #endif
489 }
490 
mouseContextMenu(const WebMouseEvent & event)491 void WebViewImpl::mouseContextMenu(const WebMouseEvent& event)
492 {
493     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
494         return;
495 
496     m_page->contextMenuController()->clearContextMenu();
497 
498     PlatformMouseEventBuilder pme(mainFrameImpl()->frameView(), event);
499 
500     // Find the right target frame. See issue 1186900.
501     HitTestResult result = hitTestResultForWindowPos(pme.pos());
502     Frame* targetFrame;
503     if (result.innerNonSharedNode())
504         targetFrame = result.innerNonSharedNode()->document()->frame();
505     else
506         targetFrame = m_page->focusController()->focusedOrMainFrame();
507 
508 #if OS(WINDOWS)
509     targetFrame->view()->setCursor(pointerCursor());
510 #endif
511 
512     m_contextMenuAllowed = true;
513     targetFrame->eventHandler()->sendContextMenuEvent(pme);
514     m_contextMenuAllowed = false;
515     // Actually showing the context menu is handled by the ContextMenuClient
516     // implementation...
517 }
518 
mouseUp(const WebMouseEvent & event)519 void WebViewImpl::mouseUp(const WebMouseEvent& event)
520 {
521     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
522         return;
523 
524 #if OS(LINUX) || OS(FREEBSD)
525     // If the event was a middle click, attempt to copy text into the focused
526     // frame. We execute this before we let the page have a go at the event
527     // because the page may change what is focused during in its event handler.
528     //
529     // This code is in the mouse up handler. There is some debate about putting
530     // this here, as opposed to the mouse down handler.
531     //   xterm: pastes on up.
532     //   GTK: pastes on down.
533     //   Firefox: pastes on up.
534     //   Midori: couldn't paste at all with 0.1.2
535     //
536     // There is something of a webcompat angle to this well, as highlighted by
537     // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
538     // down then the text is pasted just before the onclick handler runs and
539     // clears the text box. So it's important this happens after the
540     // handleMouseReleaseEvent() earlier in this function
541     if (event.button == WebMouseEvent::ButtonMiddle) {
542         Frame* focused = focusedWebCoreFrame();
543         FrameView* view = m_page->mainFrame()->view();
544         IntPoint clickPoint(m_lastMouseDownPoint.x, m_lastMouseDownPoint.y);
545         IntPoint contentPoint = view->windowToContents(clickPoint);
546         HitTestResult hitTestResult = focused->eventHandler()->hitTestResultAtPoint(contentPoint, false, false, ShouldHitTestScrollbars);
547         // We don't want to send a paste when middle clicking a scroll bar or a
548         // link (which will navigate later in the code).  The main scrollbars
549         // have to be handled separately.
550         if (!hitTestResult.scrollbar() && !hitTestResult.isLiveLink() && focused && !view->scrollbarAtPoint(clickPoint)) {
551             Editor* editor = focused->editor();
552             Pasteboard* pasteboard = Pasteboard::generalPasteboard();
553             bool oldSelectionMode = pasteboard->isSelectionMode();
554             pasteboard->setSelectionMode(true);
555             editor->command(AtomicString("Paste")).execute();
556             pasteboard->setSelectionMode(oldSelectionMode);
557         }
558     }
559 #endif
560 
561     mainFrameImpl()->frame()->eventHandler()->handleMouseReleaseEvent(
562         PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
563 
564 #if OS(WINDOWS)
565     // Dispatch the contextmenu event regardless of if the click was swallowed.
566     // On Mac/Linux, we handle it on mouse down, not up.
567     if (event.button == WebMouseEvent::ButtonRight)
568         mouseContextMenu(event);
569 #endif
570 }
571 
mouseWheel(const WebMouseWheelEvent & event)572 bool WebViewImpl::mouseWheel(const WebMouseWheelEvent& event)
573 {
574     PlatformWheelEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
575     return mainFrameImpl()->frame()->eventHandler()->handleWheelEvent(platformEvent);
576 }
577 
keyEvent(const WebKeyboardEvent & event)578 bool WebViewImpl::keyEvent(const WebKeyboardEvent& event)
579 {
580     ASSERT((event.type == WebInputEvent::RawKeyDown)
581         || (event.type == WebInputEvent::KeyDown)
582         || (event.type == WebInputEvent::KeyUp));
583 
584     // Please refer to the comments explaining the m_suppressNextKeypressEvent
585     // member.
586     // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
587     // Webkit. A keyDown event is typically associated with a keyPress(char)
588     // event and a keyUp event. We reset this flag here as this is a new keyDown
589     // event.
590     m_suppressNextKeypressEvent = false;
591 
592     // Give any select popup a chance at consuming the key event.
593     if (selectPopupHandleKeyEvent(event))
594         return true;
595 
596     // Give Autocomplete a chance to consume the key events it is interested in.
597     if (autocompleteHandleKeyEvent(event))
598         return true;
599 
600     Frame* frame = focusedWebCoreFrame();
601     if (!frame)
602         return false;
603 
604     EventHandler* handler = frame->eventHandler();
605     if (!handler)
606         return keyEventDefault(event);
607 
608 #if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD)
609     const WebInputEvent::Type contextMenuTriggeringEventType =
610 #if OS(WINDOWS)
611         WebInputEvent::KeyUp;
612 #elif OS(LINUX) || OS(FREEBSD)
613         WebInputEvent::RawKeyDown;
614 #endif
615 
616     bool isUnmodifiedMenuKey = !(event.modifiers & WebInputEvent::InputModifiers) && event.windowsKeyCode == VKEY_APPS;
617     bool isShiftF10 = event.modifiers == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10;
618     if ((isUnmodifiedMenuKey || isShiftF10) && event.type == contextMenuTriggeringEventType) {
619         sendContextMenuEvent(event);
620         return true;
621     }
622 #endif // OS(WINDOWS) || OS(LINUX) || OS(FREEBSD)
623 
624     PlatformKeyboardEventBuilder evt(event);
625 
626     if (handler->keyEvent(evt)) {
627         if (WebInputEvent::RawKeyDown == event.type) {
628             // Suppress the next keypress event unless the focused node is a plug-in node.
629             // (Flash needs these keypress events to handle non-US keyboards.)
630             Node* node = frame->document()->focusedNode();
631             if (!node || !node->renderer() || !node->renderer()->isEmbeddedObject())
632                 m_suppressNextKeypressEvent = true;
633         }
634         return true;
635     }
636 
637     return keyEventDefault(event);
638 }
639 
selectPopupHandleKeyEvent(const WebKeyboardEvent & event)640 bool WebViewImpl::selectPopupHandleKeyEvent(const WebKeyboardEvent& event)
641 {
642     if (!m_selectPopup)
643         return false;
644 
645     return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
646 }
647 
autocompleteHandleKeyEvent(const WebKeyboardEvent & event)648 bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event)
649 {
650     if (!m_autoFillPopupShowing
651         // Home and End should be left to the text field to process.
652         || event.windowsKeyCode == VKEY_HOME
653         || event.windowsKeyCode == VKEY_END)
654       return false;
655 
656     // Pressing delete triggers the removal of the selected suggestion from the DB.
657     if (event.windowsKeyCode == VKEY_DELETE
658         && m_autoFillPopup->selectedIndex() != -1) {
659         Node* node = focusedWebCoreNode();
660         if (!node || (node->nodeType() != Node::ELEMENT_NODE)) {
661             ASSERT_NOT_REACHED();
662             return false;
663         }
664         Element* element = static_cast<Element*>(node);
665         if (!element->hasLocalName(HTMLNames::inputTag)) {
666             ASSERT_NOT_REACHED();
667             return false;
668         }
669 
670         int selectedIndex = m_autoFillPopup->selectedIndex();
671 
672         if (!m_autoFillPopupClient->canRemoveSuggestionAtIndex(selectedIndex))
673             return false;
674 
675         WebString name = WebInputElement(static_cast<HTMLInputElement*>(element)).nameForAutofill();
676         WebString value = m_autoFillPopupClient->itemText(selectedIndex);
677         m_autoFillClient->removeAutocompleteSuggestion(name, value);
678         // Update the entries in the currently showing popup to reflect the
679         // deletion.
680         m_autoFillPopupClient->removeSuggestionAtIndex(selectedIndex);
681         refreshAutoFillPopup();
682         return false;
683     }
684 
685     if (!m_autoFillPopup->isInterestedInEventForKey(event.windowsKeyCode))
686         return false;
687 
688     if (m_autoFillPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) {
689         // We need to ignore the next Char event after this otherwise pressing
690         // enter when selecting an item in the menu will go to the page.
691         if (WebInputEvent::RawKeyDown == event.type)
692             m_suppressNextKeypressEvent = true;
693         return true;
694     }
695 
696     return false;
697 }
698 
charEvent(const WebKeyboardEvent & event)699 bool WebViewImpl::charEvent(const WebKeyboardEvent& event)
700 {
701     ASSERT(event.type == WebInputEvent::Char);
702 
703     // Please refer to the comments explaining the m_suppressNextKeypressEvent
704     // member.  The m_suppressNextKeypressEvent is set if the KeyDown is
705     // handled by Webkit. A keyDown event is typically associated with a
706     // keyPress(char) event and a keyUp event. We reset this flag here as it
707     // only applies to the current keyPress event.
708     bool suppress = m_suppressNextKeypressEvent;
709     m_suppressNextKeypressEvent = false;
710 
711     Frame* frame = focusedWebCoreFrame();
712     if (!frame)
713         return suppress;
714 
715     EventHandler* handler = frame->eventHandler();
716     if (!handler)
717         return suppress || keyEventDefault(event);
718 
719     PlatformKeyboardEventBuilder evt(event);
720     if (!evt.isCharacterKey())
721         return true;
722 
723     // Accesskeys are triggered by char events and can't be suppressed.
724     if (handler->handleAccessKey(evt))
725         return true;
726 
727     // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
728     // the eventHandler::keyEvent. We mimic this behavior on all platforms since
729     // for now we are converting other platform's key events to windows key
730     // events.
731     if (evt.isSystemKey())
732         return false;
733 
734     if (!suppress && !handler->keyEvent(evt))
735         return keyEventDefault(event);
736 
737     return true;
738 }
739 
740 #if ENABLE(TOUCH_EVENTS)
touchEvent(const WebTouchEvent & event)741 bool WebViewImpl::touchEvent(const WebTouchEvent& event)
742 {
743     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
744         return false;
745 
746     PlatformTouchEventBuilder touchEventBuilder(mainFrameImpl()->frameView(), event);
747     return mainFrameImpl()->frame()->eventHandler()->handleTouchEvent(touchEventBuilder);
748 }
749 #endif
750 
751 #if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD)
752 // Mac has no way to open a context menu based on a keyboard event.
sendContextMenuEvent(const WebKeyboardEvent & event)753 bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event)
754 {
755     // The contextMenuController() holds onto the last context menu that was
756     // popped up on the page until a new one is created. We need to clear
757     // this menu before propagating the event through the DOM so that we can
758     // detect if we create a new menu for this event, since we won't create
759     // a new menu if the DOM swallows the event and the defaultEventHandler does
760     // not run.
761     page()->contextMenuController()->clearContextMenu();
762 
763     m_contextMenuAllowed = true;
764     Frame* focusedFrame = page()->focusController()->focusedOrMainFrame();
765     bool handled = focusedFrame->eventHandler()->sendContextMenuEventForKey();
766     m_contextMenuAllowed = false;
767     return handled;
768 }
769 #endif
770 
keyEventDefault(const WebKeyboardEvent & event)771 bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event)
772 {
773     Frame* frame = focusedWebCoreFrame();
774     if (!frame)
775         return false;
776 
777     switch (event.type) {
778     case WebInputEvent::Char:
779         if (event.windowsKeyCode == VKEY_SPACE) {
780             int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT);
781             return scrollViewWithKeyboard(keyCode, event.modifiers);
782         }
783         break;
784     case WebInputEvent::RawKeyDown:
785         if (event.modifiers == WebInputEvent::ControlKey) {
786             switch (event.windowsKeyCode) {
787 #if !OS(DARWIN)
788             case 'A':
789                 focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll"));
790                 return true;
791             case VKEY_INSERT:
792             case 'C':
793                 focusedFrame()->executeCommand(WebString::fromUTF8("Copy"));
794                 return true;
795 #endif
796             // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
797             // key combinations which affect scrolling. Safari is buggy in the
798             // sense that it scrolls the page for all Ctrl+scrolling key
799             // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
800             case VKEY_HOME:
801             case VKEY_END:
802                 break;
803             default:
804                 return false;
805             }
806         }
807         if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey))
808             return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers);
809         break;
810     default:
811         break;
812     }
813     return false;
814 }
815 
scrollViewWithKeyboard(int keyCode,int modifiers)816 bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers)
817 {
818     ScrollDirection scrollDirection;
819     ScrollGranularity scrollGranularity;
820 #if OS(DARWIN)
821     // Control-Up/Down should be PageUp/Down on Mac.
822     if (modifiers & WebMouseEvent::ControlKey) {
823       if (keyCode == VKEY_UP)
824         keyCode = VKEY_PRIOR;
825       else if (keyCode == VKEY_DOWN)
826         keyCode = VKEY_NEXT;
827     }
828 #endif
829     if (!mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity))
830         return false;
831     return propagateScroll(scrollDirection, scrollGranularity);
832 }
833 
mapKeyCodeForScroll(int keyCode,WebCore::ScrollDirection * scrollDirection,WebCore::ScrollGranularity * scrollGranularity)834 bool WebViewImpl::mapKeyCodeForScroll(int keyCode,
835                                       WebCore::ScrollDirection* scrollDirection,
836                                       WebCore::ScrollGranularity* scrollGranularity)
837 {
838     switch (keyCode) {
839     case VKEY_LEFT:
840         *scrollDirection = ScrollLeft;
841         *scrollGranularity = ScrollByLine;
842         break;
843     case VKEY_RIGHT:
844         *scrollDirection = ScrollRight;
845         *scrollGranularity = ScrollByLine;
846         break;
847     case VKEY_UP:
848         *scrollDirection = ScrollUp;
849         *scrollGranularity = ScrollByLine;
850         break;
851     case VKEY_DOWN:
852         *scrollDirection = ScrollDown;
853         *scrollGranularity = ScrollByLine;
854         break;
855     case VKEY_HOME:
856         *scrollDirection = ScrollUp;
857         *scrollGranularity = ScrollByDocument;
858         break;
859     case VKEY_END:
860         *scrollDirection = ScrollDown;
861         *scrollGranularity = ScrollByDocument;
862         break;
863     case VKEY_PRIOR:  // page up
864         *scrollDirection = ScrollUp;
865         *scrollGranularity = ScrollByPage;
866         break;
867     case VKEY_NEXT:  // page down
868         *scrollDirection = ScrollDown;
869         *scrollGranularity = ScrollByPage;
870         break;
871     default:
872         return false;
873     }
874 
875     return true;
876 }
877 
hideSelectPopup()878 void WebViewImpl::hideSelectPopup()
879 {
880     if (m_selectPopup.get())
881         m_selectPopup->hidePopup();
882 }
883 
propagateScroll(ScrollDirection scrollDirection,ScrollGranularity scrollGranularity)884 bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection,
885                                   ScrollGranularity scrollGranularity)
886 {
887     Frame* frame = focusedWebCoreFrame();
888     if (!frame)
889         return false;
890 
891     bool scrollHandled = frame->eventHandler()->scrollOverflow(scrollDirection, scrollGranularity);
892     Frame* currentFrame = frame;
893     while (!scrollHandled && currentFrame) {
894         scrollHandled = currentFrame->view()->scroll(scrollDirection, scrollGranularity);
895         currentFrame = currentFrame->tree()->parent();
896     }
897     return scrollHandled;
898 }
899 
popupOpened(WebCore::PopupContainer * popupContainer)900 void  WebViewImpl::popupOpened(WebCore::PopupContainer* popupContainer)
901 {
902     if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
903         ASSERT(!m_selectPopup);
904         m_selectPopup = popupContainer;
905     }
906 }
907 
popupClosed(WebCore::PopupContainer * popupContainer)908 void  WebViewImpl::popupClosed(WebCore::PopupContainer* popupContainer)
909 {
910     if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
911         ASSERT(m_selectPopup.get());
912         m_selectPopup = 0;
913     }
914 }
915 
hideAutoFillPopup()916 void WebViewImpl::hideAutoFillPopup()
917 {
918     if (m_autoFillPopupShowing) {
919         m_autoFillPopup->hidePopup();
920         m_autoFillPopupShowing = false;
921     }
922 }
923 
focusedWebCoreFrame() const924 Frame* WebViewImpl::focusedWebCoreFrame() const
925 {
926     return m_page.get() ? m_page->focusController()->focusedOrMainFrame() : 0;
927 }
928 
fromPage(Page * page)929 WebViewImpl* WebViewImpl::fromPage(Page* page)
930 {
931     if (!page)
932         return 0;
933 
934     ChromeClientImpl* chromeClient = static_cast<ChromeClientImpl*>(page->chrome()->client());
935     return static_cast<WebViewImpl*>(chromeClient->webView());
936 }
937 
938 // WebWidget ------------------------------------------------------------------
939 
close()940 void WebViewImpl::close()
941 {
942     RefPtr<WebFrameImpl> mainFrameImpl;
943 
944     if (m_page.get()) {
945         // Initiate shutdown for the entire frameset.  This will cause a lot of
946         // notifications to be sent.
947         if (m_page->mainFrame()) {
948             mainFrameImpl = WebFrameImpl::fromFrame(m_page->mainFrame());
949             m_page->mainFrame()->loader()->frameDetached();
950         }
951         m_page.clear();
952     }
953 
954     // Should happen after m_page.clear().
955     if (m_devToolsAgent.get())
956         m_devToolsAgent.clear();
957 
958     // Reset the delegate to prevent notifications being sent as we're being
959     // deleted.
960     m_client = 0;
961 
962     deref();  // Balances ref() acquired in WebView::create
963 }
964 
resize(const WebSize & newSize)965 void WebViewImpl::resize(const WebSize& newSize)
966 {
967     if (m_size == newSize)
968         return;
969     m_size = newSize;
970 
971     if (mainFrameImpl()->frameView()) {
972         mainFrameImpl()->frameView()->resize(m_size.width, m_size.height);
973         mainFrameImpl()->frame()->eventHandler()->sendResizeEvent();
974     }
975 
976     if (m_client) {
977         if (isAcceleratedCompositingActive()) {
978 #if USE(ACCELERATED_COMPOSITING)
979             updateLayerRendererViewport();
980 #endif
981         } else {
982             WebRect damagedRect(0, 0, m_size.width, m_size.height);
983             m_client->didInvalidateRect(damagedRect);
984         }
985     }
986 
987 #if USE(ACCELERATED_COMPOSITING)
988     if (m_layerRenderer && isAcceleratedCompositingActive()) {
989         m_layerRenderer->resizeOnscreenContent(IntSize(std::max(1, m_size.width),
990                                                        std::max(1, m_size.height)));
991     }
992 #endif
993 }
994 
animate()995 void WebViewImpl::animate()
996 {
997 #if ENABLE(REQUEST_ANIMATION_FRAME)
998     WebFrameImpl* webframe = mainFrameImpl();
999     if (webframe) {
1000         FrameView* view = webframe->frameView();
1001         if (view)
1002             view->serviceScriptedAnimations(convertSecondsToDOMTimeStamp(currentTime()));
1003     }
1004 #endif
1005 }
1006 
layout()1007 void WebViewImpl::layout()
1008 {
1009 
1010     WebFrameImpl* webframe = mainFrameImpl();
1011     if (webframe) {
1012         // In order for our child HWNDs (NativeWindowWidgets) to update properly,
1013         // they need to be told that we are updating the screen.  The problem is
1014         // that the native widgets need to recalculate their clip region and not
1015         // overlap any of our non-native widgets.  To force the resizing, call
1016         // setFrameRect().  This will be a quick operation for most frames, but
1017         // the NativeWindowWidgets will update a proper clipping region.
1018         FrameView* view = webframe->frameView();
1019         if (view)
1020             view->setFrameRect(view->frameRect());
1021 
1022         // setFrameRect may have the side-effect of causing existing page
1023         // layout to be invalidated, so layout needs to be called last.
1024 
1025         webframe->layout();
1026     }
1027 }
1028 
1029 #if USE(ACCELERATED_COMPOSITING)
doPixelReadbackToCanvas(WebCanvas * canvas,const IntRect & rect)1030 void WebViewImpl::doPixelReadbackToCanvas(WebCanvas* canvas, const IntRect& rect)
1031 {
1032 #if USE(SKIA)
1033     PlatformContextSkia context(canvas);
1034 
1035     // PlatformGraphicsContext is actually a pointer to PlatformContextSkia
1036     GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context));
1037     int bitmapHeight = canvas->getDevice()->accessBitmap(false).height();
1038 #elif USE(CG)
1039     GraphicsContext gc(canvas);
1040     int bitmapHeight = CGBitmapContextGetHeight(reinterpret_cast<CGContextRef>(canvas));
1041 #else
1042     notImplemented();
1043 #endif
1044     // Compute rect to sample from inverted GPU buffer.
1045     IntRect invertRect(rect.x(), bitmapHeight - rect.maxY(), rect.width(), rect.height());
1046 
1047     OwnPtr<ImageBuffer> imageBuffer(ImageBuffer::create(rect.size()));
1048     RefPtr<ByteArray> pixelArray(ByteArray::create(rect.width() * rect.height() * 4));
1049     if (imageBuffer.get() && pixelArray.get()) {
1050         m_layerRenderer->getFramebufferPixels(pixelArray->data(), invertRect);
1051         imageBuffer->putPremultipliedImageData(pixelArray.get(), rect.size(), IntRect(IntPoint(), rect.size()), IntPoint());
1052         gc.save();
1053         gc.translate(IntSize(0, bitmapHeight));
1054         gc.scale(FloatSize(1.0f, -1.0f));
1055         // Use invertRect in next line, so that transform above inverts it back to
1056         // desired destination rect.
1057         gc.drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, invertRect.location());
1058         gc.restore();
1059     }
1060 }
1061 #endif
1062 
paint(WebCanvas * canvas,const WebRect & rect)1063 void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect)
1064 {
1065     if (isAcceleratedCompositingActive()) {
1066 #if USE(ACCELERATED_COMPOSITING)
1067         doComposite();
1068 
1069         // If a canvas was passed in, we use it to grab a copy of the
1070         // freshly-rendered pixels.
1071         if (canvas) {
1072             // Clip rect to the confines of the rootLayerTexture.
1073             IntRect resizeRect(rect);
1074             resizeRect.intersect(IntRect(IntPoint(), m_layerRenderer->viewportSize()));
1075             doPixelReadbackToCanvas(canvas, resizeRect);
1076         }
1077 #endif
1078     } else {
1079         WebFrameImpl* webframe = mainFrameImpl();
1080         if (webframe)
1081             webframe->paint(canvas, rect);
1082     }
1083 }
1084 
themeChanged()1085 void WebViewImpl::themeChanged()
1086 {
1087     if (!page())
1088         return;
1089     FrameView* view = page()->mainFrame()->view();
1090 
1091     WebRect damagedRect(0, 0, m_size.width, m_size.height);
1092     view->invalidateRect(damagedRect);
1093 }
1094 
composite(bool finish)1095 void WebViewImpl::composite(bool finish)
1096 {
1097 #if USE(ACCELERATED_COMPOSITING)
1098     TRACE_EVENT("WebViewImpl::composite", this, 0);
1099     if (m_recreatingGraphicsContext) {
1100         // reallocateRenderer will request a repaint whether or not it succeeded
1101         // in creating a new context.
1102         reallocateRenderer();
1103         m_recreatingGraphicsContext = false;
1104         return;
1105     }
1106     doComposite();
1107 
1108     // Finish if requested.
1109     if (finish)
1110         m_layerRenderer->finish();
1111 
1112     // Put result onscreen.
1113     m_layerRenderer->present();
1114 
1115     GraphicsContext3D* context = m_layerRenderer->context();
1116     if (context->getExtensions()->getGraphicsResetStatusARB() != GraphicsContext3D::NO_ERROR) {
1117         // Trying to recover the context right here will not work if GPU process
1118         // died. This is because GpuChannelHost::OnErrorMessage will only be
1119         // called at the next iteration of the message loop, reverting our
1120         // recovery attempts here. Instead, we detach the root layer from the
1121         // renderer, recreate the renderer at the next message loop iteration
1122         // and request a repaint yet again.
1123         m_recreatingGraphicsContext = true;
1124         setRootLayerNeedsDisplay();
1125     }
1126 #endif
1127 }
1128 
1129 const WebInputEvent* WebViewImpl::m_currentInputEvent = 0;
1130 
handleInputEvent(const WebInputEvent & inputEvent)1131 bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
1132 {
1133     UserGestureIndicator gestureIndicator(WebInputEvent::isUserGestureEventType(inputEvent.type) ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);
1134 
1135     // If we've started a drag and drop operation, ignore input events until
1136     // we're done.
1137     if (m_doingDragAndDrop)
1138         return true;
1139 
1140     if (m_ignoreInputEvents)
1141         return true;
1142 
1143     m_currentInputEvent = &inputEvent;
1144 
1145     if (m_mouseCaptureNode.get() && WebInputEvent::isMouseEventType(inputEvent.type)) {
1146         // Save m_mouseCaptureNode since mouseCaptureLost() will clear it.
1147         RefPtr<Node> node = m_mouseCaptureNode;
1148 
1149         // Not all platforms call mouseCaptureLost() directly.
1150         if (inputEvent.type == WebInputEvent::MouseUp)
1151             mouseCaptureLost();
1152 
1153         AtomicString eventType;
1154         switch (inputEvent.type) {
1155         case WebInputEvent::MouseMove:
1156             eventType = eventNames().mousemoveEvent;
1157             break;
1158         case WebInputEvent::MouseLeave:
1159             eventType = eventNames().mouseoutEvent;
1160             break;
1161         case WebInputEvent::MouseDown:
1162             eventType = eventNames().mousedownEvent;
1163             break;
1164         case WebInputEvent::MouseUp:
1165             eventType = eventNames().mouseupEvent;
1166             break;
1167         default:
1168             ASSERT_NOT_REACHED();
1169         }
1170 
1171         node->dispatchMouseEvent(
1172               PlatformMouseEventBuilder(mainFrameImpl()->frameView(), *static_cast<const WebMouseEvent*>(&inputEvent)),
1173               eventType, static_cast<const WebMouseEvent*>(&inputEvent)->clickCount);
1174         m_currentInputEvent = 0;
1175         return true;
1176     }
1177 
1178     bool handled = true;
1179 
1180     // FIXME: WebKit seems to always return false on mouse events processing
1181     // methods. For now we'll assume it has processed them (as we are only
1182     // interested in whether keyboard events are processed).
1183     switch (inputEvent.type) {
1184     case WebInputEvent::MouseMove:
1185         mouseMove(*static_cast<const WebMouseEvent*>(&inputEvent));
1186         break;
1187 
1188     case WebInputEvent::MouseLeave:
1189         mouseLeave(*static_cast<const WebMouseEvent*>(&inputEvent));
1190         break;
1191 
1192     case WebInputEvent::MouseWheel:
1193         handled = mouseWheel(*static_cast<const WebMouseWheelEvent*>(&inputEvent));
1194         break;
1195 
1196     case WebInputEvent::MouseDown:
1197         mouseDown(*static_cast<const WebMouseEvent*>(&inputEvent));
1198         break;
1199 
1200     case WebInputEvent::MouseUp:
1201         mouseUp(*static_cast<const WebMouseEvent*>(&inputEvent));
1202         break;
1203 
1204     case WebInputEvent::RawKeyDown:
1205     case WebInputEvent::KeyDown:
1206     case WebInputEvent::KeyUp:
1207         handled = keyEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent));
1208         break;
1209 
1210     case WebInputEvent::Char:
1211         handled = charEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent));
1212         break;
1213 
1214 #if ENABLE(TOUCH_EVENTS)
1215     case WebInputEvent::TouchStart:
1216     case WebInputEvent::TouchMove:
1217     case WebInputEvent::TouchEnd:
1218     case WebInputEvent::TouchCancel:
1219         handled = touchEvent(*static_cast<const WebTouchEvent*>(&inputEvent));
1220         break;
1221 #endif
1222 
1223     default:
1224         handled = false;
1225     }
1226 
1227     m_currentInputEvent = 0;
1228 
1229     return handled;
1230 }
1231 
mouseCaptureLost()1232 void WebViewImpl::mouseCaptureLost()
1233 {
1234     m_mouseCaptureNode = 0;
1235 }
1236 
setFocus(bool enable)1237 void WebViewImpl::setFocus(bool enable)
1238 {
1239     m_page->focusController()->setFocused(enable);
1240     if (enable) {
1241         // Note that we don't call setActive() when disabled as this cause extra
1242         // focus/blur events to be dispatched.
1243         m_page->focusController()->setActive(true);
1244         RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
1245         if (focusedFrame) {
1246             Node* focusedNode = focusedFrame->document()->focusedNode();
1247             if (focusedNode && focusedNode->isElementNode()
1248                 && focusedFrame->selection()->selection().isNone()) {
1249                 // If the selection was cleared while the WebView was not
1250                 // focused, then the focus element shows with a focus ring but
1251                 // no caret and does respond to keyboard inputs.
1252                 Element* element = static_cast<Element*>(focusedNode);
1253                 if (element->isTextFormControl())
1254                     element->updateFocusAppearance(true);
1255                 else if (focusedNode->isContentEditable()) {
1256                     // updateFocusAppearance() selects all the text of
1257                     // contentseditable DIVs. So we set the selection explicitly
1258                     // instead. Note that this has the side effect of moving the
1259                     // caret back to the beginning of the text.
1260                     Position position(focusedNode, 0,
1261                                       Position::PositionIsOffsetInAnchor);
1262                     focusedFrame->selection()->setSelection(
1263                         VisibleSelection(position, SEL_DEFAULT_AFFINITY));
1264                 }
1265             }
1266         }
1267         m_imeAcceptEvents = true;
1268     } else {
1269         hideAutoFillPopup();
1270         hideSelectPopup();
1271 
1272         // Clear focus on the currently focused frame if any.
1273         if (!m_page.get())
1274             return;
1275 
1276         Frame* frame = m_page->mainFrame();
1277         if (!frame)
1278             return;
1279 
1280         RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
1281         if (focusedFrame.get()) {
1282             // Finish an ongoing composition to delete the composition node.
1283             Editor* editor = focusedFrame->editor();
1284             if (editor && editor->hasComposition())
1285                 editor->confirmComposition();
1286             m_imeAcceptEvents = false;
1287         }
1288     }
1289 }
1290 
setComposition(const WebString & text,const WebVector<WebCompositionUnderline> & underlines,int selectionStart,int selectionEnd)1291 bool WebViewImpl::setComposition(
1292     const WebString& text,
1293     const WebVector<WebCompositionUnderline>& underlines,
1294     int selectionStart,
1295     int selectionEnd)
1296 {
1297     Frame* focused = focusedWebCoreFrame();
1298     if (!focused || !m_imeAcceptEvents)
1299         return false;
1300     Editor* editor = focused->editor();
1301     if (!editor)
1302         return false;
1303 
1304     // The input focus has been moved to another WebWidget object.
1305     // We should use this |editor| object only to complete the ongoing
1306     // composition.
1307     if (!editor->canEdit() && !editor->hasComposition())
1308         return false;
1309 
1310     // We should verify the parent node of this IME composition node are
1311     // editable because JavaScript may delete a parent node of the composition
1312     // node. In this case, WebKit crashes while deleting texts from the parent
1313     // node, which doesn't exist any longer.
1314     PassRefPtr<Range> range = editor->compositionRange();
1315     if (range) {
1316         const Node* node = range->startContainer();
1317         if (!node || !node->isContentEditable())
1318             return false;
1319     }
1320 
1321     // If we're not going to fire a keypress event, then the keydown event was
1322     // canceled.  In that case, cancel any existing composition.
1323     if (text.isEmpty() || m_suppressNextKeypressEvent) {
1324         // A browser process sent an IPC message which does not contain a valid
1325         // string, which means an ongoing composition has been canceled.
1326         // If the ongoing composition has been canceled, replace the ongoing
1327         // composition string with an empty string and complete it.
1328         String emptyString;
1329         Vector<CompositionUnderline> emptyUnderlines;
1330         editor->setComposition(emptyString, emptyUnderlines, 0, 0);
1331         return text.isEmpty();
1332     }
1333 
1334     // When the range of composition underlines overlap with the range between
1335     // selectionStart and selectionEnd, WebKit somehow won't paint the selection
1336     // at all (see InlineTextBox::paint() function in InlineTextBox.cpp).
1337     // But the selection range actually takes effect.
1338     editor->setComposition(String(text),
1339                            CompositionUnderlineVectorBuilder(underlines),
1340                            selectionStart, selectionEnd);
1341 
1342     return editor->hasComposition();
1343 }
1344 
confirmComposition()1345 bool WebViewImpl::confirmComposition()
1346 {
1347     return confirmComposition(WebString());
1348 }
1349 
confirmComposition(const WebString & text)1350 bool WebViewImpl::confirmComposition(const WebString& text)
1351 {
1352     Frame* focused = focusedWebCoreFrame();
1353     if (!focused || !m_imeAcceptEvents)
1354         return false;
1355     Editor* editor = focused->editor();
1356     if (!editor || (!editor->hasComposition() && !text.length()))
1357         return false;
1358 
1359     // We should verify the parent node of this IME composition node are
1360     // editable because JavaScript may delete a parent node of the composition
1361     // node. In this case, WebKit crashes while deleting texts from the parent
1362     // node, which doesn't exist any longer.
1363     PassRefPtr<Range> range = editor->compositionRange();
1364     if (range) {
1365         const Node* node = range->startContainer();
1366         if (!node || !node->isContentEditable())
1367             return false;
1368     }
1369 
1370     if (editor->hasComposition()) {
1371         if (text.length())
1372             editor->confirmComposition(String(text));
1373         else
1374             editor->confirmComposition();
1375     } else
1376         editor->insertText(String(text), 0);
1377 
1378     return true;
1379 }
1380 
textInputType()1381 WebTextInputType WebViewImpl::textInputType()
1382 {
1383     WebTextInputType type = WebTextInputTypeNone;
1384     const Frame* focused = focusedWebCoreFrame();
1385     if (!focused)
1386         return type;
1387 
1388     const Editor* editor = focused->editor();
1389     if (!editor || !editor->canEdit())
1390         return type;
1391 
1392     SelectionController* controller = focused->selection();
1393     if (!controller)
1394         return type;
1395 
1396     const Node* node = controller->start().deprecatedNode();
1397     if (!node)
1398         return type;
1399 
1400     // FIXME: Support more text input types when necessary, eg. Number,
1401     // Date, Email, URL, etc.
1402     if (controller->isInPasswordField())
1403         type = WebTextInputTypePassword;
1404     else if (node->shouldUseInputMethod())
1405         type = WebTextInputTypeText;
1406 
1407     return type;
1408 }
1409 
caretOrSelectionBounds()1410 WebRect WebViewImpl::caretOrSelectionBounds()
1411 {
1412     WebRect rect;
1413     const Frame* focused = focusedWebCoreFrame();
1414     if (!focused)
1415         return rect;
1416 
1417     SelectionController* controller = focused->selection();
1418     if (!controller)
1419         return rect;
1420 
1421     const FrameView* view = focused->view();
1422     if (!view)
1423         return rect;
1424 
1425     const Node* node = controller->base().containerNode();
1426     if (!node || !node->renderer())
1427         return rect;
1428 
1429     if (controller->isCaret())
1430         rect = view->contentsToWindow(controller->absoluteCaretBounds());
1431     else if (controller->isRange()) {
1432         node = controller->extent().containerNode();
1433         RefPtr<Range> range = controller->toNormalizedRange();
1434         if (!node || !node->renderer() || !range)
1435             return rect;
1436         rect = view->contentsToWindow(focused->editor()->firstRectForRange(range.get()));
1437     }
1438     return rect;
1439 }
1440 
selectionRange(WebPoint & start,WebPoint & end) const1441 bool WebViewImpl::selectionRange(WebPoint& start, WebPoint& end) const
1442 {
1443     const Frame* frame = focusedWebCoreFrame();
1444     if (!frame)
1445         return false;
1446     RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange();
1447     RefPtr<Range> range(Range::create(selectedRange->startContainer()->document(),
1448                                       selectedRange->startContainer(),
1449                                       selectedRange->startOffset(),
1450                                       selectedRange->startContainer(),
1451                                       selectedRange->startOffset()));
1452 
1453     IntRect rect = frame->editor()->firstRectForRange(range.get());
1454     start.x = rect.x();
1455     start.y = rect.y() + rect.height() - 1;
1456 
1457     range = Range::create(selectedRange->endContainer()->document(),
1458                           selectedRange->endContainer(),
1459                           selectedRange->endOffset(),
1460                           selectedRange->endContainer(),
1461                           selectedRange->endOffset());
1462 
1463     rect = frame->editor()->firstRectForRange(range.get());
1464     end.x = rect.x() + rect.width() - 1;
1465     end.y = rect.y() + rect.height() - 1;
1466 
1467     start = frame->view()->contentsToWindow(start);
1468     end = frame->view()->contentsToWindow(end);
1469     return true;
1470 }
1471 
setTextDirection(WebTextDirection direction)1472 void WebViewImpl::setTextDirection(WebTextDirection direction)
1473 {
1474     // The Editor::setBaseWritingDirection() function checks if we can change
1475     // the text direction of the selected node and updates its DOM "dir"
1476     // attribute and its CSS "direction" property.
1477     // So, we just call the function as Safari does.
1478     const Frame* focused = focusedWebCoreFrame();
1479     if (!focused)
1480         return;
1481 
1482     Editor* editor = focused->editor();
1483     if (!editor || !editor->canEdit())
1484         return;
1485 
1486     switch (direction) {
1487     case WebTextDirectionDefault:
1488         editor->setBaseWritingDirection(NaturalWritingDirection);
1489         break;
1490 
1491     case WebTextDirectionLeftToRight:
1492         editor->setBaseWritingDirection(LeftToRightWritingDirection);
1493         break;
1494 
1495     case WebTextDirectionRightToLeft:
1496         editor->setBaseWritingDirection(RightToLeftWritingDirection);
1497         break;
1498 
1499     default:
1500         notImplemented();
1501         break;
1502     }
1503 }
1504 
isAcceleratedCompositingActive() const1505 bool WebViewImpl::isAcceleratedCompositingActive() const
1506 {
1507 #if USE(ACCELERATED_COMPOSITING)
1508     return m_isAcceleratedCompositingActive;
1509 #else
1510     return false;
1511 #endif
1512 }
1513 
1514 // WebView --------------------------------------------------------------------
1515 
settings()1516 WebSettings* WebViewImpl::settings()
1517 {
1518     if (!m_webSettings.get())
1519         m_webSettings.set(new WebSettingsImpl(m_page->settings()));
1520     ASSERT(m_webSettings.get());
1521     return m_webSettings.get();
1522 }
1523 
pageEncoding() const1524 WebString WebViewImpl::pageEncoding() const
1525 {
1526     if (!m_page.get())
1527         return WebString();
1528 
1529     return m_page->mainFrame()->document()->loader()->writer()->encoding();
1530 }
1531 
setPageEncoding(const WebString & encodingName)1532 void WebViewImpl::setPageEncoding(const WebString& encodingName)
1533 {
1534     if (!m_page.get())
1535         return;
1536 
1537     // Only change override encoding, don't change default encoding.
1538     // Note that the new encoding must be 0 if it isn't supposed to be set.
1539     String newEncodingName;
1540     if (!encodingName.isEmpty())
1541         newEncodingName = encodingName;
1542     m_page->mainFrame()->loader()->reloadWithOverrideEncoding(newEncodingName);
1543 }
1544 
dispatchBeforeUnloadEvent()1545 bool WebViewImpl::dispatchBeforeUnloadEvent()
1546 {
1547     // FIXME: This should really cause a recursive depth-first walk of all
1548     // frames in the tree, calling each frame's onbeforeunload.  At the moment,
1549     // we're consistent with Safari 3.1, not IE/FF.
1550     Frame* frame = m_page->mainFrame();
1551     if (!frame)
1552         return true;
1553 
1554     return frame->loader()->shouldClose();
1555 }
1556 
dispatchUnloadEvent()1557 void WebViewImpl::dispatchUnloadEvent()
1558 {
1559     // Run unload handlers.
1560     m_page->mainFrame()->loader()->closeURL();
1561 }
1562 
mainFrame()1563 WebFrame* WebViewImpl::mainFrame()
1564 {
1565     return mainFrameImpl();
1566 }
1567 
findFrameByName(const WebString & name,WebFrame * relativeToFrame)1568 WebFrame* WebViewImpl::findFrameByName(
1569     const WebString& name, WebFrame* relativeToFrame)
1570 {
1571     if (!relativeToFrame)
1572         relativeToFrame = mainFrame();
1573     Frame* frame = static_cast<WebFrameImpl*>(relativeToFrame)->frame();
1574     frame = frame->tree()->find(name);
1575     return WebFrameImpl::fromFrame(frame);
1576 }
1577 
focusedFrame()1578 WebFrame* WebViewImpl::focusedFrame()
1579 {
1580     return WebFrameImpl::fromFrame(focusedWebCoreFrame());
1581 }
1582 
setFocusedFrame(WebFrame * frame)1583 void WebViewImpl::setFocusedFrame(WebFrame* frame)
1584 {
1585     if (!frame) {
1586         // Clears the focused frame if any.
1587         Frame* frame = focusedWebCoreFrame();
1588         if (frame)
1589             frame->selection()->setFocused(false);
1590         return;
1591     }
1592     WebFrameImpl* frameImpl = static_cast<WebFrameImpl*>(frame);
1593     Frame* webcoreFrame = frameImpl->frame();
1594     webcoreFrame->page()->focusController()->setFocusedFrame(webcoreFrame);
1595 }
1596 
setInitialFocus(bool reverse)1597 void WebViewImpl::setInitialFocus(bool reverse)
1598 {
1599     if (!m_page.get())
1600         return;
1601 
1602     // Since we don't have a keyboard event, we'll create one.
1603     WebKeyboardEvent keyboardEvent;
1604     keyboardEvent.type = WebInputEvent::RawKeyDown;
1605     if (reverse)
1606         keyboardEvent.modifiers = WebInputEvent::ShiftKey;
1607 
1608     // VK_TAB which is only defined on Windows.
1609     keyboardEvent.windowsKeyCode = 0x09;
1610     PlatformKeyboardEventBuilder platformEvent(keyboardEvent);
1611     RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0);
1612 
1613     Frame* frame = page()->focusController()->focusedOrMainFrame();
1614     if (Document* document = frame->document())
1615         document->setFocusedNode(0);
1616     page()->focusController()->setInitialFocus(
1617         reverse ? FocusDirectionBackward : FocusDirectionForward,
1618         webkitEvent.get());
1619 }
1620 
clearFocusedNode()1621 void WebViewImpl::clearFocusedNode()
1622 {
1623     if (!m_page.get())
1624         return;
1625 
1626     RefPtr<Frame> frame = m_page->mainFrame();
1627     if (!frame.get())
1628         return;
1629 
1630     RefPtr<Document> document = frame->document();
1631     if (!document.get())
1632         return;
1633 
1634     RefPtr<Node> oldFocusedNode = document->focusedNode();
1635 
1636     // Clear the focused node.
1637     document->setFocusedNode(0);
1638 
1639     if (!oldFocusedNode.get())
1640         return;
1641 
1642     // If a text field has focus, we need to make sure the selection controller
1643     // knows to remove selection from it. Otherwise, the text field is still
1644     // processing keyboard events even though focus has been moved to the page and
1645     // keystrokes get eaten as a result.
1646     if (oldFocusedNode->hasTagName(HTMLNames::textareaTag)
1647         || (oldFocusedNode->hasTagName(HTMLNames::inputTag)
1648             && static_cast<HTMLInputElement*>(oldFocusedNode.get())->isTextField())) {
1649         // Clear the selection.
1650         SelectionController* selection = frame->selection();
1651         selection->clear();
1652     }
1653 }
1654 
scrollFocusedNodeIntoView()1655 void WebViewImpl::scrollFocusedNodeIntoView()
1656 {
1657     Node* focusedNode = focusedWebCoreNode();
1658     if (focusedNode && focusedNode->isElementNode()) {
1659         Element* elementNode = static_cast<Element*>(focusedNode);
1660         elementNode->scrollIntoViewIfNeeded(true);
1661     }
1662 }
1663 
zoomLevel()1664 double WebViewImpl::zoomLevel()
1665 {
1666     return m_zoomLevel;
1667 }
1668 
setZoomLevel(bool textOnly,double zoomLevel)1669 double WebViewImpl::setZoomLevel(bool textOnly, double zoomLevel)
1670 {
1671     if (zoomLevel < m_minimumZoomLevel)
1672         m_zoomLevel = m_minimumZoomLevel;
1673     else if (zoomLevel > m_maximumZoomLevel)
1674         m_zoomLevel = m_maximumZoomLevel;
1675     else
1676         m_zoomLevel = zoomLevel;
1677 
1678     Frame* frame = mainFrameImpl()->frame();
1679     WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
1680     if (pluginContainer)
1681         pluginContainer->plugin()->setZoomLevel(m_zoomLevel, textOnly);
1682     else {
1683         float zoomFactor = static_cast<float>(zoomLevelToZoomFactor(m_zoomLevel));
1684         if (textOnly)
1685             frame->setPageAndTextZoomFactors(1, zoomFactor);
1686         else
1687             frame->setPageAndTextZoomFactors(zoomFactor, 1);
1688     }
1689     return m_zoomLevel;
1690 }
1691 
zoomLimitsChanged(double minimumZoomLevel,double maximumZoomLevel)1692 void WebViewImpl::zoomLimitsChanged(double minimumZoomLevel,
1693                                     double maximumZoomLevel)
1694 {
1695     m_minimumZoomLevel = minimumZoomLevel;
1696     m_maximumZoomLevel = maximumZoomLevel;
1697     m_client->zoomLimitsChanged(m_minimumZoomLevel, m_maximumZoomLevel);
1698 }
1699 
fullFramePluginZoomLevelChanged(double zoomLevel)1700 void WebViewImpl::fullFramePluginZoomLevelChanged(double zoomLevel)
1701 {
1702     if (zoomLevel == m_zoomLevel)
1703         return;
1704 
1705     m_zoomLevel = std::max(std::min(zoomLevel, m_maximumZoomLevel), m_minimumZoomLevel);
1706     m_client->zoomLevelChanged();
1707 }
1708 
zoomLevelToZoomFactor(double zoomLevel)1709 double WebView::zoomLevelToZoomFactor(double zoomLevel)
1710 {
1711     return std::pow(textSizeMultiplierRatio, zoomLevel);
1712 }
1713 
zoomFactorToZoomLevel(double factor)1714 double WebView::zoomFactorToZoomLevel(double factor)
1715 {
1716     // Since factor = 1.2^level, level = log(factor) / log(1.2)
1717     return log(factor) / log(textSizeMultiplierRatio);
1718 }
1719 
performMediaPlayerAction(const WebMediaPlayerAction & action,const WebPoint & location)1720 void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action,
1721                                            const WebPoint& location)
1722 {
1723     HitTestResult result =
1724         hitTestResultForWindowPos(location);
1725     RefPtr<Node> node = result.innerNonSharedNode();
1726     if (!node->hasTagName(HTMLNames::videoTag) && !node->hasTagName(HTMLNames::audioTag))
1727       return;
1728 
1729     RefPtr<HTMLMediaElement> mediaElement =
1730         static_pointer_cast<HTMLMediaElement>(node);
1731     switch (action.type) {
1732     case WebMediaPlayerAction::Play:
1733         if (action.enable)
1734             mediaElement->play(mediaElement->processingUserGesture());
1735         else
1736             mediaElement->pause(mediaElement->processingUserGesture());
1737         break;
1738     case WebMediaPlayerAction::Mute:
1739         mediaElement->setMuted(action.enable);
1740         break;
1741     case WebMediaPlayerAction::Loop:
1742         mediaElement->setLoop(action.enable);
1743         break;
1744     case WebMediaPlayerAction::Controls:
1745         mediaElement->setControls(action.enable);
1746         break;
1747     default:
1748         ASSERT_NOT_REACHED();
1749     }
1750 }
1751 
copyImageAt(const WebPoint & point)1752 void WebViewImpl::copyImageAt(const WebPoint& point)
1753 {
1754     if (!m_page.get())
1755         return;
1756 
1757     HitTestResult result = hitTestResultForWindowPos(point);
1758 
1759     if (result.absoluteImageURL().isEmpty()) {
1760         // There isn't actually an image at these coordinates.  Might be because
1761         // the window scrolled while the context menu was open or because the page
1762         // changed itself between when we thought there was an image here and when
1763         // we actually tried to retreive the image.
1764         //
1765         // FIXME: implement a cache of the most recent HitTestResult to avoid having
1766         //        to do two hit tests.
1767         return;
1768     }
1769 
1770     m_page->mainFrame()->editor()->copyImage(result);
1771 }
1772 
dragSourceEndedAt(const WebPoint & clientPoint,const WebPoint & screenPoint,WebDragOperation operation)1773 void WebViewImpl::dragSourceEndedAt(
1774     const WebPoint& clientPoint,
1775     const WebPoint& screenPoint,
1776     WebDragOperation operation)
1777 {
1778     PlatformMouseEvent pme(clientPoint,
1779                            screenPoint,
1780                            LeftButton, MouseEventMoved, 0, false, false, false,
1781                            false, 0);
1782     m_page->mainFrame()->eventHandler()->dragSourceEndedAt(pme,
1783         static_cast<DragOperation>(operation));
1784     m_dragScrollTimer->stop();
1785 }
1786 
dragSourceMovedTo(const WebPoint & clientPoint,const WebPoint & screenPoint,WebDragOperation operation)1787 void WebViewImpl::dragSourceMovedTo(
1788     const WebPoint& clientPoint,
1789     const WebPoint& screenPoint,
1790     WebDragOperation operation)
1791 {
1792     m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint);
1793 }
1794 
dragSourceSystemDragEnded()1795 void WebViewImpl::dragSourceSystemDragEnded()
1796 {
1797     // It's possible for us to get this callback while not doing a drag if
1798     // it's from a previous page that got unloaded.
1799     if (m_doingDragAndDrop) {
1800         m_page->dragController()->dragEnded();
1801         m_doingDragAndDrop = false;
1802     }
1803 }
1804 
dragTargetDragEnter(const WebDragData & webDragData,const WebPoint & clientPoint,const WebPoint & screenPoint,WebDragOperationsMask operationsAllowed)1805 WebDragOperation WebViewImpl::dragTargetDragEnter(
1806     const WebDragData& webDragData,
1807     const WebPoint& clientPoint,
1808     const WebPoint& screenPoint,
1809     WebDragOperationsMask operationsAllowed)
1810 {
1811     ASSERT(!m_currentDragData.get());
1812 
1813     m_currentDragData = webDragData;
1814     m_operationsAllowed = operationsAllowed;
1815 
1816     return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragEnter);
1817 }
1818 
dragTargetDragOver(const WebPoint & clientPoint,const WebPoint & screenPoint,WebDragOperationsMask operationsAllowed)1819 WebDragOperation WebViewImpl::dragTargetDragOver(
1820     const WebPoint& clientPoint,
1821     const WebPoint& screenPoint,
1822     WebDragOperationsMask operationsAllowed)
1823 {
1824     m_operationsAllowed = operationsAllowed;
1825 
1826     return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragOver);
1827 }
1828 
dragTargetDragLeave()1829 void WebViewImpl::dragTargetDragLeave()
1830 {
1831     ASSERT(m_currentDragData.get());
1832 
1833     DragData dragData(
1834         m_currentDragData.get(),
1835         IntPoint(),
1836         IntPoint(),
1837         static_cast<DragOperation>(m_operationsAllowed));
1838 
1839     m_page->dragController()->dragExited(&dragData);
1840 
1841     // FIXME: why is the drag scroll timer not stopped here?
1842 
1843     m_dragOperation = WebDragOperationNone;
1844     m_currentDragData = 0;
1845 }
1846 
dragTargetDrop(const WebPoint & clientPoint,const WebPoint & screenPoint)1847 void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint,
1848                                  const WebPoint& screenPoint)
1849 {
1850     ASSERT(m_currentDragData.get());
1851 
1852     // If this webview transitions from the "drop accepting" state to the "not
1853     // accepting" state, then our IPC message reply indicating that may be in-
1854     // flight, or else delayed by javascript processing in this webview.  If a
1855     // drop happens before our IPC reply has reached the browser process, then
1856     // the browser forwards the drop to this webview.  So only allow a drop to
1857     // proceed if our webview m_dragOperation state is not DragOperationNone.
1858 
1859     if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop.
1860         dragTargetDragLeave();
1861         return;
1862     }
1863 
1864     DragData dragData(
1865         m_currentDragData.get(),
1866         clientPoint,
1867         screenPoint,
1868         static_cast<DragOperation>(m_operationsAllowed));
1869 
1870     m_page->dragController()->performDrag(&dragData);
1871 
1872     m_dragOperation = WebDragOperationNone;
1873     m_currentDragData = 0;
1874 
1875     m_dragScrollTimer->stop();
1876 }
1877 
dragTargetDragEnterOrOver(const WebPoint & clientPoint,const WebPoint & screenPoint,DragAction dragAction)1878 WebDragOperation WebViewImpl::dragTargetDragEnterOrOver(const WebPoint& clientPoint, const WebPoint& screenPoint, DragAction dragAction)
1879 {
1880     ASSERT(m_currentDragData.get());
1881 
1882     DragData dragData(
1883         m_currentDragData.get(),
1884         clientPoint,
1885         screenPoint,
1886         static_cast<DragOperation>(m_operationsAllowed));
1887 
1888     DragOperation dropEffect;
1889     if (dragAction == DragEnter)
1890         dropEffect = m_page->dragController()->dragEntered(&dragData);
1891     else
1892         dropEffect = m_page->dragController()->dragUpdated(&dragData);
1893 
1894     // Mask the drop effect operation against the drag source's allowed operations.
1895     if (!(dropEffect & dragData.draggingSourceOperationMask()))
1896         dropEffect = DragOperationNone;
1897 
1898      m_dragOperation = static_cast<WebDragOperation>(dropEffect);
1899 
1900     if (dragAction == DragOver)
1901         m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint);
1902     else
1903         m_dragScrollTimer->stop();
1904 
1905     return m_dragOperation;
1906 }
1907 
createUniqueIdentifierForRequest()1908 unsigned long WebViewImpl::createUniqueIdentifierForRequest()
1909 {
1910     if (m_page)
1911         return m_page->progress()->createUniqueIdentifier();
1912     return 0;
1913 }
1914 
inspectElementAt(const WebPoint & point)1915 void WebViewImpl::inspectElementAt(const WebPoint& point)
1916 {
1917     if (!m_page.get())
1918         return;
1919 
1920     if (point.x == -1 || point.y == -1)
1921         m_page->inspectorController()->inspect(0);
1922     else {
1923         HitTestResult result = hitTestResultForWindowPos(point);
1924 
1925         if (!result.innerNonSharedNode())
1926             return;
1927 
1928         m_page->inspectorController()->inspect(result.innerNonSharedNode());
1929     }
1930 }
1931 
inspectorSettings() const1932 WebString WebViewImpl::inspectorSettings() const
1933 {
1934     return m_inspectorSettings;
1935 }
1936 
setInspectorSettings(const WebString & settings)1937 void WebViewImpl::setInspectorSettings(const WebString& settings)
1938 {
1939     m_inspectorSettings = settings;
1940 }
1941 
inspectorSetting(const WebString & key,WebString * value) const1942 bool WebViewImpl::inspectorSetting(const WebString& key, WebString* value) const
1943 {
1944     if (!m_inspectorSettingsMap->contains(key))
1945         return false;
1946     *value = m_inspectorSettingsMap->get(key);
1947     return true;
1948 }
1949 
setInspectorSetting(const WebString & key,const WebString & value)1950 void WebViewImpl::setInspectorSetting(const WebString& key,
1951                                       const WebString& value)
1952 {
1953     m_inspectorSettingsMap->set(key, value);
1954     client()->didUpdateInspectorSetting(key, value);
1955 }
1956 
devToolsAgent()1957 WebDevToolsAgent* WebViewImpl::devToolsAgent()
1958 {
1959     return m_devToolsAgent.get();
1960 }
1961 
accessibilityObject()1962 WebAccessibilityObject WebViewImpl::accessibilityObject()
1963 {
1964     if (!mainFrameImpl())
1965         return WebAccessibilityObject();
1966 
1967     Document* document = mainFrameImpl()->frame()->document();
1968     return WebAccessibilityObject(
1969         document->axObjectCache()->getOrCreate(document->renderer()));
1970 }
1971 
applyAutoFillSuggestions(const WebNode & node,const WebVector<WebString> & names,const WebVector<WebString> & labels,const WebVector<WebString> & icons,const WebVector<int> & uniqueIDs,int separatorIndex)1972 void WebViewImpl::applyAutoFillSuggestions(
1973     const WebNode& node,
1974     const WebVector<WebString>& names,
1975     const WebVector<WebString>& labels,
1976     const WebVector<WebString>& icons,
1977     const WebVector<int>& uniqueIDs,
1978     int separatorIndex)
1979 {
1980     ASSERT(names.size() == labels.size());
1981     ASSERT(names.size() == uniqueIDs.size());
1982     ASSERT(separatorIndex < static_cast<int>(names.size()));
1983 
1984     if (names.isEmpty()) {
1985         hideAutoFillPopup();
1986         return;
1987     }
1988 
1989     RefPtr<Node> focusedNode = focusedWebCoreNode();
1990     // If the node for which we queried the AutoFill suggestions is not the
1991     // focused node, then we have nothing to do.  FIXME: also check the
1992     // caret is at the end and that the text has not changed.
1993     if (!focusedNode || focusedNode != PassRefPtr<Node>(node)) {
1994         hideAutoFillPopup();
1995         return;
1996     }
1997 
1998     HTMLInputElement* inputElem =
1999         static_cast<HTMLInputElement*>(focusedNode.get());
2000 
2001     // The first time the AutoFill popup is shown we'll create the client and
2002     // the popup.
2003     if (!m_autoFillPopupClient.get())
2004         m_autoFillPopupClient.set(new AutoFillPopupMenuClient);
2005 
2006     m_autoFillPopupClient->initialize(
2007         inputElem, names, labels, icons, uniqueIDs, separatorIndex);
2008 
2009     if (!m_autoFillPopup.get()) {
2010         m_autoFillPopup = PopupContainer::create(m_autoFillPopupClient.get(),
2011                                                  PopupContainer::Suggestion,
2012                                                  autoFillPopupSettings);
2013     }
2014 
2015     if (m_autoFillPopupShowing) {
2016         refreshAutoFillPopup();
2017     } else {
2018         m_autoFillPopup->showInRect(focusedNode->getRect(), focusedNode->ownerDocument()->view(), 0);
2019         m_autoFillPopupShowing = true;
2020     }
2021 }
2022 
hidePopups()2023 void WebViewImpl::hidePopups()
2024 {
2025     hideSelectPopup();
2026     hideAutoFillPopup();
2027 }
2028 
performCustomContextMenuAction(unsigned action)2029 void WebViewImpl::performCustomContextMenuAction(unsigned action)
2030 {
2031     if (!m_page)
2032         return;
2033     ContextMenu* menu = m_page->contextMenuController()->contextMenu();
2034     if (!menu)
2035         return;
2036     ContextMenuItem* item = menu->itemWithAction(static_cast<ContextMenuAction>(ContextMenuItemBaseCustomTag + action));
2037     if (item)
2038         m_page->contextMenuController()->contextMenuItemSelected(item);
2039     m_page->contextMenuController()->clearContextMenu();
2040 }
2041 
2042 // WebView --------------------------------------------------------------------
2043 
setIsTransparent(bool isTransparent)2044 void WebViewImpl::setIsTransparent(bool isTransparent)
2045 {
2046     // Set any existing frames to be transparent.
2047     Frame* frame = m_page->mainFrame();
2048     while (frame) {
2049         frame->view()->setTransparent(isTransparent);
2050         frame = frame->tree()->traverseNext();
2051     }
2052 
2053     // Future frames check this to know whether to be transparent.
2054     m_isTransparent = isTransparent;
2055 }
2056 
isTransparent() const2057 bool WebViewImpl::isTransparent() const
2058 {
2059     return m_isTransparent;
2060 }
2061 
setIsActive(bool active)2062 void WebViewImpl::setIsActive(bool active)
2063 {
2064     if (page() && page()->focusController())
2065         page()->focusController()->setActive(active);
2066 }
2067 
isActive() const2068 bool WebViewImpl::isActive() const
2069 {
2070     return (page() && page()->focusController()) ? page()->focusController()->isActive() : false;
2071 }
2072 
setDomainRelaxationForbidden(bool forbidden,const WebString & scheme)2073 void WebViewImpl::setDomainRelaxationForbidden(bool forbidden, const WebString& scheme)
2074 {
2075     SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(forbidden, String(scheme));
2076 }
2077 
setScrollbarColors(unsigned inactiveColor,unsigned activeColor,unsigned trackColor)2078 void WebViewImpl::setScrollbarColors(unsigned inactiveColor,
2079                                      unsigned activeColor,
2080                                      unsigned trackColor) {
2081 #if OS(LINUX) || OS(FREEBSD)
2082     PlatformThemeChromiumGtk::setScrollbarColors(inactiveColor,
2083                                                  activeColor,
2084                                                  trackColor);
2085 #endif
2086 }
2087 
setSelectionColors(unsigned activeBackgroundColor,unsigned activeForegroundColor,unsigned inactiveBackgroundColor,unsigned inactiveForegroundColor)2088 void WebViewImpl::setSelectionColors(unsigned activeBackgroundColor,
2089                                      unsigned activeForegroundColor,
2090                                      unsigned inactiveBackgroundColor,
2091                                      unsigned inactiveForegroundColor) {
2092 #if OS(LINUX) || OS(FREEBSD)
2093     RenderThemeChromiumLinux::setSelectionColors(activeBackgroundColor,
2094                                                  activeForegroundColor,
2095                                                  inactiveBackgroundColor,
2096                                                  inactiveForegroundColor);
2097     theme()->platformColorsDidChange();
2098 #endif
2099 }
2100 
addUserScript(const WebString & sourceCode,const WebVector<WebString> & patternsIn,WebView::UserScriptInjectAt injectAt,WebView::UserContentInjectIn injectIn)2101 void WebView::addUserScript(const WebString& sourceCode,
2102                             const WebVector<WebString>& patternsIn,
2103                             WebView::UserScriptInjectAt injectAt,
2104                             WebView::UserContentInjectIn injectIn)
2105 {
2106     OwnPtr<Vector<String> > patterns(new Vector<String>);
2107     for (size_t i = 0; i < patternsIn.size(); ++i)
2108         patterns->append(patternsIn[i]);
2109 
2110     PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
2111     RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create());
2112     pageGroup->addUserScriptToWorld(world.get(), sourceCode, WebURL(), patterns.release(), 0,
2113                                     static_cast<UserScriptInjectionTime>(injectAt),
2114                                     static_cast<UserContentInjectedFrames>(injectIn));
2115 }
2116 
addUserStyleSheet(const WebString & sourceCode,const WebVector<WebString> & patternsIn,WebView::UserContentInjectIn injectIn,WebView::UserStyleInjectionTime injectionTime)2117 void WebView::addUserStyleSheet(const WebString& sourceCode,
2118                                 const WebVector<WebString>& patternsIn,
2119                                 WebView::UserContentInjectIn injectIn,
2120                                 WebView::UserStyleInjectionTime injectionTime)
2121 {
2122     OwnPtr<Vector<String> > patterns(new Vector<String>);
2123     for (size_t i = 0; i < patternsIn.size(); ++i)
2124         patterns->append(patternsIn[i]);
2125 
2126     PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
2127     RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create());
2128 
2129     // FIXME: Current callers always want the level to be "author". It probably makes sense to let
2130     // callers specify this though, since in other cases the caller will probably want "user" level.
2131     //
2132     // FIXME: It would be nice to populate the URL correctly, instead of passing an empty URL.
2133     pageGroup->addUserStyleSheetToWorld(world.get(), sourceCode, WebURL(), patterns.release(), 0,
2134                                         static_cast<UserContentInjectedFrames>(injectIn),
2135                                         UserStyleAuthorLevel,
2136                                         static_cast<WebCore::UserStyleInjectionTime>(injectionTime));
2137 }
2138 
removeAllUserContent()2139 void WebView::removeAllUserContent()
2140 {
2141     PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
2142     pageGroup->removeAllUserContent();
2143 }
2144 
didCommitLoad(bool * isNewNavigation)2145 void WebViewImpl::didCommitLoad(bool* isNewNavigation)
2146 {
2147     if (isNewNavigation)
2148         *isNewNavigation = m_observedNewNavigation;
2149 
2150 #ifndef NDEBUG
2151     ASSERT(!m_observedNewNavigation
2152         || m_page->mainFrame()->loader()->documentLoader() == m_newNavigationLoader);
2153     m_newNavigationLoader = 0;
2154 #endif
2155     m_observedNewNavigation = false;
2156 }
2157 
useExternalPopupMenus()2158 bool WebViewImpl::useExternalPopupMenus()
2159 {
2160     return shouldUseExternalPopupMenus;
2161 }
2162 
navigationPolicyFromMouseEvent(unsigned short button,bool ctrl,bool shift,bool alt,bool meta,WebNavigationPolicy * policy)2163 bool WebViewImpl::navigationPolicyFromMouseEvent(unsigned short button,
2164                                                  bool ctrl, bool shift,
2165                                                  bool alt, bool meta,
2166                                                  WebNavigationPolicy* policy)
2167 {
2168 #if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD) || OS(SOLARIS)
2169     const bool newTabModifier = (button == 1) || ctrl;
2170 #elif OS(DARWIN)
2171     const bool newTabModifier = (button == 1) || meta;
2172 #endif
2173     if (!newTabModifier && !shift && !alt)
2174       return false;
2175 
2176     ASSERT(policy);
2177     if (newTabModifier) {
2178         if (shift)
2179           *policy = WebNavigationPolicyNewForegroundTab;
2180         else
2181           *policy = WebNavigationPolicyNewBackgroundTab;
2182     } else {
2183         if (shift)
2184           *policy = WebNavigationPolicyNewWindow;
2185         else
2186           *policy = WebNavigationPolicyDownload;
2187     }
2188     return true;
2189 }
2190 
startDragging(const WebDragData & dragData,WebDragOperationsMask mask,const WebImage & dragImage,const WebPoint & dragImageOffset)2191 void WebViewImpl::startDragging(const WebDragData& dragData,
2192                                 WebDragOperationsMask mask,
2193                                 const WebImage& dragImage,
2194                                 const WebPoint& dragImageOffset)
2195 {
2196     if (!m_client)
2197         return;
2198     ASSERT(!m_doingDragAndDrop);
2199     m_doingDragAndDrop = true;
2200     m_client->startDragging(dragData, mask, dragImage, dragImageOffset);
2201 }
2202 
observeNewNavigation()2203 void WebViewImpl::observeNewNavigation()
2204 {
2205     m_observedNewNavigation = true;
2206 #ifndef NDEBUG
2207     m_newNavigationLoader = m_page->mainFrame()->loader()->documentLoader();
2208 #endif
2209 }
2210 
setIgnoreInputEvents(bool newValue)2211 void WebViewImpl::setIgnoreInputEvents(bool newValue)
2212 {
2213     ASSERT(m_ignoreInputEvents != newValue);
2214     m_ignoreInputEvents = newValue;
2215 }
2216 
2217 #if ENABLE(NOTIFICATIONS)
notificationPresenterImpl()2218 NotificationPresenterImpl* WebViewImpl::notificationPresenterImpl()
2219 {
2220     if (!m_notificationPresenter.isInitialized() && m_client)
2221         m_notificationPresenter.initialize(m_client->notificationPresenter());
2222     return &m_notificationPresenter;
2223 }
2224 #endif
2225 
refreshAutoFillPopup()2226 void WebViewImpl::refreshAutoFillPopup()
2227 {
2228     ASSERT(m_autoFillPopupShowing);
2229 
2230     // Hide the popup if it has become empty.
2231     if (!m_autoFillPopupClient->listSize()) {
2232         hideAutoFillPopup();
2233         return;
2234     }
2235 
2236     IntRect oldBounds = m_autoFillPopup->frameRect();
2237     m_autoFillPopup->refresh(focusedWebCoreNode()->getRect());
2238     IntRect newBounds = m_autoFillPopup->frameRect();
2239     // Let's resize the backing window if necessary.
2240     if (oldBounds != newBounds) {
2241         WebPopupMenuImpl* popupMenu =
2242             static_cast<WebPopupMenuImpl*>(m_autoFillPopup->client());
2243         if (popupMenu)
2244             popupMenu->client()->setWindowRect(newBounds);
2245     }
2246 }
2247 
focusedWebCoreNode()2248 Node* WebViewImpl::focusedWebCoreNode()
2249 {
2250     Frame* frame = m_page->focusController()->focusedFrame();
2251     if (!frame)
2252         return 0;
2253 
2254     Document* document = frame->document();
2255     if (!document)
2256         return 0;
2257 
2258     return document->focusedNode();
2259 }
2260 
hitTestResultForWindowPos(const IntPoint & pos)2261 HitTestResult WebViewImpl::hitTestResultForWindowPos(const IntPoint& pos)
2262 {
2263     IntPoint docPoint(m_page->mainFrame()->view()->windowToContents(pos));
2264     return m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(docPoint, false);
2265 }
2266 
setTabsToLinks(bool enable)2267 void WebViewImpl::setTabsToLinks(bool enable)
2268 {
2269     m_tabsToLinks = enable;
2270 }
2271 
tabsToLinks() const2272 bool WebViewImpl::tabsToLinks() const
2273 {
2274     return m_tabsToLinks;
2275 }
2276 
2277 #if USE(ACCELERATED_COMPOSITING)
allowsAcceleratedCompositing()2278 bool WebViewImpl::allowsAcceleratedCompositing()
2279 {
2280     return !m_compositorCreationFailed;
2281 }
2282 
pageHasRTLStyle() const2283 bool WebViewImpl::pageHasRTLStyle() const
2284 {
2285     if (!page())
2286         return false;
2287     Document* document = page()->mainFrame()->document();
2288     if (!document)
2289         return false;
2290     RenderView* renderView = document->renderView();
2291     if (!renderView)
2292         return false;
2293     RenderStyle* style = renderView->style();
2294     if (!style)
2295         return false;
2296     return (style->direction() == RTL);
2297 }
2298 
setRootGraphicsLayer(WebCore::PlatformLayer * layer)2299 void WebViewImpl::setRootGraphicsLayer(WebCore::PlatformLayer* layer)
2300 {
2301     setIsAcceleratedCompositingActive(layer);
2302     if (m_layerRenderer)
2303         m_layerRenderer->setRootLayer(layer);
2304 
2305     IntRect damagedRect(0, 0, m_size.width, m_size.height);
2306     if (m_isAcceleratedCompositingActive)
2307         invalidateRootLayerRect(damagedRect);
2308     else
2309         m_client->didInvalidateRect(damagedRect);
2310 }
2311 
setRootLayerNeedsDisplay()2312 void WebViewImpl::setRootLayerNeedsDisplay()
2313 {
2314     m_client->scheduleComposite();
2315 }
2316 
2317 
scrollRootLayerRect(const IntSize & scrollDelta,const IntRect & clipRect)2318 void WebViewImpl::scrollRootLayerRect(const IntSize& scrollDelta, const IntRect& clipRect)
2319 {
2320     updateLayerRendererViewport();
2321     setRootLayerNeedsDisplay();
2322 }
2323 
invalidateRootLayerRect(const IntRect & rect)2324 void WebViewImpl::invalidateRootLayerRect(const IntRect& rect)
2325 {
2326     ASSERT(m_layerRenderer);
2327 
2328     if (!page())
2329         return;
2330 
2331     FrameView* view = page()->mainFrame()->view();
2332     IntRect dirtyRect = view->windowToContents(rect);
2333     updateLayerRendererViewport();
2334     m_layerRenderer->invalidateRootLayerRect(dirtyRect);
2335     setRootLayerNeedsDisplay();
2336 }
2337 
2338 class WebViewImplContentPainter : public TilePaintInterface {
2339     WTF_MAKE_NONCOPYABLE(WebViewImplContentPainter);
2340 public:
create(WebViewImpl * webViewImpl)2341     static PassOwnPtr<WebViewImplContentPainter*> create(WebViewImpl* webViewImpl)
2342     {
2343         return adoptPtr(new WebViewImplContentPainter(webViewImpl));
2344     }
2345 
paint(GraphicsContext & context,const IntRect & contentRect)2346     virtual void paint(GraphicsContext& context, const IntRect& contentRect)
2347     {
2348         Page* page = m_webViewImpl->page();
2349         if (!page)
2350             return;
2351         FrameView* view = page->mainFrame()->view();
2352         view->paintContents(&context, contentRect);
2353     }
2354 
2355 private:
WebViewImplContentPainter(WebViewImpl * webViewImpl)2356     explicit WebViewImplContentPainter(WebViewImpl* webViewImpl)
2357         : m_webViewImpl(webViewImpl)
2358     {
2359     }
2360 
2361     WebViewImpl* m_webViewImpl;
2362 };
2363 
setIsAcceleratedCompositingActive(bool active)2364 void WebViewImpl::setIsAcceleratedCompositingActive(bool active)
2365 {
2366     PlatformBridge::histogramEnumeration("GPU.setIsAcceleratedCompositingActive", active * 2 + m_isAcceleratedCompositingActive, 4);
2367 
2368     if (m_isAcceleratedCompositingActive == active)
2369         return;
2370 
2371     if (!active) {
2372         m_isAcceleratedCompositingActive = false;
2373         // We need to finish all GL rendering before sending
2374         // didActivateAcceleratedCompositing(false) to prevent
2375         // flickering when compositing turns off.
2376         if (m_layerRenderer)
2377             m_layerRenderer->finish();
2378         m_client->didActivateAcceleratedCompositing(false);
2379     } else if (m_layerRenderer) {
2380         m_isAcceleratedCompositingActive = true;
2381         m_layerRenderer->resizeOnscreenContent(WebCore::IntSize(std::max(1, m_size.width),
2382                                                                 std::max(1, m_size.height)));
2383 
2384         m_client->didActivateAcceleratedCompositing(true);
2385     } else {
2386         RefPtr<GraphicsContext3D> context = m_temporaryOnscreenGraphicsContext3D.release();
2387         if (!context) {
2388             context = GraphicsContext3D::create(getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow);
2389             if (context)
2390                 context->reshape(std::max(1, m_size.width), std::max(1, m_size.height));
2391         }
2392 
2393 
2394         m_layerRenderer = LayerRendererChromium::create(context.release(), WebViewImplContentPainter::create(this));
2395         if (m_layerRenderer) {
2396             m_client->didActivateAcceleratedCompositing(true);
2397             m_isAcceleratedCompositingActive = true;
2398             m_compositorCreationFailed = false;
2399         } else {
2400             m_isAcceleratedCompositingActive = false;
2401             m_client->didActivateAcceleratedCompositing(false);
2402             m_compositorCreationFailed = true;
2403         }
2404     }
2405     if (page())
2406         page()->mainFrame()->view()->setClipsRepaints(!m_isAcceleratedCompositingActive);
2407 }
2408 
doComposite()2409 void WebViewImpl::doComposite()
2410 {
2411     ASSERT(m_layerRenderer);
2412     if (!m_layerRenderer) {
2413         setIsAcceleratedCompositingActive(false);
2414         return;
2415     }
2416 
2417     ASSERT(isAcceleratedCompositingActive());
2418     if (!page())
2419         return;
2420 
2421     m_layerRenderer->setCompositeOffscreen(settings()->compositeToTextureEnabled());
2422 
2423     CCHeadsUpDisplay* hud = m_layerRenderer->headsUpDisplay();
2424     hud->setShowFPSCounter(settings()->showFPSCounter());
2425     hud->setShowPlatformLayerTree(settings()->showPlatformLayerTree());
2426 
2427     m_layerRenderer->updateAndDrawLayers();
2428 }
2429 
reallocateRenderer()2430 void WebViewImpl::reallocateRenderer()
2431 {
2432     RefPtr<GraphicsContext3D> newContext = m_temporaryOnscreenGraphicsContext3D.get();
2433     WebGraphicsContext3D* webContext = GraphicsContext3DInternal::extractWebGraphicsContext3D(newContext.get());
2434     if (!newContext || !webContext || webContext->isContextLost())
2435         newContext = GraphicsContext3D::create(
2436             getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow);
2437     // GraphicsContext3D::create might fail and return 0, in that case LayerRendererChromium::create will also return 0.
2438     RefPtr<LayerRendererChromium> layerRenderer = LayerRendererChromium::create(newContext, WebViewImplContentPainter::create(this));
2439 
2440     // Reattach the root layer.  Child layers will get reattached as a side effect of updateLayersRecursive.
2441     if (layerRenderer) {
2442         m_layerRenderer->transferRootLayer(layerRenderer.get());
2443         m_layerRenderer = layerRenderer;
2444         // FIXME: In MacOS newContext->reshape method needs to be called to
2445         // allocate IOSurfaces. All calls to create a context followed by
2446         // reshape should really be extracted into one function; it is not
2447         // immediately obvious that GraphicsContext3D object will not
2448         // function properly until its reshape method is called.
2449         newContext->reshape(std::max(1, m_size.width), std::max(1, m_size.height));
2450         setRootGraphicsLayer(m_layerRenderer->rootLayer());
2451         // Forces ViewHostMsg_DidActivateAcceleratedCompositing to be sent so
2452         // that the browser process can reacquire surfaces.
2453         m_client->didActivateAcceleratedCompositing(true);
2454     } else
2455         setRootGraphicsLayer(0);
2456 }
2457 #endif
2458 
updateLayerRendererViewport()2459 void WebViewImpl::updateLayerRendererViewport()
2460 {
2461     ASSERT(m_layerRenderer);
2462 
2463     if (!page())
2464         return;
2465 
2466     FrameView* view = page()->mainFrame()->view();
2467     IntRect contentRect = view->visibleContentRect(false);
2468     IntRect visibleRect = view->visibleContentRect(true);
2469     IntPoint scroll(view->scrollX(), view->scrollY());
2470 
2471     m_layerRenderer->setViewport(visibleRect, contentRect, scroll);
2472 }
2473 
graphicsContext3D()2474 WebGraphicsContext3D* WebViewImpl::graphicsContext3D()
2475 {
2476 #if USE(ACCELERATED_COMPOSITING)
2477     if (m_page->settings()->acceleratedCompositingEnabled() && allowsAcceleratedCompositing()) {
2478         if (m_layerRenderer) {
2479             WebGraphicsContext3D* webContext = GraphicsContext3DInternal::extractWebGraphicsContext3D(m_layerRenderer->context());
2480             if (webContext && !webContext->isContextLost())
2481                 return webContext;
2482         }
2483         if (m_temporaryOnscreenGraphicsContext3D) {
2484             WebGraphicsContext3D* webContext = GraphicsContext3DInternal::extractWebGraphicsContext3D(m_temporaryOnscreenGraphicsContext3D.get());
2485             if (webContext && !webContext->isContextLost())
2486                 return webContext;
2487         }
2488         m_temporaryOnscreenGraphicsContext3D = GraphicsContext3D::create(getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow);
2489         if (m_temporaryOnscreenGraphicsContext3D)
2490             m_temporaryOnscreenGraphicsContext3D->reshape(std::max(1, m_size.width), std::max(1, m_size.height));
2491         return GraphicsContext3DInternal::extractWebGraphicsContext3D(m_temporaryOnscreenGraphicsContext3D.get());
2492     }
2493 #endif
2494     return 0;
2495 }
2496 
2497 } // namespace WebKit
2498