2 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "WebViewImpl.h"
34 #include "AutoFillPopupMenuClient.h"
35 #include "AXObjectCache.h"
36 #include "BackForwardListImpl.h"
38 #include "ColorSpace.h"
39 #include "CompositionUnderlineVectorBuilder.h"
40 #include "ContextMenu.h"
41 #include "ContextMenuController.h"
42 #include "ContextMenuItem.h"
43 #include "CSSStyleSelector.h"
44 #include "CSSValueKeywords.h"
46 #include "DeviceOrientationClientProxy.h"
48 #include "DocumentLoader.h"
49 #include "DOMUtilitiesPrivate.h"
50 #include "DragController.h"
51 #include "DragScrollTimer.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 "GraphicsContext.h"
62 #include "GraphicsContext3D.h"
63 #include "GraphicsContext3DInternal.h"
64 #include "HTMLInputElement.h"
65 #include "HTMLMediaElement.h"
66 #include "HitTestResult.h"
67 #include "HTMLNames.h"
69 #include "ImageBuffer.h"
70 #include "ImageData.h"
71 #include "InspectorController.h"
72 #include "KeyboardCodes.h"
73 #include "KeyboardEvent.h"
74 #include "MIMETypeRegistry.h"
75 #include "NodeRenderStyle.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"
93 #include "SpeechInputClientImpl.h"
95 #include "TypingCommand.h"
96 #include "UserGestureIndicator.h"
98 #include "WebAccessibilityObject.h"
99 #include "WebDevToolsAgentPrivate.h"
100 #include "WebDevToolsAgentImpl.h"
101 #include "WebDragData.h"
102 #include "WebFrameImpl.h"
103 #include "WebImage.h"
104 #include "WebInputElement.h"
105 #include "WebInputEvent.h"
106 #include "WebInputEventConversion.h"
108 #include "WebKitClient.h"
109 #include "WebMediaPlayerAction.h"
111 #include "WebPlugin.h"
112 #include "WebPluginContainerImpl.h"
113 #include "WebPoint.h"
114 #include "WebPopupMenuImpl.h"
116 #include "WebRuntimeFeatures.h"
117 #include "WebSettingsImpl.h"
118 #include "WebString.h"
119 #include "WebVector.h"
120 #include "WebViewClient.h"
121 #include <wtf/RefPtr.h>
124 #include <CoreGraphics/CGContext.h>
128 #include "RenderThemeChromiumWin.h"
130 #if OS(LINUX) || OS(FREEBSD)
131 #include "RenderThemeChromiumLinux.h"
133 #include "RenderTheme.h"
136 // Get rid of WTF's pow define so we can use std::pow.
138 #include <cmath> // for std::pow
140 using namespace WebCore;
144 GraphicsContext3D::Attributes getCompositorContextAttributes()
146 // Explicitly disable antialiasing for the compositor. As of the time of
147 // this writing, the only platform that supported antialiasing for the
148 // compositor was Mac OS X, because the on-screen OpenGL context creation
149 // code paths on Windows and Linux didn't yet have multisampling support.
150 // Mac OS X essentially always behaves as though it's rendering offscreen.
151 // Multisampling has a heavy cost especially on devices with relatively low
152 // fill rate like most notebooks, and the Mac implementation would need to
153 // be optimized to resolve directly into the IOSurface shared between the
154 // GPU and browser processes. For these reasons and to avoid platform
155 // disparities we explicitly disable antialiasing.
156 GraphicsContext3D::Attributes attributes;
157 attributes.antialias = false;
161 } // anonymous namespace
165 // Change the text zoom level by kTextSizeMultiplierRatio each time the user
166 // zooms text in or out (ie., change by 20%). The min and max values limit
167 // text zoom to half and 3x the original text size. These three values match
168 // those in Apple's port in WebKit/WebKit/WebView/WebView.mm
169 const double WebView::textSizeMultiplierRatio = 1.2;
170 const double WebView::minTextSizeMultiplier = 0.5;
171 const double WebView::maxTextSizeMultiplier = 3.0;
174 // The group name identifies a namespace of pages. Page group is used on OSX
175 // for some programs that use HTML views to display things that don't seem like
176 // web pages to the user (so shouldn't have visited link coloring). We only use
178 const char* pageGroupName = "default";
180 // Used to defer all page activity in cases where the embedder wishes to run
181 // a nested event loop. Using a stack enables nesting of message loop invocations.
182 static Vector<PageGroupLoadDeferrer*> pageGroupLoadDeferrerStack;
184 // Ensure that the WebDragOperation enum values stay in sync with the original
185 // DragOperation constants.
186 #define COMPILE_ASSERT_MATCHING_ENUM(coreName) \
187 COMPILE_ASSERT(int(coreName) == int(Web##coreName), dummy##coreName)
188 COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone);
189 COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy);
190 COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink);
191 COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric);
192 COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate);
193 COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove);
194 COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete);
195 COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery);
197 static const PopupContainerSettings autoFillPopupSettings = {
198 false, // setTextOnIndexChange
199 false, // acceptOnAbandon
200 true, // loopSelectionNavigation
201 false, // restrictWidthOfListBox (For security reasons show the entire entry
202 // so the user doesn't enter information he did not intend to.)
203 // For suggestions, we use the direction of the input field as the direction
204 // of the popup items. The main reason is to keep the display of items in
205 // drop-down the same as the items in the input field.
206 PopupContainerSettings::DOMElementDirection,
209 static bool shouldUseExternalPopupMenus = false;
211 // WebView ----------------------------------------------------------------
213 WebView* WebView::create(WebViewClient* client, WebDevToolsAgentClient* devToolsClient)
215 // Keep runtime flag for device motion turned off until it's implemented.
216 WebRuntimeFeatures::enableDeviceMotion(false);
218 // Pass the WebViewImpl's self-reference to the caller.
219 return adoptRef(new WebViewImpl(client, devToolsClient)).leakRef();
222 void WebView::setUseExternalPopupMenus(bool useExternalPopupMenus)
224 shouldUseExternalPopupMenus = useExternalPopupMenus;
227 void WebView::updateVisitedLinkState(unsigned long long linkHash)
229 Page::visitedStateChanged(PageGroup::pageGroup(pageGroupName), linkHash);
232 void WebView::resetVisitedLinkState()
234 Page::allVisitedStateChanged(PageGroup::pageGroup(pageGroupName));
237 void WebView::willEnterModalLoop()
239 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
242 if (pageGroup->pages().isEmpty())
243 pageGroupLoadDeferrerStack.append(static_cast<PageGroupLoadDeferrer*>(0));
245 // Pick any page in the page group since we are deferring all pages.
246 pageGroupLoadDeferrerStack.append(new PageGroupLoadDeferrer(*pageGroup->pages().begin(), true));
250 void WebView::didExitModalLoop()
252 ASSERT(pageGroupLoadDeferrerStack.size());
254 delete pageGroupLoadDeferrerStack.last();
255 pageGroupLoadDeferrerStack.removeLast();
258 void WebViewImpl::initializeMainFrame(WebFrameClient* frameClient)
260 // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame
261 // and releases that reference once the corresponding Frame is destroyed.
262 RefPtr<WebFrameImpl> frame = WebFrameImpl::create(frameClient);
264 frame->initializeAsMainFrame(this);
266 // Restrict the access to the local file system
267 // (see WebView.mm WebView::_commonInitializationWithFrameName).
268 SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForLocalOnly);
271 WebViewImpl::WebViewImpl(WebViewClient* client, WebDevToolsAgentClient* devToolsClient)
273 , m_backForwardListClientImpl(this)
274 , m_chromeClientImpl(this)
275 , m_contextMenuClientImpl(this)
276 , m_dragClientImpl(this)
277 , m_editorClientImpl(this)
278 , m_inspectorClientImpl(this)
279 , m_observedNewNavigation(false)
281 , m_newNavigationLoader(0)
284 , m_minimumZoomLevel(zoomFactorToZoomLevel(minTextSizeMultiplier))
285 , m_maximumZoomLevel(zoomFactorToZoomLevel(maxTextSizeMultiplier))
286 , m_contextMenuAllowed(false)
287 , m_doingDragAndDrop(false)
288 , m_ignoreInputEvents(false)
289 , m_suppressNextKeypressEvent(false)
290 , m_initialNavigationPolicy(WebNavigationPolicyIgnore)
291 , m_imeAcceptEvents(true)
292 , m_dragTargetDispatch(false)
294 , m_dropEffect(DropEffectDefault)
295 , m_operationsAllowed(WebDragOperationNone)
296 , m_dragOperation(WebDragOperationNone)
297 , m_autoFillPopupShowing(false)
298 , m_autoFillPopupClient(0)
300 , m_isTransparent(false)
301 , m_tabsToLinks(false)
302 , m_dragScrollTimer(new DragScrollTimer())
303 #if USE(ACCELERATED_COMPOSITING)
305 , m_isAcceleratedCompositingActive(false)
306 , m_compositorCreationFailed(false)
308 #if ENABLE(INPUT_SPEECH)
309 , m_speechInputClient(SpeechInputClientImpl::create(client))
311 , m_deviceOrientationClientProxy(new DeviceOrientationClientProxy(client ? client->deviceOrientationClient() : 0))
313 // WebKit/win/WebView.cpp does the same thing, except they call the
314 // KJS specific wrapper around this method. We need to have threading
315 // initialized because CollatorICU requires it.
316 WTF::initializeThreading();
317 WTF::initializeMainThread();
319 // set to impossible point so we always get the first mouse pos
320 m_lastMousePosition = WebPoint(-1, -1);
323 m_devToolsAgent = new WebDevToolsAgentImpl(this, devToolsClient);
325 Page::PageClients pageClients;
326 pageClients.chromeClient = &m_chromeClientImpl;
327 pageClients.contextMenuClient = &m_contextMenuClientImpl;
328 pageClients.editorClient = &m_editorClientImpl;
329 pageClients.dragClient = &m_dragClientImpl;
330 pageClients.inspectorClient = &m_inspectorClientImpl;
331 #if ENABLE(INPUT_SPEECH)
332 pageClients.speechInputClient = m_speechInputClient.get();
334 pageClients.deviceOrientationClient = m_deviceOrientationClientProxy.get();
336 m_page.set(new Page(pageClients));
338 static_cast<BackForwardListImpl*>(m_page->backForwardList())->setClient(&m_backForwardListClientImpl);
339 m_page->setGroupName(pageGroupName);
341 m_inspectorSettingsMap.set(new SettingsMap);
344 WebViewImpl::~WebViewImpl()
349 RenderTheme* WebViewImpl::theme() const
351 return m_page.get() ? m_page->theme() : RenderTheme::defaultTheme().get();
354 WebFrameImpl* WebViewImpl::mainFrameImpl()
356 return m_page.get() ? WebFrameImpl::fromFrame(m_page->mainFrame()) : 0;
359 bool WebViewImpl::tabKeyCyclesThroughElements() const
361 ASSERT(m_page.get());
362 return m_page->tabKeyCyclesThroughElements();
365 void WebViewImpl::setTabKeyCyclesThroughElements(bool value)
368 m_page->setTabKeyCyclesThroughElements(value);
371 void WebViewImpl::mouseMove(const WebMouseEvent& event)
373 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
376 m_lastMousePosition = WebPoint(event.x, event.y);
378 // We call mouseMoved here instead of handleMouseMovedEvent because we need
379 // our ChromeClientImpl to receive changes to the mouse position and
380 // tooltip text, and mouseMoved handles all of that.
381 mainFrameImpl()->frame()->eventHandler()->mouseMoved(
382 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
385 void WebViewImpl::mouseLeave(const WebMouseEvent& event)
387 // This event gets sent as the main frame is closing. In that case, just
389 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
392 m_client->setMouseOverURL(WebURL());
394 mainFrameImpl()->frame()->eventHandler()->handleMouseMoveEvent(
395 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
398 void WebViewImpl::mouseDown(const WebMouseEvent& event)
400 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
403 // If there is a select popup open, close it as the user is clicking on
404 // the page (outside of the popup). We also save it so we can prevent a
405 // click on the select element from immediately reopening the popup.
406 RefPtr<WebCore::PopupContainer> selectPopup;
407 if (event.button == WebMouseEvent::ButtonLeft) {
408 selectPopup = m_selectPopup;
410 ASSERT(!m_selectPopup);
413 m_lastMouseDownPoint = WebPoint(event.x, event.y);
415 RefPtr<Node> clickedNode;
416 if (event.button == WebMouseEvent::ButtonLeft) {
417 IntPoint point(event.x, event.y);
418 point = m_page->mainFrame()->view()->windowToContents(point);
419 HitTestResult result(m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, false));
420 Node* hitNode = result.innerNonSharedNode();
422 // Take capture on a mouse down on a plugin so we can send it mouse events.
423 if (hitNode && hitNode->renderer() && hitNode->renderer()->isEmbeddedObject())
424 m_mouseCaptureNode = hitNode;
426 // If a text field that has focus is clicked again, we should display the
428 RefPtr<Node> focusedNode = focusedWebCoreNode();
429 if (focusedNode.get() && toHTMLInputElement(focusedNode.get())) {
430 if (hitNode == focusedNode) {
431 // Already focused text field was clicked, let's remember this. If
432 // focus has not changed after the mouse event is processed, we'll
433 // trigger the autocomplete.
434 clickedNode = focusedNode;
439 mainFrameImpl()->frame()->loader()->resetMultipleFormSubmissionProtection();
441 mainFrameImpl()->frame()->eventHandler()->handleMousePressEvent(
442 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
444 if (clickedNode.get() && clickedNode == focusedWebCoreNode()) {
445 // Focus has not changed, show the AutoFill popup.
446 static_cast<EditorClientImpl*>(m_page->editorClient())->
447 showFormAutofillForNode(clickedNode.get());
449 if (m_selectPopup && m_selectPopup == selectPopup) {
450 // That click triggered a select popup which is the same as the one that
451 // was showing before the click. It means the user clicked the select
452 // while the popup was showing, and as a result we first closed then
453 // immediately reopened the select popup. It needs to be closed.
457 // Dispatch the contextmenu event regardless of if the click was swallowed.
458 // On Windows, we handle it on mouse up, not down.
460 if (event.button == WebMouseEvent::ButtonRight
461 || (event.button == WebMouseEvent::ButtonLeft
462 && event.modifiers & WebMouseEvent::ControlKey))
463 mouseContextMenu(event);
464 #elif OS(LINUX) || OS(FREEBSD)
465 if (event.button == WebMouseEvent::ButtonRight)
466 mouseContextMenu(event);
470 void WebViewImpl::mouseContextMenu(const WebMouseEvent& event)
472 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
475 m_page->contextMenuController()->clearContextMenu();
477 PlatformMouseEventBuilder pme(mainFrameImpl()->frameView(), event);
479 // Find the right target frame. See issue 1186900.
480 HitTestResult result = hitTestResultForWindowPos(pme.pos());
482 if (result.innerNonSharedNode())
483 targetFrame = result.innerNonSharedNode()->document()->frame();
485 targetFrame = m_page->focusController()->focusedOrMainFrame();
488 targetFrame->view()->setCursor(pointerCursor());
491 m_contextMenuAllowed = true;
492 targetFrame->eventHandler()->sendContextMenuEvent(pme);
493 m_contextMenuAllowed = false;
494 // Actually showing the context menu is handled by the ContextMenuClient
498 void WebViewImpl::mouseUp(const WebMouseEvent& event)
500 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
503 #if OS(LINUX) || OS(FREEBSD)
504 // If the event was a middle click, attempt to copy text into the focused
505 // frame. We execute this before we let the page have a go at the event
506 // because the page may change what is focused during in its event handler.
508 // This code is in the mouse up handler. There is some debate about putting
509 // this here, as opposed to the mouse down handler.
510 // xterm: pastes on up.
511 // GTK: pastes on down.
512 // Firefox: pastes on up.
513 // Midori: couldn't paste at all with 0.1.2
515 // There is something of a webcompat angle to this well, as highlighted by
516 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
517 // down then the text is pasted just before the onclick handler runs and
518 // clears the text box. So it's important this happens after the
519 // handleMouseReleaseEvent() earlier in this function
520 if (event.button == WebMouseEvent::ButtonMiddle) {
521 Frame* focused = focusedWebCoreFrame();
522 FrameView* view = m_page->mainFrame()->view();
523 IntPoint clickPoint(m_lastMouseDownPoint.x, m_lastMouseDownPoint.y);
524 IntPoint contentPoint = view->windowToContents(clickPoint);
525 HitTestResult hitTestResult = focused->eventHandler()->hitTestResultAtPoint(contentPoint, false, false, ShouldHitTestScrollbars);
526 // We don't want to send a paste when middle clicking a scroll bar or a
527 // link (which will navigate later in the code). The main scrollbars
528 // have to be handled separately.
529 if (!hitTestResult.scrollbar() && !hitTestResult.isLiveLink() && focused && !view->scrollbarAtPoint(clickPoint)) {
530 Editor* editor = focused->editor();
531 Pasteboard* pasteboard = Pasteboard::generalPasteboard();
532 bool oldSelectionMode = pasteboard->isSelectionMode();
533 pasteboard->setSelectionMode(true);
534 editor->command(AtomicString("Paste")).execute();
535 pasteboard->setSelectionMode(oldSelectionMode);
540 mainFrameImpl()->frame()->eventHandler()->handleMouseReleaseEvent(
541 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
544 // Dispatch the contextmenu event regardless of if the click was swallowed.
545 // On Mac/Linux, we handle it on mouse down, not up.
546 if (event.button == WebMouseEvent::ButtonRight)
547 mouseContextMenu(event);
551 bool WebViewImpl::mouseWheel(const WebMouseWheelEvent& event)
553 PlatformWheelEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
554 return mainFrameImpl()->frame()->eventHandler()->handleWheelEvent(platformEvent);
557 bool WebViewImpl::keyEvent(const WebKeyboardEvent& event)
559 ASSERT((event.type == WebInputEvent::RawKeyDown)
560 || (event.type == WebInputEvent::KeyDown)
561 || (event.type == WebInputEvent::KeyUp));
563 // Please refer to the comments explaining the m_suppressNextKeypressEvent
565 // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
566 // Webkit. A keyDown event is typically associated with a keyPress(char)
567 // event and a keyUp event. We reset this flag here as this is a new keyDown
569 m_suppressNextKeypressEvent = false;
571 // Give any select popup a chance at consuming the key event.
572 if (selectPopupHandleKeyEvent(event))
575 // Give Autocomplete a chance to consume the key events it is interested in.
576 if (autocompleteHandleKeyEvent(event))
579 Frame* frame = focusedWebCoreFrame();
583 EventHandler* handler = frame->eventHandler();
585 return keyEventDefault(event);
587 #if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD)
588 const WebInputEvent::Type contextMenuTriggeringEventType =
590 WebInputEvent::KeyUp;
591 #elif OS(LINUX) || OS(FREEBSD)
592 WebInputEvent::RawKeyDown;
595 bool isUnmodifiedMenuKey = !(event.modifiers & WebInputEvent::InputModifiers) && event.windowsKeyCode == VKEY_APPS;
596 bool isShiftF10 = event.modifiers == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10;
597 if ((isUnmodifiedMenuKey || isShiftF10) && event.type == contextMenuTriggeringEventType) {
598 sendContextMenuEvent(event);
601 #endif // OS(WINDOWS) || OS(LINUX) || OS(FREEBSD)
603 // It's not clear if we should continue after detecting a capslock keypress.
604 // I'll err on the side of continuing, which is the pre-existing behaviour.
605 if (event.windowsKeyCode == VKEY_CAPITAL)
606 handler->capsLockStateMayHaveChanged();
608 PlatformKeyboardEventBuilder evt(event);
610 if (handler->keyEvent(evt)) {
611 if (WebInputEvent::RawKeyDown == event.type) {
612 // Suppress the next keypress event unless the focused node is a plug-in node.
613 // (Flash needs these keypress events to handle non-US keyboards.)
614 Node* node = frame->document()->focusedNode();
615 if (!node || !node->renderer() || !node->renderer()->isEmbeddedObject())
616 m_suppressNextKeypressEvent = true;
621 return keyEventDefault(event);
624 bool WebViewImpl::selectPopupHandleKeyEvent(const WebKeyboardEvent& event)
629 return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
632 bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event)
634 if (!m_autoFillPopupShowing
635 // Home and End should be left to the text field to process.
636 || event.windowsKeyCode == VKEY_HOME
637 || event.windowsKeyCode == VKEY_END)
640 // Pressing delete triggers the removal of the selected suggestion from the DB.
641 if (event.windowsKeyCode == VKEY_DELETE
642 && m_autoFillPopup->selectedIndex() != -1) {
643 Node* node = focusedWebCoreNode();
644 if (!node || (node->nodeType() != Node::ELEMENT_NODE)) {
645 ASSERT_NOT_REACHED();
648 Element* element = static_cast<Element*>(node);
649 if (!element->hasLocalName(HTMLNames::inputTag)) {
650 ASSERT_NOT_REACHED();
654 int selectedIndex = m_autoFillPopup->selectedIndex();
656 if (!m_autoFillPopupClient->canRemoveSuggestionAtIndex(selectedIndex))
659 WebString name = WebInputElement(static_cast<HTMLInputElement*>(element)).nameForAutofill();
660 WebString value = m_autoFillPopupClient->itemText(selectedIndex);
661 m_client->removeAutofillSuggestions(name, value);
662 // Update the entries in the currently showing popup to reflect the
664 m_autoFillPopupClient->removeSuggestionAtIndex(selectedIndex);
665 refreshAutoFillPopup();
669 if (!m_autoFillPopup->isInterestedInEventForKey(event.windowsKeyCode))
672 if (m_autoFillPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) {
673 // We need to ignore the next Char event after this otherwise pressing
674 // enter when selecting an item in the menu will go to the page.
675 if (WebInputEvent::RawKeyDown == event.type)
676 m_suppressNextKeypressEvent = true;
683 bool WebViewImpl::charEvent(const WebKeyboardEvent& event)
685 ASSERT(event.type == WebInputEvent::Char);
687 // Please refer to the comments explaining the m_suppressNextKeypressEvent
688 // member. The m_suppressNextKeypressEvent is set if the KeyDown is
689 // handled by Webkit. A keyDown event is typically associated with a
690 // keyPress(char) event and a keyUp event. We reset this flag here as it
691 // only applies to the current keyPress event.
692 bool suppress = m_suppressNextKeypressEvent;
693 m_suppressNextKeypressEvent = false;
695 Frame* frame = focusedWebCoreFrame();
699 EventHandler* handler = frame->eventHandler();
701 return suppress || keyEventDefault(event);
703 PlatformKeyboardEventBuilder evt(event);
704 if (!evt.isCharacterKey())
707 // Accesskeys are triggered by char events and can't be suppressed.
708 if (handler->handleAccessKey(evt))
711 // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
712 // the eventHandler::keyEvent. We mimic this behavior on all platforms since
713 // for now we are converting other platform's key events to windows key
715 if (evt.isSystemKey())
718 if (!suppress && !handler->keyEvent(evt))
719 return keyEventDefault(event);
724 #if ENABLE(TOUCH_EVENTS)
725 bool WebViewImpl::touchEvent(const WebTouchEvent& event)
727 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
730 PlatformTouchEventBuilder touchEventBuilder(mainFrameImpl()->frameView(), event);
731 return mainFrameImpl()->frame()->eventHandler()->handleTouchEvent(touchEventBuilder);
735 #if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD)
736 // Mac has no way to open a context menu based on a keyboard event.
737 bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event)
739 // The contextMenuController() holds onto the last context menu that was
740 // popped up on the page until a new one is created. We need to clear
741 // this menu before propagating the event through the DOM so that we can
742 // detect if we create a new menu for this event, since we won't create
743 // a new menu if the DOM swallows the event and the defaultEventHandler does
745 page()->contextMenuController()->clearContextMenu();
747 m_contextMenuAllowed = true;
748 Frame* focusedFrame = page()->focusController()->focusedOrMainFrame();
749 bool handled = focusedFrame->eventHandler()->sendContextMenuEventForKey();
750 m_contextMenuAllowed = false;
755 bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event)
757 Frame* frame = focusedWebCoreFrame();
761 switch (event.type) {
762 case WebInputEvent::Char:
763 if (event.windowsKeyCode == VKEY_SPACE) {
764 int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT);
765 return scrollViewWithKeyboard(keyCode, event.modifiers);
768 case WebInputEvent::RawKeyDown:
769 if (event.modifiers == WebInputEvent::ControlKey) {
770 switch (event.windowsKeyCode) {
773 focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll"));
777 focusedFrame()->executeCommand(WebString::fromUTF8("Copy"));
780 // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
781 // key combinations which affect scrolling. Safari is buggy in the
782 // sense that it scrolls the page for all Ctrl+scrolling key
783 // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
791 if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey))
792 return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers);
800 bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers)
802 ScrollDirection scrollDirection;
803 ScrollGranularity scrollGranularity;
804 if (!mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity))
806 return propagateScroll(scrollDirection, scrollGranularity);
809 bool WebViewImpl::mapKeyCodeForScroll(int keyCode,
810 WebCore::ScrollDirection* scrollDirection,
811 WebCore::ScrollGranularity* scrollGranularity)
815 *scrollDirection = ScrollLeft;
816 *scrollGranularity = ScrollByLine;
819 *scrollDirection = ScrollRight;
820 *scrollGranularity = ScrollByLine;
823 *scrollDirection = ScrollUp;
824 *scrollGranularity = ScrollByLine;
827 *scrollDirection = ScrollDown;
828 *scrollGranularity = ScrollByLine;
831 *scrollDirection = ScrollUp;
832 *scrollGranularity = ScrollByDocument;
835 *scrollDirection = ScrollDown;
836 *scrollGranularity = ScrollByDocument;
838 case VKEY_PRIOR: // page up
839 *scrollDirection = ScrollUp;
840 *scrollGranularity = ScrollByPage;
842 case VKEY_NEXT: // page down
843 *scrollDirection = ScrollDown;
844 *scrollGranularity = ScrollByPage;
853 void WebViewImpl::hideSelectPopup()
855 if (m_selectPopup.get())
856 m_selectPopup->hidePopup();
859 bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection,
860 ScrollGranularity scrollGranularity)
862 Frame* frame = focusedWebCoreFrame();
866 bool scrollHandled = frame->eventHandler()->scrollOverflow(scrollDirection, scrollGranularity);
867 Frame* currentFrame = frame;
868 while (!scrollHandled && currentFrame) {
869 scrollHandled = currentFrame->view()->scroll(scrollDirection, scrollGranularity);
870 currentFrame = currentFrame->tree()->parent();
872 return scrollHandled;
875 void WebViewImpl::popupOpened(WebCore::PopupContainer* popupContainer)
877 if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
878 ASSERT(!m_selectPopup);
879 m_selectPopup = popupContainer;
883 void WebViewImpl::popupClosed(WebCore::PopupContainer* popupContainer)
885 if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
886 ASSERT(m_selectPopup.get());
891 void WebViewImpl::hideAutoFillPopup()
893 if (m_autoFillPopupShowing) {
894 m_autoFillPopup->hidePopup();
895 m_autoFillPopupShowing = false;
899 Frame* WebViewImpl::focusedWebCoreFrame()
901 return m_page.get() ? m_page->focusController()->focusedOrMainFrame() : 0;
904 WebViewImpl* WebViewImpl::fromPage(Page* page)
909 return static_cast<ChromeClientImpl*>(page->chrome()->client())->webView();
912 // WebWidget ------------------------------------------------------------------
914 void WebViewImpl::close()
916 RefPtr<WebFrameImpl> mainFrameImpl;
919 // Initiate shutdown for the entire frameset. This will cause a lot of
920 // notifications to be sent.
921 if (m_page->mainFrame()) {
922 mainFrameImpl = WebFrameImpl::fromFrame(m_page->mainFrame());
923 m_page->mainFrame()->loader()->frameDetached();
928 // Should happen after m_page.clear().
929 if (m_devToolsAgent.get())
930 m_devToolsAgent.clear();
932 // Reset the delegate to prevent notifications being sent as we're being
936 deref(); // Balances ref() acquired in WebView::create
939 void WebViewImpl::resize(const WebSize& newSize)
941 if (m_size == newSize)
945 if (mainFrameImpl()->frameView()) {
946 mainFrameImpl()->frameView()->resize(m_size.width, m_size.height);
947 mainFrameImpl()->frame()->eventHandler()->sendResizeEvent();
951 WebRect damagedRect(0, 0, m_size.width, m_size.height);
952 if (isAcceleratedCompositingActive()) {
953 #if USE(ACCELERATED_COMPOSITING)
954 invalidateRootLayerRect(damagedRect);
957 m_client->didInvalidateRect(damagedRect);
960 #if USE(ACCELERATED_COMPOSITING)
961 if (m_layerRenderer && isAcceleratedCompositingActive()) {
962 m_layerRenderer->resizeOnscreenContent(IntSize(std::max(1, m_size.width),
963 std::max(1, m_size.height)));
968 void WebViewImpl::layout()
970 WebFrameImpl* webframe = mainFrameImpl();
972 // In order for our child HWNDs (NativeWindowWidgets) to update properly,
973 // they need to be told that we are updating the screen. The problem is
974 // that the native widgets need to recalculate their clip region and not
975 // overlap any of our non-native widgets. To force the resizing, call
976 // setFrameRect(). This will be a quick operation for most frames, but
977 // the NativeWindowWidgets will update a proper clipping region.
978 FrameView* view = webframe->frameView();
980 view->setFrameRect(view->frameRect());
982 // setFrameRect may have the side-effect of causing existing page
983 // layout to be invalidated, so layout needs to be called last.
989 #if USE(ACCELERATED_COMPOSITING)
990 void WebViewImpl::doPixelReadbackToCanvas(WebCanvas* canvas, const IntRect& rect)
992 ASSERT(rect.right() <= m_layerRenderer->rootLayerTextureSize().width()
993 && rect.bottom() <= m_layerRenderer->rootLayerTextureSize().height());
996 PlatformContextSkia context(canvas);
998 // PlatformGraphicsContext is actually a pointer to PlatformContextSkia
999 GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context));
1000 int bitmapHeight = canvas->getDevice()->accessBitmap(false).height();
1002 GraphicsContext gc(canvas);
1003 int bitmapHeight = CGBitmapContextGetHeight(reinterpret_cast<CGContextRef>(canvas));
1007 // Compute rect to sample from inverted GPU buffer.
1008 IntRect invertRect(rect.x(), bitmapHeight - rect.bottom(), rect.width(), rect.height());
1010 OwnPtr<ImageBuffer> imageBuffer(ImageBuffer::create(rect.size()));
1011 RefPtr<ImageData> imageData(ImageData::create(rect.width(), rect.height()));
1012 if (imageBuffer.get() && imageData.get()) {
1013 m_layerRenderer->getFramebufferPixels(imageData->data()->data()->data(), invertRect);
1014 imageBuffer->putPremultipliedImageData(imageData.get(), IntRect(IntPoint(), rect.size()), IntPoint());
1016 gc.translate(FloatSize(0.0f, bitmapHeight));
1017 gc.scale(FloatSize(1.0f, -1.0f));
1018 // Use invertRect in next line, so that transform above inverts it back to
1019 // desired destination rect.
1020 gc.drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, invertRect.location());
1026 void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect)
1028 if (isAcceleratedCompositingActive()) {
1029 #if USE(ACCELERATED_COMPOSITING)
1032 // If a canvas was passed in, we use it to grab a copy of the
1033 // freshly-rendered pixels.
1035 // Clip rect to the confines of the rootLayerTexture.
1036 IntRect resizeRect(rect);
1037 resizeRect.intersect(IntRect(IntPoint(), m_layerRenderer->rootLayerTextureSize()));
1038 doPixelReadbackToCanvas(canvas, resizeRect);
1042 WebFrameImpl* webframe = mainFrameImpl();
1044 webframe->paint(canvas, rect);
1048 void WebViewImpl::themeChanged()
1052 FrameView* view = page()->mainFrame()->view();
1054 WebRect damagedRect(0, 0, m_size.width, m_size.height);
1055 view->invalidateRect(damagedRect);
1058 void WebViewImpl::composite(bool finish)
1060 #if USE(ACCELERATED_COMPOSITING)
1063 // Finish if requested.
1065 m_layerRenderer->finish();
1067 // Put result onscreen.
1068 m_layerRenderer->present();
1070 GraphicsContext3D* context = m_layerRenderer->context();
1071 if (context->getExtensions()->getGraphicsResetStatusARB() != GraphicsContext3D::NO_ERROR)
1072 reallocateRenderer();
1076 const WebInputEvent* WebViewImpl::m_currentInputEvent = 0;
1078 bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
1080 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1082 // If we've started a drag and drop operation, ignore input events until
1084 if (m_doingDragAndDrop)
1087 if (m_ignoreInputEvents)
1090 m_currentInputEvent = &inputEvent;
1092 if (m_mouseCaptureNode.get() && WebInputEvent::isMouseEventType(inputEvent.type)) {
1093 // Save m_mouseCaptureNode since mouseCaptureLost() will clear it.
1094 RefPtr<Node> node = m_mouseCaptureNode;
1096 // Not all platforms call mouseCaptureLost() directly.
1097 if (inputEvent.type == WebInputEvent::MouseUp)
1100 AtomicString eventType;
1101 switch (inputEvent.type) {
1102 case WebInputEvent::MouseMove:
1103 eventType = eventNames().mousemoveEvent;
1105 case WebInputEvent::MouseLeave:
1106 eventType = eventNames().mouseoutEvent;
1108 case WebInputEvent::MouseDown:
1109 eventType = eventNames().mousedownEvent;
1111 case WebInputEvent::MouseUp:
1112 eventType = eventNames().mouseupEvent;
1115 ASSERT_NOT_REACHED();
1118 node->dispatchMouseEvent(
1119 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), *static_cast<const WebMouseEvent*>(&inputEvent)),
1120 eventType, static_cast<const WebMouseEvent*>(&inputEvent)->clickCount);
1121 m_currentInputEvent = 0;
1125 bool handled = true;
1127 // FIXME: WebKit seems to always return false on mouse events processing
1128 // methods. For now we'll assume it has processed them (as we are only
1129 // interested in whether keyboard events are processed).
1130 switch (inputEvent.type) {
1131 case WebInputEvent::MouseMove:
1132 mouseMove(*static_cast<const WebMouseEvent*>(&inputEvent));
1135 case WebInputEvent::MouseLeave:
1136 mouseLeave(*static_cast<const WebMouseEvent*>(&inputEvent));
1139 case WebInputEvent::MouseWheel:
1140 handled = mouseWheel(*static_cast<const WebMouseWheelEvent*>(&inputEvent));
1143 case WebInputEvent::MouseDown:
1144 mouseDown(*static_cast<const WebMouseEvent*>(&inputEvent));
1147 case WebInputEvent::MouseUp:
1148 mouseUp(*static_cast<const WebMouseEvent*>(&inputEvent));
1151 case WebInputEvent::RawKeyDown:
1152 case WebInputEvent::KeyDown:
1153 case WebInputEvent::KeyUp:
1154 handled = keyEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent));
1157 case WebInputEvent::Char:
1158 handled = charEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent));
1161 #if ENABLE(TOUCH_EVENTS)
1162 case WebInputEvent::TouchStart:
1163 case WebInputEvent::TouchMove:
1164 case WebInputEvent::TouchEnd:
1165 case WebInputEvent::TouchCancel:
1166 handled = touchEvent(*static_cast<const WebTouchEvent*>(&inputEvent));
1174 m_currentInputEvent = 0;
1179 void WebViewImpl::mouseCaptureLost()
1181 m_mouseCaptureNode = 0;
1184 void WebViewImpl::setFocus(bool enable)
1186 m_page->focusController()->setFocused(enable);
1188 // Note that we don't call setActive() when disabled as this cause extra
1189 // focus/blur events to be dispatched.
1190 m_page->focusController()->setActive(true);
1191 RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
1193 Node* focusedNode = focusedFrame->document()->focusedNode();
1194 if (focusedNode && focusedNode->isElementNode()
1195 && focusedFrame->selection()->selection().isNone()) {
1196 // If the selection was cleared while the WebView was not
1197 // focused, then the focus element shows with a focus ring but
1198 // no caret and does respond to keyboard inputs.
1199 Element* element = static_cast<Element*>(focusedNode);
1200 if (element->isTextFormControl())
1201 element->updateFocusAppearance(true);
1202 else if (focusedNode->isContentEditable()) {
1203 // updateFocusAppearance() selects all the text of
1204 // contentseditable DIVs. So we set the selection explicitly
1205 // instead. Note that this has the side effect of moving the
1206 // caret back to the beginning of the text.
1207 Position position(focusedNode, 0,
1208 Position::PositionIsOffsetInAnchor);
1209 focusedFrame->selection()->setSelection(
1210 VisibleSelection(position, SEL_DEFAULT_AFFINITY));
1214 m_imeAcceptEvents = true;
1216 hideAutoFillPopup();
1219 // Clear focus on the currently focused frame if any.
1223 Frame* frame = m_page->mainFrame();
1227 RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
1228 if (focusedFrame.get()) {
1229 // Finish an ongoing composition to delete the composition node.
1230 Editor* editor = focusedFrame->editor();
1231 if (editor && editor->hasComposition())
1232 editor->confirmComposition();
1233 m_imeAcceptEvents = false;
1238 bool WebViewImpl::setComposition(
1239 const WebString& text,
1240 const WebVector<WebCompositionUnderline>& underlines,
1244 Frame* focused = focusedWebCoreFrame();
1245 if (!focused || !m_imeAcceptEvents)
1247 Editor* editor = focused->editor();
1251 // The input focus has been moved to another WebWidget object.
1252 // We should use this |editor| object only to complete the ongoing
1254 if (!editor->canEdit() && !editor->hasComposition())
1257 // We should verify the parent node of this IME composition node are
1258 // editable because JavaScript may delete a parent node of the composition
1259 // node. In this case, WebKit crashes while deleting texts from the parent
1260 // node, which doesn't exist any longer.
1261 PassRefPtr<Range> range = editor->compositionRange();
1263 const Node* node = range->startPosition().node();
1264 if (!node || !node->isContentEditable())
1268 // If we're not going to fire a keypress event, then the keydown event was
1269 // canceled. In that case, cancel any existing composition.
1270 if (text.isEmpty() || m_suppressNextKeypressEvent) {
1271 // A browser process sent an IPC message which does not contain a valid
1272 // string, which means an ongoing composition has been canceled.
1273 // If the ongoing composition has been canceled, replace the ongoing
1274 // composition string with an empty string and complete it.
1276 Vector<CompositionUnderline> emptyUnderlines;
1277 editor->setComposition(emptyString, emptyUnderlines, 0, 0);
1278 return text.isEmpty();
1281 // When the range of composition underlines overlap with the range between
1282 // selectionStart and selectionEnd, WebKit somehow won't paint the selection
1283 // at all (see InlineTextBox::paint() function in InlineTextBox.cpp).
1284 // But the selection range actually takes effect.
1285 editor->setComposition(String(text),
1286 CompositionUnderlineVectorBuilder(underlines),
1287 selectionStart, selectionEnd);
1289 return editor->hasComposition();
1292 bool WebViewImpl::confirmComposition()
1294 Frame* focused = focusedWebCoreFrame();
1295 if (!focused || !m_imeAcceptEvents)
1297 Editor* editor = focused->editor();
1298 if (!editor || !editor->hasComposition())
1301 // We should verify the parent node of this IME composition node are
1302 // editable because JavaScript may delete a parent node of the composition
1303 // node. In this case, WebKit crashes while deleting texts from the parent
1304 // node, which doesn't exist any longer.
1305 PassRefPtr<Range> range = editor->compositionRange();
1307 const Node* node = range->startPosition().node();
1308 if (!node || !node->isContentEditable())
1312 editor->confirmComposition();
1316 WebTextInputType WebViewImpl::textInputType()
1318 WebTextInputType type = WebTextInputTypeNone;
1319 const Frame* focused = focusedWebCoreFrame();
1323 const Editor* editor = focused->editor();
1324 if (!editor || !editor->canEdit())
1327 SelectionController* controller = focused->selection();
1331 const Node* node = controller->start().node();
1335 // FIXME: Support more text input types when necessary, eg. Number,
1336 // Date, Email, URL, etc.
1337 if (controller->isInPasswordField())
1338 type = WebTextInputTypePassword;
1339 else if (node->shouldUseInputMethod())
1340 type = WebTextInputTypeText;
1345 WebRect WebViewImpl::caretOrSelectionBounds()
1348 const Frame* focused = focusedWebCoreFrame();
1352 SelectionController* controller = focused->selection();
1356 const FrameView* view = focused->view();
1360 const Node* node = controller->start().node();
1361 if (!node || !node->renderer())
1364 if (controller->isCaret())
1365 rect = view->contentsToWindow(controller->absoluteCaretBounds());
1366 else if (controller->isRange()) {
1367 node = controller->end().node();
1368 if (!node || !node->renderer())
1370 RefPtr<Range> range = controller->toNormalizedRange();
1371 rect = view->contentsToWindow(focused->editor()->firstRectForRange(range.get()));
1376 void WebViewImpl::setTextDirection(WebTextDirection direction)
1378 // The Editor::setBaseWritingDirection() function checks if we can change
1379 // the text direction of the selected node and updates its DOM "dir"
1380 // attribute and its CSS "direction" property.
1381 // So, we just call the function as Safari does.
1382 const Frame* focused = focusedWebCoreFrame();
1386 Editor* editor = focused->editor();
1387 if (!editor || !editor->canEdit())
1390 switch (direction) {
1391 case WebTextDirectionDefault:
1392 editor->setBaseWritingDirection(NaturalWritingDirection);
1395 case WebTextDirectionLeftToRight:
1396 editor->setBaseWritingDirection(LeftToRightWritingDirection);
1399 case WebTextDirectionRightToLeft:
1400 editor->setBaseWritingDirection(RightToLeftWritingDirection);
1409 bool WebViewImpl::isAcceleratedCompositingActive() const
1411 #if USE(ACCELERATED_COMPOSITING)
1412 return m_isAcceleratedCompositingActive;
1418 // WebView --------------------------------------------------------------------
1420 WebSettings* WebViewImpl::settings()
1422 if (!m_webSettings.get())
1423 m_webSettings.set(new WebSettingsImpl(m_page->settings()));
1424 ASSERT(m_webSettings.get());
1425 return m_webSettings.get();
1428 WebString WebViewImpl::pageEncoding() const
1433 return m_page->mainFrame()->loader()->writer()->encoding();
1436 void WebViewImpl::setPageEncoding(const WebString& encodingName)
1441 // Only change override encoding, don't change default encoding.
1442 // Note that the new encoding must be 0 if it isn't supposed to be set.
1443 String newEncodingName;
1444 if (!encodingName.isEmpty())
1445 newEncodingName = encodingName;
1446 m_page->mainFrame()->loader()->reloadWithOverrideEncoding(newEncodingName);
1449 bool WebViewImpl::dispatchBeforeUnloadEvent()
1451 // FIXME: This should really cause a recursive depth-first walk of all
1452 // frames in the tree, calling each frame's onbeforeunload. At the moment,
1453 // we're consistent with Safari 3.1, not IE/FF.
1454 Frame* frame = m_page->mainFrame();
1458 return frame->loader()->shouldClose();
1461 void WebViewImpl::dispatchUnloadEvent()
1463 // Run unload handlers.
1464 m_page->mainFrame()->loader()->closeURL();
1467 WebFrame* WebViewImpl::mainFrame()
1469 return mainFrameImpl();
1472 WebFrame* WebViewImpl::findFrameByName(
1473 const WebString& name, WebFrame* relativeToFrame)
1475 if (!relativeToFrame)
1476 relativeToFrame = mainFrame();
1477 Frame* frame = static_cast<WebFrameImpl*>(relativeToFrame)->frame();
1478 frame = frame->tree()->find(name);
1479 return WebFrameImpl::fromFrame(frame);
1482 WebFrame* WebViewImpl::focusedFrame()
1484 return WebFrameImpl::fromFrame(focusedWebCoreFrame());
1487 void WebViewImpl::setFocusedFrame(WebFrame* frame)
1490 // Clears the focused frame if any.
1491 Frame* frame = focusedWebCoreFrame();
1493 frame->selection()->setFocused(false);
1496 WebFrameImpl* frameImpl = static_cast<WebFrameImpl*>(frame);
1497 Frame* webcoreFrame = frameImpl->frame();
1498 webcoreFrame->page()->focusController()->setFocusedFrame(webcoreFrame);
1501 void WebViewImpl::setInitialFocus(bool reverse)
1506 // Since we don't have a keyboard event, we'll create one.
1507 WebKeyboardEvent keyboardEvent;
1508 keyboardEvent.type = WebInputEvent::RawKeyDown;
1510 keyboardEvent.modifiers = WebInputEvent::ShiftKey;
1512 // VK_TAB which is only defined on Windows.
1513 keyboardEvent.windowsKeyCode = 0x09;
1514 PlatformKeyboardEventBuilder platformEvent(keyboardEvent);
1515 RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0);
1517 Frame* frame = page()->focusController()->focusedOrMainFrame();
1518 if (Document* document = frame->document())
1519 document->setFocusedNode(0);
1520 page()->focusController()->setInitialFocus(
1521 reverse ? FocusDirectionBackward : FocusDirectionForward,
1525 void WebViewImpl::clearFocusedNode()
1530 RefPtr<Frame> frame = m_page->mainFrame();
1534 RefPtr<Document> document = frame->document();
1535 if (!document.get())
1538 RefPtr<Node> oldFocusedNode = document->focusedNode();
1540 // Clear the focused node.
1541 document->setFocusedNode(0);
1543 if (!oldFocusedNode.get())
1546 // If a text field has focus, we need to make sure the selection controller
1547 // knows to remove selection from it. Otherwise, the text field is still
1548 // processing keyboard events even though focus has been moved to the page and
1549 // keystrokes get eaten as a result.
1550 if (oldFocusedNode->hasTagName(HTMLNames::textareaTag)
1551 || (oldFocusedNode->hasTagName(HTMLNames::inputTag)
1552 && static_cast<HTMLInputElement*>(oldFocusedNode.get())->isTextField())) {
1553 // Clear the selection.
1554 SelectionController* selection = frame->selection();
1559 void WebViewImpl::scrollFocusedNodeIntoView()
1561 Node* focusedNode = focusedWebCoreNode();
1562 if (focusedNode && focusedNode->isElementNode()) {
1563 Element* elementNode = static_cast<Element*>(focusedNode);
1564 elementNode->scrollIntoViewIfNeeded(true);
1568 double WebViewImpl::zoomLevel()
1573 double WebViewImpl::setZoomLevel(bool textOnly, double zoomLevel)
1575 if (zoomLevel < m_minimumZoomLevel)
1576 m_zoomLevel = m_minimumZoomLevel;
1577 else if (zoomLevel > m_maximumZoomLevel)
1578 m_zoomLevel = m_maximumZoomLevel;
1580 m_zoomLevel = zoomLevel;
1582 Frame* frame = mainFrameImpl()->frame();
1583 WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
1584 if (pluginContainer)
1585 pluginContainer->plugin()->setZoomLevel(m_zoomLevel, textOnly);
1587 double zoomFactor = zoomLevelToZoomFactor(m_zoomLevel);
1589 frame->setPageAndTextZoomFactors(1, zoomFactor);
1591 frame->setPageAndTextZoomFactors(zoomFactor, 1);
1596 void WebViewImpl::zoomLimitsChanged(double minimumZoomLevel,
1597 double maximumZoomLevel)
1599 m_minimumZoomLevel = minimumZoomLevel;
1600 m_maximumZoomLevel = maximumZoomLevel;
1601 m_client->zoomLimitsChanged(m_minimumZoomLevel, m_maximumZoomLevel);
1604 void WebViewImpl::fullFramePluginZoomLevelChanged(double zoomLevel)
1606 if (zoomLevel == m_zoomLevel)
1609 m_zoomLevel = std::max(std::min(zoomLevel, m_maximumZoomLevel), m_minimumZoomLevel);
1610 m_client->zoomLevelChanged();
1613 double WebView::zoomLevelToZoomFactor(double zoomLevel)
1615 return std::pow(textSizeMultiplierRatio, zoomLevel);
1618 double WebView::zoomFactorToZoomLevel(double factor)
1620 // Since factor = 1.2^level, level = log(factor) / log(1.2)
1621 return log(factor) / log(textSizeMultiplierRatio);
1624 void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action,
1625 const WebPoint& location)
1627 HitTestResult result =
1628 hitTestResultForWindowPos(location);
1629 RefPtr<Node> node = result.innerNonSharedNode();
1630 if (!node->hasTagName(HTMLNames::videoTag) && !node->hasTagName(HTMLNames::audioTag))
1633 RefPtr<HTMLMediaElement> mediaElement =
1634 static_pointer_cast<HTMLMediaElement>(node);
1635 switch (action.type) {
1636 case WebMediaPlayerAction::Play:
1638 mediaElement->play(mediaElement->processingUserGesture());
1640 mediaElement->pause(mediaElement->processingUserGesture());
1642 case WebMediaPlayerAction::Mute:
1643 mediaElement->setMuted(action.enable);
1645 case WebMediaPlayerAction::Loop:
1646 mediaElement->setLoop(action.enable);
1648 case WebMediaPlayerAction::Controls:
1649 mediaElement->setControls(action.enable);
1652 ASSERT_NOT_REACHED();
1656 void WebViewImpl::copyImageAt(const WebPoint& point)
1661 HitTestResult result = hitTestResultForWindowPos(point);
1663 if (result.absoluteImageURL().isEmpty()) {
1664 // There isn't actually an image at these coordinates. Might be because
1665 // the window scrolled while the context menu was open or because the page
1666 // changed itself between when we thought there was an image here and when
1667 // we actually tried to retreive the image.
1669 // FIXME: implement a cache of the most recent HitTestResult to avoid having
1670 // to do two hit tests.
1674 m_page->mainFrame()->editor()->copyImage(result);
1677 void WebViewImpl::dragSourceEndedAt(
1678 const WebPoint& clientPoint,
1679 const WebPoint& screenPoint,
1680 WebDragOperation operation)
1682 PlatformMouseEvent pme(clientPoint,
1684 LeftButton, MouseEventMoved, 0, false, false, false,
1686 m_page->mainFrame()->eventHandler()->dragSourceEndedAt(pme,
1687 static_cast<DragOperation>(operation));
1688 m_dragScrollTimer->stop();
1691 void WebViewImpl::dragSourceMovedTo(
1692 const WebPoint& clientPoint,
1693 const WebPoint& screenPoint,
1694 WebDragOperation operation)
1696 m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint);
1699 void WebViewImpl::dragSourceSystemDragEnded()
1701 // It's possible for us to get this callback while not doing a drag if
1702 // it's from a previous page that got unloaded.
1703 if (m_doingDragAndDrop) {
1704 m_page->dragController()->dragEnded();
1705 m_doingDragAndDrop = false;
1709 WebDragOperation WebViewImpl::dragTargetDragEnter(
1710 const WebDragData& webDragData, int identity,
1711 const WebPoint& clientPoint,
1712 const WebPoint& screenPoint,
1713 WebDragOperationsMask operationsAllowed)
1715 ASSERT(!m_currentDragData.get());
1717 m_currentDragData = webDragData;
1718 m_dragIdentity = identity;
1719 m_operationsAllowed = operationsAllowed;
1721 return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragEnter);
1724 WebDragOperation WebViewImpl::dragTargetDragEnterNew(
1726 const WebPoint& clientPoint,
1727 const WebPoint& screenPoint,
1728 WebDragOperationsMask operationsAllowed)
1730 ASSERT(!m_currentDragData.get());
1732 m_currentDragData = ChromiumDataObject::createReadable(Clipboard::DragAndDrop);
1733 m_dragIdentity = identity;
1734 m_operationsAllowed = operationsAllowed;
1736 return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragEnter);
1739 WebDragOperation WebViewImpl::dragTargetDragOver(
1740 const WebPoint& clientPoint,
1741 const WebPoint& screenPoint,
1742 WebDragOperationsMask operationsAllowed)
1744 m_operationsAllowed = operationsAllowed;
1746 return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragOver);
1749 void WebViewImpl::dragTargetDragLeave()
1751 ASSERT(m_currentDragData.get());
1754 m_currentDragData.get(),
1757 static_cast<DragOperation>(m_operationsAllowed));
1759 m_dragTargetDispatch = true;
1760 m_page->dragController()->dragExited(&dragData);
1761 m_dragTargetDispatch = false;
1763 m_currentDragData = 0;
1764 m_dropEffect = DropEffectDefault;
1765 m_dragOperation = WebDragOperationNone;
1769 void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint,
1770 const WebPoint& screenPoint)
1772 ASSERT(m_currentDragData.get());
1774 // If this webview transitions from the "drop accepting" state to the "not
1775 // accepting" state, then our IPC message reply indicating that may be in-
1776 // flight, or else delayed by javascript processing in this webview. If a
1777 // drop happens before our IPC reply has reached the browser process, then
1778 // the browser forwards the drop to this webview. So only allow a drop to
1779 // proceed if our webview m_dragOperation state is not DragOperationNone.
1781 if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop.
1782 dragTargetDragLeave();
1787 m_currentDragData.get(),
1790 static_cast<DragOperation>(m_operationsAllowed));
1792 m_dragTargetDispatch = true;
1793 m_page->dragController()->performDrag(&dragData);
1794 m_dragTargetDispatch = false;
1796 m_currentDragData = 0;
1797 m_dropEffect = DropEffectDefault;
1798 m_dragOperation = WebDragOperationNone;
1800 m_dragScrollTimer->stop();
1803 int WebViewImpl::dragIdentity()
1805 if (m_dragTargetDispatch)
1806 return m_dragIdentity;
1810 WebDragOperation WebViewImpl::dragTargetDragEnterOrOver(const WebPoint& clientPoint, const WebPoint& screenPoint, DragAction dragAction)
1812 ASSERT(m_currentDragData.get());
1815 m_currentDragData.get(),
1818 static_cast<DragOperation>(m_operationsAllowed));
1820 m_dropEffect = DropEffectDefault;
1821 m_dragTargetDispatch = true;
1822 DragOperation effect = dragAction == DragEnter ? m_page->dragController()->dragEntered(&dragData)
1823 : m_page->dragController()->dragUpdated(&dragData);
1824 // Mask the operation against the drag source's allowed operations.
1825 if (!(effect & dragData.draggingSourceOperationMask()))
1826 effect = DragOperationNone;
1827 m_dragTargetDispatch = false;
1829 if (m_dropEffect != DropEffectDefault) {
1830 m_dragOperation = (m_dropEffect != DropEffectNone) ? WebDragOperationCopy
1831 : WebDragOperationNone;
1833 m_dragOperation = static_cast<WebDragOperation>(effect);
1835 if (dragAction == DragOver)
1836 m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint);
1838 m_dragScrollTimer->stop();
1841 return m_dragOperation;
1844 unsigned long WebViewImpl::createUniqueIdentifierForRequest()
1847 return m_page->progress()->createUniqueIdentifier();
1851 void WebViewImpl::inspectElementAt(const WebPoint& point)
1856 if (point.x == -1 || point.y == -1)
1857 m_page->inspectorController()->inspect(0);
1859 HitTestResult result = hitTestResultForWindowPos(point);
1861 if (!result.innerNonSharedNode())
1864 m_page->inspectorController()->inspect(result.innerNonSharedNode());
1868 WebString WebViewImpl::inspectorSettings() const
1870 return m_inspectorSettings;
1873 void WebViewImpl::setInspectorSettings(const WebString& settings)
1875 m_inspectorSettings = settings;
1878 bool WebViewImpl::inspectorSetting(const WebString& key, WebString* value) const
1880 if (!m_inspectorSettingsMap->contains(key))
1882 *value = m_inspectorSettingsMap->get(key);
1886 void WebViewImpl::setInspectorSetting(const WebString& key,
1887 const WebString& value)
1889 m_inspectorSettingsMap->set(key, value);
1890 client()->didUpdateInspectorSetting(key, value);
1893 WebDevToolsAgent* WebViewImpl::devToolsAgent()
1895 return m_devToolsAgent.get();
1898 WebAccessibilityObject WebViewImpl::accessibilityObject()
1900 if (!mainFrameImpl())
1901 return WebAccessibilityObject();
1903 Document* document = mainFrameImpl()->frame()->document();
1904 return WebAccessibilityObject(
1905 document->axObjectCache()->getOrCreate(document->renderer()));
1908 void WebViewImpl::applyAutoFillSuggestions(
1909 const WebNode& node,
1910 const WebVector<WebString>& names,
1911 const WebVector<WebString>& labels,
1912 const WebVector<int>& uniqueIDs,
1915 WebVector<WebString> icons(names.size());
1916 applyAutoFillSuggestions(node, names, labels, icons, uniqueIDs, separatorIndex);
1919 void WebViewImpl::applyAutoFillSuggestions(
1920 const WebNode& node,
1921 const WebVector<WebString>& names,
1922 const WebVector<WebString>& labels,
1923 const WebVector<WebString>& icons,
1924 const WebVector<int>& uniqueIDs,
1927 ASSERT(names.size() == labels.size());
1928 ASSERT(names.size() == uniqueIDs.size());
1929 ASSERT(separatorIndex < static_cast<int>(names.size()));
1931 if (names.isEmpty()) {
1932 hideAutoFillPopup();
1936 RefPtr<Node> focusedNode = focusedWebCoreNode();
1937 // If the node for which we queried the AutoFill suggestions is not the
1938 // focused node, then we have nothing to do. FIXME: also check the
1939 // caret is at the end and that the text has not changed.
1940 if (!focusedNode || focusedNode != PassRefPtr<Node>(node)) {
1941 hideAutoFillPopup();
1945 HTMLInputElement* inputElem =
1946 static_cast<HTMLInputElement*>(focusedNode.get());
1948 // The first time the AutoFill popup is shown we'll create the client and
1950 if (!m_autoFillPopupClient.get())
1951 m_autoFillPopupClient.set(new AutoFillPopupMenuClient);
1953 m_autoFillPopupClient->initialize(
1954 inputElem, names, labels, icons, uniqueIDs, separatorIndex);
1956 if (!m_autoFillPopup.get()) {
1957 m_autoFillPopup = PopupContainer::create(m_autoFillPopupClient.get(),
1958 PopupContainer::Suggestion,
1959 autoFillPopupSettings);
1962 if (m_autoFillPopupShowing) {
1963 refreshAutoFillPopup();
1965 m_autoFillPopup->show(focusedNode->getRect(), focusedNode->ownerDocument()->view(), 0);
1966 m_autoFillPopupShowing = true;
1969 // DEPRECATED: This special mode will go away once AutoFill and Autocomplete
1970 // merge is complete.
1971 if (m_autoFillPopupClient)
1972 m_autoFillPopupClient->setAutocompleteMode(false);
1975 // DEPRECATED: replacing with applyAutoFillSuggestions.
1976 void WebViewImpl::applyAutocompleteSuggestions(
1977 const WebNode& node,
1978 const WebVector<WebString>& suggestions,
1979 int defaultSuggestionIndex)
1981 WebVector<WebString> names(suggestions.size());
1982 WebVector<WebString> labels(suggestions.size());
1983 WebVector<WebString> icons(suggestions.size());
1984 WebVector<int> uniqueIDs(suggestions.size());
1986 for (size_t i = 0; i < suggestions.size(); ++i)
1987 names[i] = suggestions[i];
1989 applyAutoFillSuggestions(node, names, labels, icons, uniqueIDs, -1);
1990 if (m_autoFillPopupClient)
1991 m_autoFillPopupClient->setAutocompleteMode(true);
1994 void WebViewImpl::hidePopups()
1997 hideAutoFillPopup();
2000 void WebViewImpl::performCustomContextMenuAction(unsigned action)
2004 ContextMenu* menu = m_page->contextMenuController()->contextMenu();
2007 ContextMenuItem* item = menu->itemWithAction(static_cast<ContextMenuAction>(ContextMenuItemBaseCustomTag + action));
2009 m_page->contextMenuController()->contextMenuItemSelected(item);
2010 m_page->contextMenuController()->clearContextMenu();
2013 // WebView --------------------------------------------------------------------
2015 bool WebViewImpl::setDropEffect(bool accept)
2017 if (m_dragTargetDispatch) {
2018 m_dropEffect = accept ? DropEffectCopy : DropEffectNone;
2024 void WebViewImpl::setIsTransparent(bool isTransparent)
2026 // Set any existing frames to be transparent.
2027 Frame* frame = m_page->mainFrame();
2029 frame->view()->setTransparent(isTransparent);
2030 frame = frame->tree()->traverseNext();
2033 // Future frames check this to know whether to be transparent.
2034 m_isTransparent = isTransparent;
2037 bool WebViewImpl::isTransparent() const
2039 return m_isTransparent;
2042 void WebViewImpl::setIsActive(bool active)
2044 if (page() && page()->focusController())
2045 page()->focusController()->setActive(active);
2048 bool WebViewImpl::isActive() const
2050 return (page() && page()->focusController()) ? page()->focusController()->isActive() : false;
2053 void WebViewImpl::setDomainRelaxationForbidden(bool forbidden, const WebString& scheme)
2055 SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(forbidden, String(scheme));
2058 void WebViewImpl::setScrollbarColors(unsigned inactiveColor,
2059 unsigned activeColor,
2060 unsigned trackColor) {
2061 #if OS(LINUX) || OS(FREEBSD)
2062 PlatformThemeChromiumGtk::setScrollbarColors(inactiveColor,
2068 void WebViewImpl::setSelectionColors(unsigned activeBackgroundColor,
2069 unsigned activeForegroundColor,
2070 unsigned inactiveBackgroundColor,
2071 unsigned inactiveForegroundColor) {
2072 #if OS(LINUX) || OS(FREEBSD)
2073 RenderThemeChromiumLinux::setSelectionColors(activeBackgroundColor,
2074 activeForegroundColor,
2075 inactiveBackgroundColor,
2076 inactiveForegroundColor);
2077 theme()->platformColorsDidChange();
2081 void WebView::addUserScript(const WebString& sourceCode,
2082 const WebVector<WebString>& patternsIn,
2083 WebView::UserScriptInjectAt injectAt,
2084 WebView::UserContentInjectIn injectIn)
2086 OwnPtr<Vector<String> > patterns(new Vector<String>);
2087 for (size_t i = 0; i < patternsIn.size(); ++i)
2088 patterns->append(patternsIn[i]);
2090 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
2091 RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create());
2092 pageGroup->addUserScriptToWorld(world.get(), sourceCode, WebURL(), patterns.release(), 0,
2093 static_cast<UserScriptInjectionTime>(injectAt),
2094 static_cast<UserContentInjectedFrames>(injectIn));
2097 void WebView::addUserStyleSheet(const WebString& sourceCode,
2098 const WebVector<WebString>& patternsIn,
2099 WebView::UserContentInjectIn injectIn,
2100 WebView::UserStyleInjectionTime injectionTime)
2102 OwnPtr<Vector<String> > patterns(new Vector<String>);
2103 for (size_t i = 0; i < patternsIn.size(); ++i)
2104 patterns->append(patternsIn[i]);
2106 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
2107 RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create());
2109 // FIXME: Current callers always want the level to be "author". It probably makes sense to let
2110 // callers specify this though, since in other cases the caller will probably want "user" level.
2112 // FIXME: It would be nice to populate the URL correctly, instead of passing an empty URL.
2113 pageGroup->addUserStyleSheetToWorld(world.get(), sourceCode, WebURL(), patterns.release(), 0,
2114 static_cast<UserContentInjectedFrames>(injectIn),
2115 UserStyleAuthorLevel,
2116 static_cast<WebCore::UserStyleInjectionTime>(injectionTime));
2119 void WebView::removeAllUserContent()
2121 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
2122 pageGroup->removeAllUserContent();
2125 void WebViewImpl::didCommitLoad(bool* isNewNavigation)
2127 if (isNewNavigation)
2128 *isNewNavigation = m_observedNewNavigation;
2131 ASSERT(!m_observedNewNavigation
2132 || m_page->mainFrame()->loader()->documentLoader() == m_newNavigationLoader);
2133 m_newNavigationLoader = 0;
2135 m_observedNewNavigation = false;
2138 bool WebViewImpl::useExternalPopupMenus()
2140 return shouldUseExternalPopupMenus;
2143 bool WebViewImpl::navigationPolicyFromMouseEvent(unsigned short button,
2144 bool ctrl, bool shift,
2145 bool alt, bool meta,
2146 WebNavigationPolicy* policy)
2148 #if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD) || OS(SOLARIS)
2149 const bool newTabModifier = (button == 1) || ctrl;
2151 const bool newTabModifier = (button == 1) || meta;
2153 if (!newTabModifier && !shift && !alt)
2157 if (newTabModifier) {
2159 *policy = WebNavigationPolicyNewForegroundTab;
2161 *policy = WebNavigationPolicyNewBackgroundTab;
2164 *policy = WebNavigationPolicyNewWindow;
2166 *policy = WebNavigationPolicyDownload;
2171 void WebViewImpl::startDragging(const WebDragData& dragData,
2172 WebDragOperationsMask mask,
2173 const WebImage& dragImage,
2174 const WebPoint& dragImageOffset)
2178 ASSERT(!m_doingDragAndDrop);
2179 m_doingDragAndDrop = true;
2180 m_client->startDragging(dragData, mask, dragImage, dragImageOffset);
2183 void WebViewImpl::setCurrentHistoryItem(HistoryItem* item)
2185 m_backForwardListClientImpl.setCurrentHistoryItem(item);
2188 HistoryItem* WebViewImpl::previousHistoryItem()
2190 return m_backForwardListClientImpl.previousHistoryItem();
2193 void WebViewImpl::observeNewNavigation()
2195 m_observedNewNavigation = true;
2197 m_newNavigationLoader = m_page->mainFrame()->loader()->documentLoader();
2201 void WebViewImpl::setIgnoreInputEvents(bool newValue)
2203 ASSERT(m_ignoreInputEvents != newValue);
2204 m_ignoreInputEvents = newValue;
2207 #if ENABLE(NOTIFICATIONS)
2208 NotificationPresenterImpl* WebViewImpl::notificationPresenterImpl()
2210 if (!m_notificationPresenter.isInitialized() && m_client)
2211 m_notificationPresenter.initialize(m_client->notificationPresenter());
2212 return &m_notificationPresenter;
2216 void WebViewImpl::refreshAutoFillPopup()
2218 ASSERT(m_autoFillPopupShowing);
2220 // Hide the popup if it has become empty.
2221 if (!m_autoFillPopupClient->listSize()) {
2222 hideAutoFillPopup();
2226 IntRect oldBounds = m_autoFillPopup->boundsRect();
2227 m_autoFillPopup->refresh();
2228 IntRect newBounds = m_autoFillPopup->boundsRect();
2229 // Let's resize the backing window if necessary.
2230 if (oldBounds != newBounds) {
2231 WebPopupMenuImpl* popupMenu =
2232 static_cast<WebPopupMenuImpl*>(m_autoFillPopup->client());
2234 popupMenu->client()->setWindowRect(newBounds);
2238 Node* WebViewImpl::focusedWebCoreNode()
2240 Frame* frame = m_page->focusController()->focusedFrame();
2244 Document* document = frame->document();
2248 return document->focusedNode();
2251 HitTestResult WebViewImpl::hitTestResultForWindowPos(const IntPoint& pos)
2253 IntPoint docPoint(m_page->mainFrame()->view()->windowToContents(pos));
2254 return m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(docPoint, false);
2257 void WebViewImpl::setTabsToLinks(bool enable)
2259 m_tabsToLinks = enable;
2262 bool WebViewImpl::tabsToLinks() const
2264 return m_tabsToLinks;
2267 #if USE(ACCELERATED_COMPOSITING)
2268 bool WebViewImpl::allowsAcceleratedCompositing()
2270 return !m_compositorCreationFailed;
2273 void WebViewImpl::setRootGraphicsLayer(WebCore::PlatformLayer* layer)
2275 bool wasActive = m_isAcceleratedCompositingActive;
2276 setIsAcceleratedCompositingActive(layer ? true : false);
2277 if (m_layerRenderer)
2278 m_layerRenderer->setRootLayer(layer);
2279 if (wasActive != m_isAcceleratedCompositingActive) {
2280 IntRect damagedRect(0, 0, m_size.width, m_size.height);
2281 if (m_isAcceleratedCompositingActive)
2282 invalidateRootLayerRect(damagedRect);
2284 m_client->didInvalidateRect(damagedRect);
2288 void WebViewImpl::setRootLayerNeedsDisplay()
2290 m_client->scheduleComposite();
2294 void WebViewImpl::scrollRootLayerRect(const IntSize& scrollDelta, const IntRect& clipRect)
2296 ASSERT(m_layerRenderer);
2297 // Compute the damage rect in viewport space.
2298 WebFrameImpl* webframe = mainFrameImpl();
2301 FrameView* view = webframe->frameView();
2305 IntRect contentRect = view->visibleContentRect(false);
2306 IntRect screenRect = view->contentsToWindow(contentRect);
2308 // We support fast scrolling in one direction at a time.
2309 if (scrollDelta.width() && scrollDelta.height()) {
2310 invalidateRootLayerRect(WebRect(screenRect));
2314 // Compute the region we will expose by scrolling. We use the
2315 // content rect for invalidation. Using this space for damage
2316 // rects allows us to intermix invalidates with scrolls.
2317 IntRect damagedContentsRect;
2318 if (scrollDelta.width()) {
2319 int dx = scrollDelta.width();
2320 damagedContentsRect.setY(screenRect.y());
2321 damagedContentsRect.setHeight(screenRect.height());
2323 damagedContentsRect.setX(screenRect.x());
2324 damagedContentsRect.setWidth(dx);
2326 damagedContentsRect.setX(screenRect.right() + dx);
2327 damagedContentsRect.setWidth(-dx);
2330 int dy = scrollDelta.height();
2331 damagedContentsRect.setX(screenRect.x());
2332 damagedContentsRect.setWidth(screenRect.width());
2334 damagedContentsRect.setY(screenRect.y());
2335 damagedContentsRect.setHeight(dy);
2337 damagedContentsRect.setY(screenRect.bottom() + dy);
2338 damagedContentsRect.setHeight(-dy);
2342 // Move the previous damage
2343 m_rootLayerScrollDamage.move(scrollDelta.width(), scrollDelta.height());
2344 // Union with the new damage rect.
2345 m_rootLayerScrollDamage.unite(damagedContentsRect);
2347 // Scroll any existing damage that intersects with clip rect
2348 if (clipRect.intersects(m_rootLayerDirtyRect)) {
2349 // Find the inner damage
2350 IntRect innerDamage(clipRect);
2351 innerDamage.intersect(m_rootLayerDirtyRect);
2354 innerDamage.move(scrollDelta.width(), scrollDelta.height());
2356 // Merge it back into the damaged rect
2357 m_rootLayerDirtyRect.unite(innerDamage);
2360 setRootLayerNeedsDisplay();
2363 void WebViewImpl::invalidateRootLayerRect(const IntRect& rect)
2365 ASSERT(m_layerRenderer);
2370 // FIXME: add a smarter damage aggregation logic and/or unify with
2371 // LayerChromium's damage logic
2372 m_rootLayerDirtyRect.unite(rect);
2373 setRootLayerNeedsDisplay();
2377 void WebViewImpl::setIsAcceleratedCompositingActive(bool active)
2379 if (m_isAcceleratedCompositingActive == active)
2383 m_isAcceleratedCompositingActive = false;
2384 m_layerRenderer->finish(); // finish all GL rendering before we hide the window?
2385 m_client->didActivateAcceleratedCompositing(false);
2389 if (m_layerRenderer) {
2390 m_isAcceleratedCompositingActive = true;
2391 m_layerRenderer->resizeOnscreenContent(WebCore::IntSize(std::max(1, m_size.width),
2392 std::max(1, m_size.height)));
2394 m_client->didActivateAcceleratedCompositing(true);
2398 RefPtr<GraphicsContext3D> context = m_temporaryOnscreenGraphicsContext3D.release();
2400 context = GraphicsContext3D::create(getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow);
2402 context->reshape(std::max(1, m_size.width), std::max(1, m_size.height));
2404 m_layerRenderer = LayerRendererChromium::create(context.release());
2405 if (m_layerRenderer) {
2406 m_client->didActivateAcceleratedCompositing(true);
2407 m_isAcceleratedCompositingActive = true;
2408 m_compositorCreationFailed = false;
2410 m_isAcceleratedCompositingActive = false;
2411 m_client->didActivateAcceleratedCompositing(false);
2412 m_compositorCreationFailed = true;
2416 void WebViewImpl::updateRootLayerContents(const IntRect& rect)
2418 if (!isAcceleratedCompositingActive())
2421 WebFrameImpl* webframe = mainFrameImpl();
2424 FrameView* view = webframe->frameView();
2428 LayerChromium* rootLayer = m_layerRenderer->rootLayer();
2430 IntRect visibleRect = view->visibleContentRect(true);
2432 m_layerRenderer->setRootLayerCanvasSize(IntSize(rect.width(), rect.height()));
2433 GraphicsContext* rootLayerContext = m_layerRenderer->rootLayerGraphicsContext();
2436 PlatformContextSkia* skiaContext = rootLayerContext->platformContext();
2437 skia::PlatformCanvas* platformCanvas = skiaContext->canvas();
2439 platformCanvas->save();
2441 // Bring the canvas into the coordinate system of the paint rect.
2442 platformCanvas->translate(static_cast<SkScalar>(-rect.x()), static_cast<SkScalar>(-rect.y()));
2444 rootLayerContext->save();
2446 webframe->paintWithContext(*rootLayerContext, rect);
2447 rootLayerContext->restore();
2449 platformCanvas->restore();
2451 CGContextRef cgContext = rootLayerContext->platformContext();
2453 CGContextSaveGState(cgContext);
2455 // Bring the CoreGraphics context into the coordinate system of the paint rect.
2456 CGContextTranslateCTM(cgContext, -rect.x(), -rect.y());
2458 rootLayerContext->save();
2460 webframe->paintWithContext(*rootLayerContext, rect);
2461 rootLayerContext->restore();
2463 CGContextRestoreGState(cgContext);
2465 #error Must port to your platform
2470 void WebViewImpl::doComposite()
2472 ASSERT(isAcceleratedCompositingActive());
2475 FrameView* view = page()->mainFrame()->view();
2477 // The visibleRect includes scrollbars whereas the contentRect doesn't.
2478 IntRect visibleRect = view->visibleContentRect(true);
2479 IntRect contentRect = view->visibleContentRect(false);
2480 IntRect viewPort = IntRect(0, 0, m_size.width, m_size.height);
2482 // Give the compositor a chance to setup/resize the root texture handle and perform scrolling.
2483 m_layerRenderer->prepareToDrawLayers(visibleRect, contentRect, IntPoint(view->scrollX(), view->scrollY()));
2485 // Draw the contents of the root layer.
2486 Vector<IntRect> damageRects;
2487 damageRects.append(m_rootLayerScrollDamage);
2488 damageRects.append(m_rootLayerDirtyRect);
2489 for (size_t i = 0; i < damageRects.size(); ++i) {
2490 IntRect damagedRect = damageRects[i];
2492 // Intersect this rectangle with the viewPort.
2493 damagedRect.intersect(viewPort);
2496 if (damagedRect.width() && damagedRect.height()) {
2497 updateRootLayerContents(damagedRect);
2498 m_layerRenderer->updateRootLayerTextureRect(damagedRect);
2501 m_rootLayerDirtyRect = IntRect();
2502 m_rootLayerScrollDamage = IntRect();
2504 // Draw the actual layers...
2505 m_layerRenderer->drawLayers(visibleRect, contentRect);
2508 void WebViewImpl::reallocateRenderer()
2510 GraphicsContext3D* context = m_layerRenderer->context();
2511 RefPtr<GraphicsContext3D> newContext = GraphicsContext3D::create(context->getContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow);
2512 // GraphicsContext3D::create might fail and return 0, in that case LayerRendererChromium::create will also return 0.
2513 RefPtr<LayerRendererChromium> layerRenderer = LayerRendererChromium::create(newContext);
2515 // Reattach the root layer. Child layers will get reattached as a side effect of updateLayersRecursive.
2517 m_layerRenderer->transferRootLayer(layerRenderer.get());
2518 m_layerRenderer = layerRenderer;
2520 // Enable or disable accelerated compositing and request a refresh.
2521 m_isAcceleratedCompositingActive = false;
2522 setRootGraphicsLayer(m_layerRenderer ? m_layerRenderer->rootLayer() : 0);
2527 WebGraphicsContext3D* WebViewImpl::graphicsContext3D()
2529 #if USE(ACCELERATED_COMPOSITING)
2530 if (m_page->settings()->acceleratedCompositingEnabled() && allowsAcceleratedCompositing()) {
2531 GraphicsContext3D* context = 0;
2532 if (m_layerRenderer)
2533 context = m_layerRenderer->context();
2534 else if (m_temporaryOnscreenGraphicsContext3D)
2535 context = m_temporaryOnscreenGraphicsContext3D.get();
2537 m_temporaryOnscreenGraphicsContext3D = GraphicsContext3D::create(getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow);
2538 if (m_temporaryOnscreenGraphicsContext3D)
2539 m_temporaryOnscreenGraphicsContext3D->reshape(std::max(1, m_size.width), std::max(1, m_size.height));
2540 context = m_temporaryOnscreenGraphicsContext3D.get();
2542 return GraphicsContext3DInternal::extractWebGraphicsContext3D(context);
2548 } // namespace WebKit