2 * Copyright (C) 2009 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 "AutocompletePopupMenuClient.h"
35 #include "AXObjectCache.h"
36 #include "ContextMenu.h"
37 #include "ContextMenuController.h"
38 #include "ContextMenuItem.h"
39 #include "CSSStyleSelector.h"
40 #include "CSSValueKeywords.h"
43 #include "DocumentLoader.h"
44 #include "DOMUtilitiesPrivate.h"
45 #include "DragController.h"
48 #include "EventHandler.h"
49 #include "FocusController.h"
50 #include "FontDescription.h"
51 #include "FrameLoader.h"
52 #include "FrameTree.h"
53 #include "FrameView.h"
54 #include "GraphicsContext.h"
55 #include "HitTestResult.h"
56 #include "HTMLInputElement.h"
57 #include "HTMLMediaElement.h"
58 #include "HTMLNames.h"
60 #include "InspectorController.h"
62 #include "KeyboardCodes.h"
63 #include "KeyboardEvent.h"
64 #include "MIMETypeRegistry.h"
65 #include "NodeRenderStyle.h"
67 #include "PageGroup.h"
68 #include "Pasteboard.h"
69 #include "PlatformContextSkia.h"
70 #include "PlatformKeyboardEvent.h"
71 #include "PlatformMouseEvent.h"
72 #include "PlatformWheelEvent.h"
73 #include "PluginInfoStore.h"
74 #include "PopupMenuChromium.h"
75 #include "PopupMenuClient.h"
76 #include "ProgressTracker.h"
77 #include "RenderView.h"
78 #include "ResourceHandle.h"
79 #include "SecurityOrigin.h"
80 #include "SelectionController.h"
82 #include "TypingCommand.h"
83 #include "WebAccessibilityObject.h"
84 #include "WebDevToolsAgentPrivate.h"
85 #include "WebDragData.h"
86 #include "WebFrameImpl.h"
87 #include "WebInputEvent.h"
88 #include "WebInputEventConversion.h"
89 #include "WebMediaPlayerAction.h"
92 #include "WebPopupMenuImpl.h"
94 #include "WebSettingsImpl.h"
95 #include "WebString.h"
96 #include "WebVector.h"
97 #include "WebViewClient.h"
100 #include "KeyboardCodesWin.h"
101 #include "RenderThemeChromiumWin.h"
104 #include "RenderThemeChromiumLinux.h"
106 #include "KeyboardCodesPosix.h"
107 #include "RenderTheme.h"
110 // Get rid of WTF's pow define so we can use std::pow.
112 #include <cmath> // for std::pow
114 using namespace WebCore
;
118 // Change the text zoom level by kTextSizeMultiplierRatio each time the user
119 // zooms text in or out (ie., change by 20%). The min and max values limit
120 // text zoom to half and 3x the original text size. These three values match
121 // those in Apple's port in WebKit/WebKit/WebView/WebView.mm
122 static const double textSizeMultiplierRatio
= 1.2;
123 static const double minTextSizeMultiplier
= 0.5;
124 static const double maxTextSizeMultiplier
= 3.0;
126 // The group name identifies a namespace of pages. Page group is used on OSX
127 // for some programs that use HTML views to display things that don't seem like
128 // web pages to the user (so shouldn't have visited link coloring). We only use
130 const char* pageGroupName
= "default";
132 // Ensure that the WebDragOperation enum values stay in sync with the original
133 // DragOperation constants.
134 #define COMPILE_ASSERT_MATCHING_ENUM(coreName) \
135 COMPILE_ASSERT(int(coreName) == int(Web##coreName), dummy##coreName)
136 COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone
);
137 COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy
);
138 COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink
);
139 COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric
);
140 COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate
);
141 COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove
);
142 COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete
);
143 COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery
);
145 // Note that focusOnShow is false so that the autocomplete popup is shown not
146 // activated. We need the page to still have focus so the user can keep typing
147 // while the popup is showing.
148 static const PopupContainerSettings autocompletePopupSettings
= {
149 false, // focusOnShow
150 false, // setTextOnIndexChange
151 false, // acceptOnAbandon
152 true, // loopSelectionNavigation
153 true, // restrictWidthOfListBox. Same as other browser (Fx, IE, and safari)
154 // For autocomplete, we use the direction of the input field as the direction
155 // of the popup items. The main reason is to keep the display of items in
156 // drop-down the same as the items in the input field.
157 PopupContainerSettings::DOMElementDirection
,
160 // WebView ----------------------------------------------------------------
162 WebView
* WebView::create(WebViewClient
* client
)
164 return new WebViewImpl(client
);
167 void WebView::updateVisitedLinkState(unsigned long long linkHash
)
169 Page::visitedStateChanged(PageGroup::pageGroup(pageGroupName
), linkHash
);
172 void WebView::resetVisitedLinkState()
174 Page::allVisitedStateChanged(PageGroup::pageGroup(pageGroupName
));
177 void WebViewImpl::initializeMainFrame(WebFrameClient
* frameClient
)
179 // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame
180 // and releases that reference once the corresponding Frame is destroyed.
181 RefPtr
<WebFrameImpl
> frame
= WebFrameImpl::create(frameClient
);
183 frame
->initializeAsMainFrame(this);
185 // Restrict the access to the local file system
186 // (see WebView.mm WebView::_commonInitializationWithFrameName).
187 SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForLocalOnly
);
190 WebViewImpl::WebViewImpl(WebViewClient
* client
)
192 , m_backForwardListClientImpl(this)
193 , m_chromeClientImpl(this)
194 , m_contextMenuClientImpl(this)
195 , m_dragClientImpl(this)
196 , m_editorClientImpl(this)
197 , m_inspectorClientImpl(this)
198 , m_observedNewNavigation(false)
200 , m_newNavigationLoader(0)
203 , m_contextMenuAllowed(false)
204 , m_doingDragAndDrop(false)
205 , m_ignoreInputEvents(false)
206 , m_suppressNextKeypressEvent(false)
207 , m_initialNavigationPolicy(WebNavigationPolicyIgnore
)
208 , m_imeAcceptEvents(true)
209 , m_dragTargetDispatch(false)
211 , m_dropEffect(DropEffectDefault
)
212 , m_operationsAllowed(WebDragOperationNone
)
213 , m_dragOperation(WebDragOperationNone
)
214 , m_autocompletePopupShowing(false)
215 , m_isTransparent(false)
216 , m_tabsToLinks(false)
218 // WebKit/win/WebView.cpp does the same thing, except they call the
219 // KJS specific wrapper around this method. We need to have threading
220 // initialized because CollatorICU requires it.
221 WTF::initializeThreading();
223 // set to impossible point so we always get the first mouse pos
224 m_lastMousePosition
= WebPoint(-1, -1);
226 // the page will take ownership of the various clients
227 m_page
.set(new Page(&m_chromeClientImpl
,
228 &m_contextMenuClientImpl
,
231 &m_inspectorClientImpl
,
235 m_page
->backForwardList()->setClient(&m_backForwardListClientImpl
);
236 m_page
->setGroupName(pageGroupName
);
239 WebViewImpl::~WebViewImpl()
244 RenderTheme
* WebViewImpl::theme() const
246 return m_page
.get() ? m_page
->theme() : RenderTheme::defaultTheme().get();
249 WebFrameImpl
* WebViewImpl::mainFrameImpl()
251 return m_page
.get() ? WebFrameImpl::fromFrame(m_page
->mainFrame()) : 0;
254 bool WebViewImpl::tabKeyCyclesThroughElements() const
256 ASSERT(m_page
.get());
257 return m_page
->tabKeyCyclesThroughElements();
260 void WebViewImpl::setTabKeyCyclesThroughElements(bool value
)
263 m_page
->setTabKeyCyclesThroughElements(value
);
266 void WebViewImpl::mouseMove(const WebMouseEvent
& event
)
268 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
271 m_lastMousePosition
= WebPoint(event
.x
, event
.y
);
273 // We call mouseMoved here instead of handleMouseMovedEvent because we need
274 // our ChromeClientImpl to receive changes to the mouse position and
275 // tooltip text, and mouseMoved handles all of that.
276 mainFrameImpl()->frame()->eventHandler()->mouseMoved(
277 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event
));
280 void WebViewImpl::mouseLeave(const WebMouseEvent
& event
)
282 // This event gets sent as the main frame is closing. In that case, just
284 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
287 m_client
->setMouseOverURL(WebURL());
289 mainFrameImpl()->frame()->eventHandler()->handleMouseMoveEvent(
290 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event
));
293 void WebViewImpl::mouseDown(const WebMouseEvent
& event
)
295 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
298 m_lastMouseDownPoint
= WebPoint(event
.x
, event
.y
);
300 // If a text field that has focus is clicked again, we should display the
301 // autocomplete popup.
302 RefPtr
<Node
> clickedNode
;
303 if (event
.button
== WebMouseEvent::ButtonLeft
) {
304 RefPtr
<Node
> focusedNode
= focusedWebCoreNode();
305 if (focusedNode
.get() && toHTMLInputElement(focusedNode
.get())) {
306 IntPoint
point(event
.x
, event
.y
);
307 point
= m_page
->mainFrame()->view()->windowToContents(point
);
308 HitTestResult
result(point
);
309 result
= m_page
->mainFrame()->eventHandler()->hitTestResultAtPoint(point
, false);
310 if (result
.innerNonSharedNode() == focusedNode
) {
311 // Already focused text field was clicked, let's remember this. If
312 // focus has not changed after the mouse event is processed, we'll
313 // trigger the autocomplete.
314 clickedNode
= focusedNode
;
319 mainFrameImpl()->frame()->eventHandler()->handleMousePressEvent(
320 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event
));
322 if (clickedNode
.get() && clickedNode
== focusedWebCoreNode()) {
323 // Focus has not changed, show the autocomplete popup.
324 static_cast<EditorClientImpl
*>(m_page
->editorClient())->
325 showFormAutofillForNode(clickedNode
.get());
328 // Dispatch the contextmenu event regardless of if the click was swallowed.
329 // On Windows, we handle it on mouse up, not down.
331 if (event
.button
== WebMouseEvent::ButtonRight
332 || (event
.button
== WebMouseEvent::ButtonLeft
333 && event
.modifiers
& WebMouseEvent::ControlKey
))
334 mouseContextMenu(event
);
335 #elif PLATFORM(LINUX)
336 if (event
.button
== WebMouseEvent::ButtonRight
)
337 mouseContextMenu(event
);
341 void WebViewImpl::mouseContextMenu(const WebMouseEvent
& event
)
343 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
346 m_page
->contextMenuController()->clearContextMenu();
348 PlatformMouseEventBuilder
pme(mainFrameImpl()->frameView(), event
);
350 // Find the right target frame. See issue 1186900.
351 HitTestResult result
= hitTestResultForWindowPos(pme
.pos());
353 if (result
.innerNonSharedNode())
354 targetFrame
= result
.innerNonSharedNode()->document()->frame();
356 targetFrame
= m_page
->focusController()->focusedOrMainFrame();
359 targetFrame
->view()->setCursor(pointerCursor());
362 m_contextMenuAllowed
= true;
363 targetFrame
->eventHandler()->sendContextMenuEvent(pme
);
364 m_contextMenuAllowed
= false;
365 // Actually showing the context menu is handled by the ContextMenuClient
369 void WebViewImpl::mouseUp(const WebMouseEvent
& event
)
371 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
375 // If the event was a middle click, attempt to copy text into the focused
376 // frame. We execute this before we let the page have a go at the event
377 // because the page may change what is focused during in its event handler.
379 // This code is in the mouse up handler. There is some debate about putting
380 // this here, as opposed to the mouse down handler.
381 // xterm: pastes on up.
382 // GTK: pastes on down.
383 // Firefox: pastes on up.
384 // Midori: couldn't paste at all with 0.1.2
386 // There is something of a webcompat angle to this well, as highlighted by
387 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
388 // down then the text is pasted just before the onclick handler runs and
389 // clears the text box. So it's important this happens after the
390 // handleMouseReleaseEvent() earlier in this function
391 if (event
.button
== WebMouseEvent::ButtonMiddle
) {
392 Frame
* focused
= focusedWebCoreFrame();
393 IntPoint
clickPoint(m_lastMouseDownPoint
.x
, m_lastMouseDownPoint
.y
);
394 clickPoint
= m_page
->mainFrame()->view()->windowToContents(clickPoint
);
395 HitTestResult hitTestResult
=
396 focused
->eventHandler()->hitTestResultAtPoint(clickPoint
, false, false,
397 ShouldHitTestScrollbars
);
398 // We don't want to send a paste when middle clicking a scroll bar or a
399 // link (which will navigate later in the code).
400 if (!hitTestResult
.scrollbar() && !hitTestResult
.isLiveLink() && focused
) {
401 Editor
* editor
= focused
->editor();
402 Pasteboard
* pasteboard
= Pasteboard::generalPasteboard();
403 bool oldSelectionMode
= pasteboard
->isSelectionMode();
404 pasteboard
->setSelectionMode(true);
405 editor
->command(AtomicString("Paste")).execute();
406 pasteboard
->setSelectionMode(oldSelectionMode
);
412 mainFrameImpl()->frame()->eventHandler()->handleMouseReleaseEvent(
413 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event
));
416 // Dispatch the contextmenu event regardless of if the click was swallowed.
417 // On Mac/Linux, we handle it on mouse down, not up.
418 if (event
.button
== WebMouseEvent::ButtonRight
)
419 mouseContextMenu(event
);
423 void WebViewImpl::mouseWheel(const WebMouseWheelEvent
& event
)
425 PlatformWheelEventBuilder
platformEvent(mainFrameImpl()->frameView(), event
);
426 mainFrameImpl()->frame()->eventHandler()->handleWheelEvent(platformEvent
);
429 bool WebViewImpl::keyEvent(const WebKeyboardEvent
& event
)
431 ASSERT((event
.type
== WebInputEvent::RawKeyDown
)
432 || (event
.type
== WebInputEvent::KeyDown
)
433 || (event
.type
== WebInputEvent::KeyUp
));
435 // Please refer to the comments explaining the m_suppressNextKeypressEvent
437 // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
438 // Webkit. A keyDown event is typically associated with a keyPress(char)
439 // event and a keyUp event. We reset this flag here as this is a new keyDown
441 m_suppressNextKeypressEvent
= false;
443 // Give autocomplete a chance to consume the key events it is interested in.
444 if (autocompleteHandleKeyEvent(event
))
447 Frame
* frame
= focusedWebCoreFrame();
451 EventHandler
* handler
= frame
->eventHandler();
453 return keyEventDefault(event
);
455 #if PLATFORM(WIN_OS) || PLATFORM(LINUX)
456 const WebInputEvent::Type contextMenuTriggeringEventType
=
458 WebInputEvent::KeyUp
;
459 #elif PLATFORM(LINUX)
460 WebInputEvent::RawKeyDown
;
463 if (((!event
.modifiers
&& (event
.windowsKeyCode
== VKEY_APPS
))
464 || ((event
.modifiers
== WebInputEvent::ShiftKey
) && (event
.windowsKeyCode
== VKEY_F10
)))
465 && event
.type
== contextMenuTriggeringEventType
) {
466 sendContextMenuEvent(event
);
471 // It's not clear if we should continue after detecting a capslock keypress.
472 // I'll err on the side of continuing, which is the pre-existing behaviour.
473 if (event
.windowsKeyCode
== VKEY_CAPITAL
)
474 handler
->capsLockStateMayHaveChanged();
476 PlatformKeyboardEventBuilder
evt(event
);
478 if (handler
->keyEvent(evt
)) {
479 if (WebInputEvent::RawKeyDown
== event
.type
)
480 m_suppressNextKeypressEvent
= true;
484 return keyEventDefault(event
);
487 bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent
& event
)
489 if (!m_autocompletePopupShowing
490 // Home and End should be left to the text field to process.
491 || event
.windowsKeyCode
== VKEY_HOME
492 || event
.windowsKeyCode
== VKEY_END
)
495 // Pressing delete triggers the removal of the selected suggestion from the DB.
496 if (event
.windowsKeyCode
== VKEY_DELETE
497 && m_autocompletePopup
->selectedIndex() != -1) {
498 Node
* node
= focusedWebCoreNode();
499 if (!node
|| (node
->nodeType() != Node::ELEMENT_NODE
)) {
500 ASSERT_NOT_REACHED();
503 Element
* element
= static_cast<Element
*>(node
);
504 if (!element
->hasLocalName(HTMLNames::inputTag
)) {
505 ASSERT_NOT_REACHED();
509 int selectedIndex
= m_autocompletePopup
->selectedIndex();
510 HTMLInputElement
* inputElement
= static_cast<HTMLInputElement
*>(element
);
511 WebString name
= inputElement
->name();
512 WebString value
= m_autocompletePopupClient
->itemText(selectedIndex
);
513 m_client
->removeAutofillSuggestions(name
, value
);
514 // Update the entries in the currently showing popup to reflect the
516 m_autocompletePopupClient
->removeItemAtIndex(selectedIndex
);
517 refreshAutofillPopup();
521 if (!m_autocompletePopup
->isInterestedInEventForKey(event
.windowsKeyCode
))
524 if (m_autocompletePopup
->handleKeyEvent(PlatformKeyboardEventBuilder(event
))) {
525 // We need to ignore the next Char event after this otherwise pressing
526 // enter when selecting an item in the menu will go to the page.
527 if (WebInputEvent::RawKeyDown
== event
.type
)
528 m_suppressNextKeypressEvent
= true;
535 bool WebViewImpl::charEvent(const WebKeyboardEvent
& event
)
537 ASSERT(event
.type
== WebInputEvent::Char
);
539 // Please refer to the comments explaining the m_suppressNextKeypressEvent
540 // member. The m_suppressNextKeypressEvent is set if the KeyDown is
541 // handled by Webkit. A keyDown event is typically associated with a
542 // keyPress(char) event and a keyUp event. We reset this flag here as it
543 // only applies to the current keyPress event.
544 bool suppress
= m_suppressNextKeypressEvent
;
545 m_suppressNextKeypressEvent
= false;
547 Frame
* frame
= focusedWebCoreFrame();
551 EventHandler
* handler
= frame
->eventHandler();
553 return suppress
|| keyEventDefault(event
);
555 PlatformKeyboardEventBuilder
evt(event
);
556 if (!evt
.isCharacterKey())
559 // Accesskeys are triggered by char events and can't be suppressed.
560 if (handler
->handleAccessKey(evt
))
563 // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
564 // the eventHandler::keyEvent. We mimic this behavior on all platforms since
565 // for now we are converting other platform's key events to windows key
567 if (evt
.isSystemKey())
570 if (!suppress
&& !handler
->keyEvent(evt
))
571 return keyEventDefault(event
);
576 // The WebViewImpl::SendContextMenuEvent function is based on the Webkit
578 // bool WebView::handleContextMenuEvent(WPARAM wParam, LPARAM lParam) in
579 // webkit\webkit\win\WebView.cpp. The only significant change in this
580 // function is the code to convert from a Keyboard event to the Right
581 // Mouse button up event.
583 // This function is an ugly copy/paste and should be cleaned up when the
584 // WebKitWin version is cleaned: https://bugs.webkit.org/show_bug.cgi?id=20438
585 #if PLATFORM(WIN_OS) || PLATFORM(LINUX)
586 // FIXME: implement on Mac
587 bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent
& event
)
589 static const int kContextMenuMargin
= 1;
590 Frame
* mainFrameImpl
= page()->mainFrame();
591 FrameView
* view
= mainFrameImpl
->view();
595 IntPoint
coords(-1, -1);
597 int rightAligned
= ::GetSystemMetrics(SM_MENUDROPALIGNMENT
);
599 int rightAligned
= 0;
604 Frame
* focusedFrame
= page()->focusController()->focusedOrMainFrame();
605 Node
* focusedNode
= focusedFrame
->document()->focusedNode();
606 Position start
= mainFrameImpl
->selection()->selection().start();
608 if (focusedFrame
->editor() && focusedFrame
->editor()->canEdit() && start
.node()) {
609 RenderObject
* renderer
= start
.node()->renderer();
613 RefPtr
<Range
> selection
= mainFrameImpl
->selection()->toNormalizedRange();
614 IntRect firstRect
= mainFrameImpl
->firstRectForRange(selection
.get());
616 int x
= rightAligned
? firstRect
.right() : firstRect
.x();
617 location
= IntPoint(x
, firstRect
.bottom());
618 } else if (focusedNode
)
619 location
= focusedNode
->getRect().bottomLeft();
622 rightAligned
? view
->contentsWidth() - kContextMenuMargin
: kContextMenuMargin
,
626 location
= view
->contentsToWindow(location
);
627 // FIXME: The IntSize(0, -1) is a hack to get the hit-testing to result in
628 // the selected element. Ideally we'd have the position of a context menu
629 // event be separate from its target node.
630 coords
= location
+ IntSize(0, -1);
632 // The contextMenuController() holds onto the last context menu that was
633 // popped up on the page until a new one is created. We need to clear
634 // this menu before propagating the event through the DOM so that we can
635 // detect if we create a new menu for this event, since we won't create
636 // a new menu if the DOM swallows the event and the defaultEventHandler does
638 page()->contextMenuController()->clearContextMenu();
640 focusedFrame
->view()->setCursor(pointerCursor());
641 WebMouseEvent mouseEvent
;
642 mouseEvent
.button
= WebMouseEvent::ButtonRight
;
643 mouseEvent
.x
= coords
.x();
644 mouseEvent
.y
= coords
.y();
645 mouseEvent
.type
= WebInputEvent::MouseUp
;
647 PlatformMouseEventBuilder
platformEvent(view
, mouseEvent
);
649 m_contextMenuAllowed
= true;
650 bool handled
= focusedFrame
->eventHandler()->sendContextMenuEvent(platformEvent
);
651 m_contextMenuAllowed
= false;
656 bool WebViewImpl::keyEventDefault(const WebKeyboardEvent
& event
)
658 Frame
* frame
= focusedWebCoreFrame();
662 switch (event
.type
) {
663 case WebInputEvent::Char
:
664 if (event
.windowsKeyCode
== VKEY_SPACE
) {
665 int keyCode
= ((event
.modifiers
& WebInputEvent::ShiftKey
) ? VKEY_PRIOR
: VKEY_NEXT
);
666 return scrollViewWithKeyboard(keyCode
, event
.modifiers
);
669 case WebInputEvent::RawKeyDown
:
670 if (event
.modifiers
== WebInputEvent::ControlKey
) {
671 switch (event
.windowsKeyCode
) {
673 focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll"));
677 focusedFrame()->executeCommand(WebString::fromUTF8("Copy"));
679 // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
680 // key combinations which affect scrolling. Safari is buggy in the
681 // sense that it scrolls the page for all Ctrl+scrolling key
682 // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
690 if (!event
.isSystemKey
&& !(event
.modifiers
& WebInputEvent::ShiftKey
))
691 return scrollViewWithKeyboard(event
.windowsKeyCode
, event
.modifiers
);
699 bool WebViewImpl::scrollViewWithKeyboard(int keyCode
, int modifiers
)
701 ScrollDirection scrollDirection
;
702 ScrollGranularity scrollGranularity
;
706 scrollDirection
= ScrollLeft
;
707 scrollGranularity
= ScrollByLine
;
710 scrollDirection
= ScrollRight
;
711 scrollGranularity
= ScrollByLine
;
714 scrollDirection
= ScrollUp
;
715 scrollGranularity
= ScrollByLine
;
718 scrollDirection
= ScrollDown
;
719 scrollGranularity
= ScrollByLine
;
722 scrollDirection
= ScrollUp
;
723 scrollGranularity
= ScrollByDocument
;
726 scrollDirection
= ScrollDown
;
727 scrollGranularity
= ScrollByDocument
;
729 case VKEY_PRIOR
: // page up
730 scrollDirection
= ScrollUp
;
731 scrollGranularity
= ScrollByPage
;
733 case VKEY_NEXT
: // page down
734 scrollDirection
= ScrollDown
;
735 scrollGranularity
= ScrollByPage
;
741 return propagateScroll(scrollDirection
, scrollGranularity
);
744 bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection
,
745 ScrollGranularity scrollGranularity
)
747 Frame
* frame
= focusedWebCoreFrame();
752 frame
->eventHandler()->scrollOverflow(scrollDirection
,
754 Frame
* currentFrame
= frame
;
755 while (!scrollHandled
&& currentFrame
) {
756 scrollHandled
= currentFrame
->view()->scroll(scrollDirection
,
758 currentFrame
= currentFrame
->tree()->parent();
760 return scrollHandled
;
763 Frame
* WebViewImpl::focusedWebCoreFrame()
765 return m_page
.get() ? m_page
->focusController()->focusedOrMainFrame() : 0;
768 WebViewImpl
* WebViewImpl::fromPage(Page
* page
)
773 return static_cast<ChromeClientImpl
*>(page
->chrome()->client())->webView();
776 // WebWidget ------------------------------------------------------------------
778 void WebViewImpl::close()
780 RefPtr
<WebFrameImpl
> mainFrameImpl
;
783 // Initiate shutdown for the entire frameset. This will cause a lot of
784 // notifications to be sent.
785 if (m_page
->mainFrame()) {
786 mainFrameImpl
= WebFrameImpl::fromFrame(m_page
->mainFrame());
787 m_page
->mainFrame()->loader()->frameDetached();
792 // Should happen after m_page.clear().
793 if (m_devToolsAgent
.get())
794 m_devToolsAgent
.clear();
796 // Reset the delegate to prevent notifications being sent as we're being
800 deref(); // Balances ref() acquired in WebView::create
803 void WebViewImpl::resize(const WebSize
& newSize
)
805 if (m_size
== newSize
)
809 if (mainFrameImpl()->frameView()) {
810 mainFrameImpl()->frameView()->resize(m_size
.width
, m_size
.height
);
811 mainFrameImpl()->frame()->eventHandler()->sendResizeEvent();
815 WebRect
damagedRect(0, 0, m_size
.width
, m_size
.height
);
816 m_client
->didInvalidateRect(damagedRect
);
820 void WebViewImpl::layout()
822 WebFrameImpl
* webframe
= mainFrameImpl();
824 // In order for our child HWNDs (NativeWindowWidgets) to update properly,
825 // they need to be told that we are updating the screen. The problem is
826 // that the native widgets need to recalculate their clip region and not
827 // overlap any of our non-native widgets. To force the resizing, call
828 // setFrameRect(). This will be a quick operation for most frames, but
829 // the NativeWindowWidgets will update a proper clipping region.
830 FrameView
* view
= webframe
->frameView();
832 view
->setFrameRect(view
->frameRect());
834 // setFrameRect may have the side-effect of causing existing page
835 // layout to be invalidated, so layout needs to be called last.
841 void WebViewImpl::paint(WebCanvas
* canvas
, const WebRect
& rect
)
843 WebFrameImpl
* webframe
= mainFrameImpl();
845 webframe
->paint(canvas
, rect
);
848 // FIXME: m_currentInputEvent should be removed once ChromeClient::show() can
849 // get the current-event information from WebCore.
850 const WebInputEvent
* WebViewImpl::m_currentInputEvent
= 0;
852 bool WebViewImpl::handleInputEvent(const WebInputEvent
& inputEvent
)
854 // If we've started a drag and drop operation, ignore input events until
856 if (m_doingDragAndDrop
)
859 if (m_ignoreInputEvents
)
862 // FIXME: Remove m_currentInputEvent.
863 // This only exists to allow ChromeClient::show() to know which mouse button
864 // triggered a window.open event.
865 // Safari must perform a similar hack, ours is in our WebKit glue layer
866 // theirs is in the application. This should go when WebCore can be fixed
867 // to pass more event information to ChromeClient::show()
868 m_currentInputEvent
= &inputEvent
;
872 // FIXME: WebKit seems to always return false on mouse events processing
873 // methods. For now we'll assume it has processed them (as we are only
874 // interested in whether keyboard events are processed).
875 switch (inputEvent
.type
) {
876 case WebInputEvent::MouseMove
:
877 mouseMove(*static_cast<const WebMouseEvent
*>(&inputEvent
));
880 case WebInputEvent::MouseLeave
:
881 mouseLeave(*static_cast<const WebMouseEvent
*>(&inputEvent
));
884 case WebInputEvent::MouseWheel
:
885 mouseWheel(*static_cast<const WebMouseWheelEvent
*>(&inputEvent
));
888 case WebInputEvent::MouseDown
:
889 mouseDown(*static_cast<const WebMouseEvent
*>(&inputEvent
));
892 case WebInputEvent::MouseUp
:
893 mouseUp(*static_cast<const WebMouseEvent
*>(&inputEvent
));
896 case WebInputEvent::RawKeyDown
:
897 case WebInputEvent::KeyDown
:
898 case WebInputEvent::KeyUp
:
899 handled
= keyEvent(*static_cast<const WebKeyboardEvent
*>(&inputEvent
));
902 case WebInputEvent::Char
:
903 handled
= charEvent(*static_cast<const WebKeyboardEvent
*>(&inputEvent
));
910 m_currentInputEvent
= 0;
915 void WebViewImpl::mouseCaptureLost()
919 void WebViewImpl::setFocus(bool enable
)
921 m_page
->focusController()->setFocused(enable
);
923 // Note that we don't call setActive() when disabled as this cause extra
924 // focus/blur events to be dispatched.
925 m_page
->focusController()->setActive(true);
926 RefPtr
<Frame
> focusedFrame
= m_page
->focusController()->focusedFrame();
928 Node
* focusedNode
= focusedFrame
->document()->focusedNode();
929 if (focusedNode
&& focusedNode
->isElementNode()
930 && focusedFrame
->selection()->selection().isNone()) {
931 // If the selection was cleared while the WebView was not
932 // focused, then the focus element shows with a focus ring but
933 // no caret and does respond to keyboard inputs.
934 Element
* element
= static_cast<Element
*>(focusedNode
);
935 if (element
->isTextFormControl())
936 element
->updateFocusAppearance(true);
937 else if (focusedNode
->isContentEditable()) {
938 // updateFocusAppearance() selects all the text of
939 // contentseditable DIVs. So we set the selection explicitly
940 // instead. Note that this has the side effect of moving the
941 // caret back to the beginning of the text.
942 Position
position(focusedNode
, 0,
943 Position::PositionIsOffsetInAnchor
);
944 focusedFrame
->selection()->setSelection(
945 VisibleSelection(position
, SEL_DEFAULT_AFFINITY
));
949 m_imeAcceptEvents
= true;
951 hideAutoCompletePopup();
953 // Clear focus on the currently focused frame if any.
957 Frame
* frame
= m_page
->mainFrame();
961 RefPtr
<Frame
> focusedFrame
= m_page
->focusController()->focusedFrame();
962 if (focusedFrame
.get()) {
963 // Finish an ongoing composition to delete the composition node.
964 Editor
* editor
= focusedFrame
->editor();
965 if (editor
&& editor
->hasComposition())
966 editor
->confirmComposition();
967 m_imeAcceptEvents
= false;
972 bool WebViewImpl::handleCompositionEvent(WebCompositionCommand command
,
976 const WebString
& imeString
)
978 Frame
* focused
= focusedWebCoreFrame();
979 if (!focused
|| !m_imeAcceptEvents
)
981 Editor
* editor
= focused
->editor();
984 if (!editor
->canEdit()) {
985 // The input focus has been moved to another WebWidget object.
986 // We should use this |editor| object only to complete the ongoing
988 if (!editor
->hasComposition())
992 // We should verify the parent node of this IME composition node are
993 // editable because JavaScript may delete a parent node of the composition
994 // node. In this case, WebKit crashes while deleting texts from the parent
995 // node, which doesn't exist any longer.
996 PassRefPtr
<Range
> range
= editor
->compositionRange();
998 const Node
* node
= range
->startPosition().node();
999 if (!node
|| !node
->isContentEditable())
1003 if (command
== WebCompositionCommandDiscard
) {
1004 // A browser process sent an IPC message which does not contain a valid
1005 // string, which means an ongoing composition has been canceled.
1006 // If the ongoing composition has been canceled, replace the ongoing
1007 // composition string with an empty string and complete it.
1009 Vector
<CompositionUnderline
> emptyUnderlines
;
1010 editor
->setComposition(emptyString
, emptyUnderlines
, 0, 0);
1012 // A browser process sent an IPC message which contains a string to be
1013 // displayed in this Editor object.
1014 // To display the given string, set the given string to the
1015 // m_compositionNode member of this Editor object and display it.
1016 if (targetStart
< 0)
1019 targetEnd
= static_cast<int>(imeString
.length());
1020 String
compositionString(imeString
);
1021 // Create custom underlines.
1022 // To emphasize the selection, the selected region uses a solid black
1023 // for its underline while other regions uses a pale gray for theirs.
1024 Vector
<CompositionUnderline
> underlines(3);
1025 underlines
[0].startOffset
= 0;
1026 underlines
[0].endOffset
= targetStart
;
1027 underlines
[0].thick
= true;
1028 underlines
[0].color
.setRGB(0xd3, 0xd3, 0xd3);
1029 underlines
[1].startOffset
= targetStart
;
1030 underlines
[1].endOffset
= targetEnd
;
1031 underlines
[1].thick
= true;
1032 underlines
[1].color
.setRGB(0x00, 0x00, 0x00);
1033 underlines
[2].startOffset
= targetEnd
;
1034 underlines
[2].endOffset
= static_cast<int>(imeString
.length());
1035 underlines
[2].thick
= true;
1036 underlines
[2].color
.setRGB(0xd3, 0xd3, 0xd3);
1037 // When we use custom underlines, WebKit ("InlineTextBox.cpp" Line 282)
1038 // prevents from writing a text in between 'selectionStart' and
1039 // 'selectionEnd' somehow.
1040 // Therefore, we use the 'cursorPosition' for these arguments so that
1041 // there are not any characters in the above region.
1042 editor
->setComposition(compositionString
, underlines
,
1043 cursorPosition
, cursorPosition
);
1044 // The given string is a result string, which means the ongoing
1045 // composition has been completed. I have to call the
1046 // Editor::confirmCompletion() and complete this composition.
1047 if (command
== WebCompositionCommandConfirm
)
1048 editor
->confirmComposition();
1051 return editor
->hasComposition();
1054 bool WebViewImpl::queryCompositionStatus(bool* enableIME
, WebRect
* caretRect
)
1056 // Store whether the selected node needs IME and the caret rectangle.
1057 // This process consists of the following four steps:
1058 // 1. Retrieve the selection controller of the focused frame;
1059 // 2. Retrieve the caret rectangle from the controller;
1060 // 3. Convert the rectangle, which is relative to the parent view, to the
1061 // one relative to the client window, and;
1062 // 4. Store the converted rectangle.
1063 const Frame
* focused
= focusedWebCoreFrame();
1067 const Editor
* editor
= focused
->editor();
1068 if (!editor
|| !editor
->canEdit())
1071 SelectionController
* controller
= focused
->selection();
1075 const Node
* node
= controller
->start().node();
1079 *enableIME
= node
->shouldUseInputMethod() && !controller
->isInPasswordField();
1080 const FrameView
* view
= node
->document()->view();
1084 *caretRect
= view
->contentsToWindow(controller
->absoluteCaretBounds());
1088 void WebViewImpl::setTextDirection(WebTextDirection direction
)
1090 // The Editor::setBaseWritingDirection() function checks if we can change
1091 // the text direction of the selected node and updates its DOM "dir"
1092 // attribute and its CSS "direction" property.
1093 // So, we just call the function as Safari does.
1094 const Frame
* focused
= focusedWebCoreFrame();
1098 Editor
* editor
= focused
->editor();
1099 if (!editor
|| !editor
->canEdit())
1102 switch (direction
) {
1103 case WebTextDirectionDefault
:
1104 editor
->setBaseWritingDirection(NaturalWritingDirection
);
1107 case WebTextDirectionLeftToRight
:
1108 editor
->setBaseWritingDirection(LeftToRightWritingDirection
);
1111 case WebTextDirectionRightToLeft
:
1112 editor
->setBaseWritingDirection(RightToLeftWritingDirection
);
1121 // WebView --------------------------------------------------------------------
1123 WebSettings
* WebViewImpl::settings()
1125 if (!m_webSettings
.get())
1126 m_webSettings
.set(new WebSettingsImpl(m_page
->settings()));
1127 ASSERT(m_webSettings
.get());
1128 return m_webSettings
.get();
1131 WebString
WebViewImpl::pageEncoding() const
1136 return m_page
->mainFrame()->loader()->encoding();
1139 void WebViewImpl::setPageEncoding(const WebString
& encodingName
)
1144 // Only change override encoding, don't change default encoding.
1145 // Note that the new encoding must be 0 if it isn't supposed to be set.
1146 String newEncodingName
;
1147 if (!encodingName
.isEmpty())
1148 newEncodingName
= encodingName
;
1149 m_page
->mainFrame()->loader()->reloadWithOverrideEncoding(newEncodingName
);
1152 bool WebViewImpl::dispatchBeforeUnloadEvent()
1154 // FIXME: This should really cause a recursive depth-first walk of all
1155 // frames in the tree, calling each frame's onbeforeunload. At the moment,
1156 // we're consistent with Safari 3.1, not IE/FF.
1157 Frame
* frame
= m_page
->focusController()->focusedOrMainFrame();
1161 return frame
->shouldClose();
1164 void WebViewImpl::dispatchUnloadEvent()
1166 // Run unload handlers.
1167 m_page
->mainFrame()->loader()->closeURL();
1170 WebFrame
* WebViewImpl::mainFrame()
1172 return mainFrameImpl();
1175 WebFrame
* WebViewImpl::findFrameByName(
1176 const WebString
& name
, WebFrame
* relativeToFrame
)
1178 if (!relativeToFrame
)
1179 relativeToFrame
= mainFrame();
1180 Frame
* frame
= static_cast<WebFrameImpl
*>(relativeToFrame
)->frame();
1181 frame
= frame
->tree()->find(name
);
1182 return WebFrameImpl::fromFrame(frame
);
1185 WebFrame
* WebViewImpl::focusedFrame()
1187 return WebFrameImpl::fromFrame(focusedWebCoreFrame());
1190 void WebViewImpl::setFocusedFrame(WebFrame
* frame
)
1193 // Clears the focused frame if any.
1194 Frame
* frame
= focusedWebCoreFrame();
1196 frame
->selection()->setFocused(false);
1199 WebFrameImpl
* frameImpl
= static_cast<WebFrameImpl
*>(frame
);
1200 Frame
* webcoreFrame
= frameImpl
->frame();
1201 webcoreFrame
->page()->focusController()->setFocusedFrame(webcoreFrame
);
1204 void WebViewImpl::setInitialFocus(bool reverse
)
1209 // Since we don't have a keyboard event, we'll create one.
1210 WebKeyboardEvent keyboardEvent
;
1211 keyboardEvent
.type
= WebInputEvent::RawKeyDown
;
1213 keyboardEvent
.modifiers
= WebInputEvent::ShiftKey
;
1215 // VK_TAB which is only defined on Windows.
1216 keyboardEvent
.windowsKeyCode
= 0x09;
1217 PlatformKeyboardEventBuilder
platformEvent(keyboardEvent
);
1218 RefPtr
<KeyboardEvent
> webkitEvent
= KeyboardEvent::create(platformEvent
, 0);
1219 page()->focusController()->setInitialFocus(
1220 reverse
? FocusDirectionBackward
: FocusDirectionForward
,
1224 void WebViewImpl::clearFocusedNode()
1229 RefPtr
<Frame
> frame
= m_page
->mainFrame();
1233 RefPtr
<Document
> document
= frame
->document();
1234 if (!document
.get())
1237 RefPtr
<Node
> oldFocusedNode
= document
->focusedNode();
1239 // Clear the focused node.
1240 document
->setFocusedNode(0);
1242 if (!oldFocusedNode
.get())
1245 // If a text field has focus, we need to make sure the selection controller
1246 // knows to remove selection from it. Otherwise, the text field is still
1247 // processing keyboard events even though focus has been moved to the page and
1248 // keystrokes get eaten as a result.
1249 if (oldFocusedNode
->hasTagName(HTMLNames::textareaTag
)
1250 || (oldFocusedNode
->hasTagName(HTMLNames::inputTag
)
1251 && static_cast<HTMLInputElement
*>(oldFocusedNode
.get())->isTextField())) {
1252 // Clear the selection.
1253 SelectionController
* selection
= frame
->selection();
1258 int WebViewImpl::zoomLevel()
1263 int WebViewImpl::setZoomLevel(bool textOnly
, int zoomLevel
)
1265 float zoomFactor
= static_cast<float>(
1266 std::max(std::min(std::pow(textSizeMultiplierRatio
, zoomLevel
),
1267 maxTextSizeMultiplier
),
1268 minTextSizeMultiplier
));
1269 Frame
* frame
= mainFrameImpl()->frame();
1270 if (zoomFactor
!= frame
->zoomFactor()) {
1271 m_zoomLevel
= zoomLevel
;
1272 frame
->setZoomFactor(zoomFactor
, textOnly
);
1277 void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction
& action
,
1278 const WebPoint
& location
)
1280 HitTestResult result
=
1281 hitTestResultForWindowPos(location
);
1282 RefPtr
<Node
> node
= result
.innerNonSharedNode();
1283 if (!node
->hasTagName(HTMLNames::videoTag
) && !node
->hasTagName(HTMLNames::audioTag
))
1286 RefPtr
<HTMLMediaElement
> mediaElement
=
1287 static_pointer_cast
<HTMLMediaElement
>(node
);
1288 switch (action
.type
) {
1289 case WebMediaPlayerAction::Play
:
1291 mediaElement
->play();
1293 mediaElement
->pause();
1295 case WebMediaPlayerAction::Mute
:
1296 mediaElement
->setMuted(action
.enable
);
1298 case WebMediaPlayerAction::Loop
:
1299 mediaElement
->setLoop(action
.enable
);
1302 ASSERT_NOT_REACHED();
1306 void WebViewImpl::copyImageAt(const WebPoint
& point
)
1311 HitTestResult result
= hitTestResultForWindowPos(point
);
1313 if (result
.absoluteImageURL().isEmpty()) {
1314 // There isn't actually an image at these coordinates. Might be because
1315 // the window scrolled while the context menu was open or because the page
1316 // changed itself between when we thought there was an image here and when
1317 // we actually tried to retreive the image.
1319 // FIXME: implement a cache of the most recent HitTestResult to avoid having
1320 // to do two hit tests.
1324 m_page
->mainFrame()->editor()->copyImage(result
);
1327 void WebViewImpl::dragSourceEndedAt(
1328 const WebPoint
& clientPoint
,
1329 const WebPoint
& screenPoint
,
1330 WebDragOperation operation
)
1332 PlatformMouseEvent
pme(clientPoint
,
1334 LeftButton
, MouseEventMoved
, 0, false, false, false,
1336 m_page
->mainFrame()->eventHandler()->dragSourceEndedAt(pme
,
1337 static_cast<DragOperation
>(operation
));
1340 void WebViewImpl::dragSourceSystemDragEnded()
1342 // It's possible for us to get this callback while not doing a drag if
1343 // it's from a previous page that got unloaded.
1344 if (m_doingDragAndDrop
) {
1345 m_page
->dragController()->dragEnded();
1346 m_doingDragAndDrop
= false;
1350 WebDragOperation
WebViewImpl::dragTargetDragEnter(
1351 const WebDragData
& webDragData
, int identity
,
1352 const WebPoint
& clientPoint
,
1353 const WebPoint
& screenPoint
,
1354 WebDragOperationsMask operationsAllowed
)
1356 ASSERT(!m_currentDragData
.get());
1358 m_currentDragData
= webDragData
;
1359 m_dragIdentity
= identity
;
1360 m_operationsAllowed
= operationsAllowed
;
1363 m_currentDragData
.get(),
1366 static_cast<DragOperation
>(operationsAllowed
));
1368 m_dropEffect
= DropEffectDefault
;
1369 m_dragTargetDispatch
= true;
1370 DragOperation effect
= m_page
->dragController()->dragEntered(&dragData
);
1371 // Mask the operation against the drag source's allowed operations.
1372 if ((effect
& dragData
.draggingSourceOperationMask()) != effect
)
1373 effect
= DragOperationNone
;
1374 m_dragTargetDispatch
= false;
1376 if (m_dropEffect
!= DropEffectDefault
) {
1377 m_dragOperation
= (m_dropEffect
!= DropEffectNone
) ? WebDragOperationCopy
1378 : WebDragOperationNone
;
1380 m_dragOperation
= static_cast<WebDragOperation
>(effect
);
1381 return m_dragOperation
;
1384 WebDragOperation
WebViewImpl::dragTargetDragOver(
1385 const WebPoint
& clientPoint
,
1386 const WebPoint
& screenPoint
,
1387 WebDragOperationsMask operationsAllowed
)
1389 ASSERT(m_currentDragData
.get());
1391 m_operationsAllowed
= operationsAllowed
;
1393 m_currentDragData
.get(),
1396 static_cast<DragOperation
>(operationsAllowed
));
1398 m_dropEffect
= DropEffectDefault
;
1399 m_dragTargetDispatch
= true;
1400 DragOperation effect
= m_page
->dragController()->dragUpdated(&dragData
);
1401 // Mask the operation against the drag source's allowed operations.
1402 if ((effect
& dragData
.draggingSourceOperationMask()) != effect
)
1403 effect
= DragOperationNone
;
1404 m_dragTargetDispatch
= false;
1406 if (m_dropEffect
!= DropEffectDefault
) {
1407 m_dragOperation
= (m_dropEffect
!= DropEffectNone
) ? WebDragOperationCopy
1408 : WebDragOperationNone
;
1410 m_dragOperation
= static_cast<WebDragOperation
>(effect
);
1411 return m_dragOperation
;
1414 void WebViewImpl::dragTargetDragLeave()
1416 ASSERT(m_currentDragData
.get());
1419 m_currentDragData
.get(),
1422 static_cast<DragOperation
>(m_operationsAllowed
));
1424 m_dragTargetDispatch
= true;
1425 m_page
->dragController()->dragExited(&dragData
);
1426 m_dragTargetDispatch
= false;
1428 m_currentDragData
= 0;
1429 m_dropEffect
= DropEffectDefault
;
1430 m_dragOperation
= WebDragOperationNone
;
1434 void WebViewImpl::dragTargetDrop(const WebPoint
& clientPoint
,
1435 const WebPoint
& screenPoint
)
1437 ASSERT(m_currentDragData
.get());
1439 // If this webview transitions from the "drop accepting" state to the "not
1440 // accepting" state, then our IPC message reply indicating that may be in-
1441 // flight, or else delayed by javascript processing in this webview. If a
1442 // drop happens before our IPC reply has reached the browser process, then
1443 // the browser forwards the drop to this webview. So only allow a drop to
1444 // proceed if our webview m_dragOperation state is not DragOperationNone.
1446 if (m_dragOperation
== WebDragOperationNone
) { // IPC RACE CONDITION: do not allow this drop.
1447 dragTargetDragLeave();
1452 m_currentDragData
.get(),
1455 static_cast<DragOperation
>(m_operationsAllowed
));
1457 m_dragTargetDispatch
= true;
1458 m_page
->dragController()->performDrag(&dragData
);
1459 m_dragTargetDispatch
= false;
1461 m_currentDragData
= 0;
1462 m_dropEffect
= DropEffectDefault
;
1463 m_dragOperation
= WebDragOperationNone
;
1467 int WebViewImpl::dragIdentity()
1469 if (m_dragTargetDispatch
)
1470 return m_dragIdentity
;
1474 unsigned long WebViewImpl::createUniqueIdentifierForRequest() {
1476 return m_page
->progress()->createUniqueIdentifier();
1480 void WebViewImpl::inspectElementAt(const WebPoint
& point
)
1485 if (point
.x
== -1 || point
.y
== -1)
1486 m_page
->inspectorController()->inspect(0);
1488 HitTestResult result
= hitTestResultForWindowPos(point
);
1490 if (!result
.innerNonSharedNode())
1493 m_page
->inspectorController()->inspect(result
.innerNonSharedNode());
1497 WebString
WebViewImpl::inspectorSettings() const
1499 return m_inspectorSettings
;
1502 void WebViewImpl::setInspectorSettings(const WebString
& settings
)
1504 m_inspectorSettings
= settings
;
1507 WebDevToolsAgent
* WebViewImpl::devToolsAgent()
1509 return m_devToolsAgent
.get();
1512 void WebViewImpl::setDevToolsAgent(WebDevToolsAgent
* devToolsAgent
)
1514 ASSERT(!m_devToolsAgent
.get()); // May only set once!
1515 m_devToolsAgent
.set(static_cast<WebDevToolsAgentPrivate
*>(devToolsAgent
));
1518 WebAccessibilityObject
WebViewImpl::accessibilityObject()
1520 if (!mainFrameImpl())
1521 return WebAccessibilityObject();
1523 Document
* document
= mainFrameImpl()->frame()->document();
1524 return WebAccessibilityObject(
1525 document
->axObjectCache()->getOrCreate(document
->renderer()));
1528 void WebViewImpl::applyAutofillSuggestions(
1529 const WebNode
& node
,
1530 const WebVector
<WebString
>& suggestions
,
1531 int defaultSuggestionIndex
)
1533 if (!m_page
.get() || suggestions
.isEmpty()) {
1534 hideAutoCompletePopup();
1538 ASSERT(defaultSuggestionIndex
< static_cast<int>(suggestions
.size()));
1540 if (RefPtr
<Frame
> focused
= m_page
->focusController()->focusedFrame()) {
1541 RefPtr
<Document
> document
= focused
->document();
1542 if (!document
.get()) {
1543 hideAutoCompletePopup();
1547 RefPtr
<Node
> focusedNode
= document
->focusedNode();
1548 // If the node for which we queried the autofill suggestions is not the
1549 // focused node, then we have nothing to do. FIXME: also check the
1550 // carret is at the end and that the text has not changed.
1551 if (!focusedNode
.get() || focusedNode
!= PassRefPtr
<Node
>(node
)) {
1552 hideAutoCompletePopup();
1556 if (!focusedNode
->hasTagName(HTMLNames::inputTag
)) {
1557 ASSERT_NOT_REACHED();
1561 HTMLInputElement
* inputElem
=
1562 static_cast<HTMLInputElement
*>(focusedNode
.get());
1564 // The first time the autocomplete is shown we'll create the client and the
1566 if (!m_autocompletePopupClient
.get())
1567 m_autocompletePopupClient
.set(new AutocompletePopupMenuClient(this));
1568 m_autocompletePopupClient
->initialize(inputElem
,
1570 defaultSuggestionIndex
);
1571 if (!m_autocompletePopup
.get()) {
1572 m_autocompletePopup
=
1573 PopupContainer::create(m_autocompletePopupClient
.get(),
1574 autocompletePopupSettings
);
1577 if (m_autocompletePopupShowing
) {
1578 m_autocompletePopupClient
->setSuggestions(suggestions
);
1579 refreshAutofillPopup();
1581 m_autocompletePopup
->show(focusedNode
->getRect(),
1582 focusedNode
->ownerDocument()->view(), 0);
1583 m_autocompletePopupShowing
= true;
1588 void WebViewImpl::hideAutofillPopup()
1590 hideAutoCompletePopup();
1593 void WebViewImpl::performCustomContextMenuAction(unsigned action
)
1597 ContextMenu
* menu
= m_page
->contextMenuController()->contextMenu();
1600 ContextMenuItem
* item
= menu
->itemWithAction(static_cast<ContextMenuAction
>(ContextMenuItemBaseCustomTag
+ action
));
1602 m_page
->contextMenuController()->contextMenuItemSelected(item
);
1603 m_page
->contextMenuController()->clearContextMenu();
1606 // WebView --------------------------------------------------------------------
1608 bool WebViewImpl::setDropEffect(bool accept
)
1610 if (m_dragTargetDispatch
) {
1611 m_dropEffect
= accept
? DropEffectCopy
: DropEffectNone
;
1617 void WebViewImpl::setIsTransparent(bool isTransparent
)
1619 // Set any existing frames to be transparent.
1620 Frame
* frame
= m_page
->mainFrame();
1622 frame
->view()->setTransparent(isTransparent
);
1623 frame
= frame
->tree()->traverseNext();
1626 // Future frames check this to know whether to be transparent.
1627 m_isTransparent
= isTransparent
;
1630 bool WebViewImpl::isTransparent() const
1632 return m_isTransparent
;
1635 void WebViewImpl::setIsActive(bool active
)
1637 if (page() && page()->focusController())
1638 page()->focusController()->setActive(active
);
1641 bool WebViewImpl::isActive() const
1643 return (page() && page()->focusController()) ? page()->focusController()->isActive() : false;
1646 void WebViewImpl::setScrollbarColors(unsigned inactiveColor
,
1647 unsigned activeColor
,
1648 unsigned trackColor
) {
1650 RenderThemeChromiumLinux::setScrollbarColors(inactiveColor
,
1656 void WebViewImpl::didCommitLoad(bool* isNewNavigation
)
1658 if (isNewNavigation
)
1659 *isNewNavigation
= m_observedNewNavigation
;
1662 ASSERT(!m_observedNewNavigation
1663 || m_page
->mainFrame()->loader()->documentLoader() == m_newNavigationLoader
);
1664 m_newNavigationLoader
= 0;
1666 m_observedNewNavigation
= false;
1669 bool WebViewImpl::navigationPolicyFromMouseEvent(unsigned short button
,
1670 bool ctrl
, bool shift
,
1671 bool alt
, bool meta
,
1672 WebNavigationPolicy
* policy
)
1674 #if PLATFORM(WIN_OS) || PLATFORM(LINUX) || PLATFORM(FREEBSD)
1675 const bool newTabModifier
= (button
== 1) || ctrl
;
1676 #elif PLATFORM(DARWIN)
1677 const bool newTabModifier
= (button
== 1) || meta
;
1679 if (!newTabModifier
&& !shift
&& !alt
)
1683 if (newTabModifier
) {
1685 *policy
= WebNavigationPolicyNewForegroundTab
;
1687 *policy
= WebNavigationPolicyNewBackgroundTab
;
1690 *policy
= WebNavigationPolicyNewWindow
;
1692 *policy
= WebNavigationPolicyDownload
;
1697 void WebViewImpl::startDragging(const WebPoint
& eventPos
,
1698 const WebDragData
& dragData
,
1699 WebDragOperationsMask mask
)
1703 ASSERT(!m_doingDragAndDrop
);
1704 m_doingDragAndDrop
= true;
1705 m_client
->startDragging(eventPos
, dragData
, mask
);
1708 void WebViewImpl::setCurrentHistoryItem(HistoryItem
* item
)
1710 m_backForwardListClientImpl
.setCurrentHistoryItem(item
);
1713 HistoryItem
* WebViewImpl::previousHistoryItem()
1715 return m_backForwardListClientImpl
.previousHistoryItem();
1718 void WebViewImpl::observeNewNavigation()
1720 m_observedNewNavigation
= true;
1722 m_newNavigationLoader
= m_page
->mainFrame()->loader()->documentLoader();
1726 void WebViewImpl::hideAutoCompletePopup()
1728 if (m_autocompletePopupShowing
) {
1729 m_autocompletePopup
->hidePopup();
1730 autoCompletePopupDidHide();
1734 void WebViewImpl::autoCompletePopupDidHide()
1736 m_autocompletePopupShowing
= false;
1739 void WebViewImpl::setIgnoreInputEvents(bool newValue
)
1741 ASSERT(m_ignoreInputEvents
!= newValue
);
1742 m_ignoreInputEvents
= newValue
;
1745 #if ENABLE(NOTIFICATIONS)
1746 NotificationPresenterImpl
* WebViewImpl::notificationPresenterImpl()
1748 if (!m_notificationPresenter
.isInitialized() && m_client
)
1749 m_notificationPresenter
.initialize(m_client
->notificationPresenter());
1750 return &m_notificationPresenter
;
1754 void WebViewImpl::refreshAutofillPopup()
1756 ASSERT(m_autocompletePopupShowing
);
1758 // Hide the popup if it has become empty.
1759 if (!m_autocompletePopupClient
->listSize()) {
1760 hideAutoCompletePopup();
1764 IntRect oldBounds
= m_autocompletePopup
->boundsRect();
1765 m_autocompletePopup
->refresh();
1766 IntRect newBounds
= m_autocompletePopup
->boundsRect();
1767 // Let's resize the backing window if necessary.
1768 if (oldBounds
!= newBounds
) {
1769 WebPopupMenuImpl
* popupMenu
=
1770 static_cast<WebPopupMenuImpl
*>(m_autocompletePopup
->client());
1771 popupMenu
->client()->setWindowRect(newBounds
);
1775 Node
* WebViewImpl::focusedWebCoreNode()
1777 Frame
* frame
= m_page
->focusController()->focusedFrame();
1781 Document
* document
= frame
->document();
1785 return document
->focusedNode();
1788 HitTestResult
WebViewImpl::hitTestResultForWindowPos(const IntPoint
& pos
)
1790 IntPoint
docPoint(m_page
->mainFrame()->view()->windowToContents(pos
));
1791 return m_page
->mainFrame()->eventHandler()->hitTestResultAtPoint(docPoint
, false);
1794 void WebViewImpl::setTabsToLinks(bool enable
)
1796 m_tabsToLinks
= enable
;
1799 bool WebViewImpl::tabsToLinks() const
1801 return m_tabsToLinks
;
1804 } // namespace WebKit