• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "config.h"
32 #include "WebViewImpl.h"
33 
34 #include "AutoFillPopupMenuClient.h"
35 #include "AutocompletePopupMenuClient.h"
36 #include "AXObjectCache.h"
37 #include "Chrome.h"
38 #include "ContextMenu.h"
39 #include "ContextMenuController.h"
40 #include "ContextMenuItem.h"
41 #include "CSSStyleSelector.h"
42 #include "CSSValueKeywords.h"
43 #include "Cursor.h"
44 #include "Document.h"
45 #include "DocumentLoader.h"
46 #include "DOMUtilitiesPrivate.h"
47 #include "DragController.h"
48 #include "DragData.h"
49 #include "Editor.h"
50 #include "EventHandler.h"
51 #include "FocusController.h"
52 #include "FontDescription.h"
53 #include "FrameLoader.h"
54 #include "FrameTree.h"
55 #include "FrameView.h"
56 #include "GraphicsContext.h"
57 #include "HitTestResult.h"
58 #include "HTMLInputElement.h"
59 #include "HTMLMediaElement.h"
60 #include "HTMLNames.h"
61 #include "Image.h"
62 #include "InspectorController.h"
63 #include "IntRect.h"
64 #include "KeyboardCodes.h"
65 #include "KeyboardEvent.h"
66 #include "MIMETypeRegistry.h"
67 #include "NodeRenderStyle.h"
68 #include "Page.h"
69 #include "PageGroup.h"
70 #include "PageGroupLoadDeferrer.h"
71 #include "Pasteboard.h"
72 #include "PlatformContextSkia.h"
73 #include "PlatformKeyboardEvent.h"
74 #include "PlatformMouseEvent.h"
75 #include "PlatformWheelEvent.h"
76 #include "PluginInfoStore.h"
77 #include "PopupMenuChromium.h"
78 #include "PopupMenuClient.h"
79 #include "ProgressTracker.h"
80 #include "RenderView.h"
81 #include "ResourceHandle.h"
82 #include "SecurityOrigin.h"
83 #include "SelectionController.h"
84 #include "Settings.h"
85 #include "TypingCommand.h"
86 #include "WebAccessibilityObject.h"
87 #include "WebDevToolsAgentPrivate.h"
88 #include "WebDragData.h"
89 #include "WebFrameImpl.h"
90 #include "WebInputEvent.h"
91 #include "WebInputEventConversion.h"
92 #include "WebMediaPlayerAction.h"
93 #include "WebNode.h"
94 #include "WebPoint.h"
95 #include "WebPopupMenuImpl.h"
96 #include "WebRect.h"
97 #include "WebSettingsImpl.h"
98 #include "WebString.h"
99 #include "WebVector.h"
100 #include "WebViewClient.h"
101 
102 #if OS(WINDOWS)
103 #include "KeyboardCodesWin.h"
104 #include "RenderThemeChromiumWin.h"
105 #else
106 #if OS(LINUX)
107 #include "RenderThemeChromiumLinux.h"
108 #endif
109 #include "KeyboardCodesPosix.h"
110 #include "RenderTheme.h"
111 #endif
112 
113 // Get rid of WTF's pow define so we can use std::pow.
114 #undef pow
115 #include <cmath> // for std::pow
116 
117 using namespace WebCore;
118 
119 namespace WebKit {
120 
121 // Change the text zoom level by kTextSizeMultiplierRatio each time the user
122 // zooms text in or out (ie., change by 20%).  The min and max values limit
123 // text zoom to half and 3x the original text size.  These three values match
124 // those in Apple's port in WebKit/WebKit/WebView/WebView.mm
125 static const double textSizeMultiplierRatio = 1.2;
126 static const double minTextSizeMultiplier = 0.5;
127 static const double maxTextSizeMultiplier = 3.0;
128 
129 // The group name identifies a namespace of pages.  Page group is used on OSX
130 // for some programs that use HTML views to display things that don't seem like
131 // web pages to the user (so shouldn't have visited link coloring).  We only use
132 // one page group.
133 const char* pageGroupName = "default";
134 
135 // Used to defer all page activity in cases where the embedder wishes to run
136 // a nested event loop.
137 static PageGroupLoadDeferrer* pageGroupLoadDeferrer;
138 
139 // Ensure that the WebDragOperation enum values stay in sync with the original
140 // DragOperation constants.
141 #define COMPILE_ASSERT_MATCHING_ENUM(coreName) \
142     COMPILE_ASSERT(int(coreName) == int(Web##coreName), dummy##coreName)
143 COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone);
144 COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy);
145 COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink);
146 COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric);
147 COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate);
148 COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove);
149 COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete);
150 COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery);
151 
152 // Note that focusOnShow is false so that the suggestions popup is shown not
153 // activated.  We need the page to still have focus so the user can keep typing
154 // while the popup is showing.
155 static const PopupContainerSettings suggestionsPopupSettings = {
156     false,  // focusOnShow
157     false,  // setTextOnIndexChange
158     false,  // acceptOnAbandon
159     true,   // loopSelectionNavigation
160     true,   // restrictWidthOfListBox. Same as other browser (Fx, IE, and safari)
161     // For suggestions, we use the direction of the input field as the direction
162     // of the popup items. The main reason is to keep the display of items in
163     // drop-down the same as the items in the input field.
164     PopupContainerSettings::DOMElementDirection,
165 };
166 
167 // WebView ----------------------------------------------------------------
168 
create(WebViewClient * client)169 WebView* WebView::create(WebViewClient* client)
170 {
171     return new WebViewImpl(client);
172 }
173 
updateVisitedLinkState(unsigned long long linkHash)174 void WebView::updateVisitedLinkState(unsigned long long linkHash)
175 {
176     Page::visitedStateChanged(PageGroup::pageGroup(pageGroupName), linkHash);
177 }
178 
resetVisitedLinkState()179 void WebView::resetVisitedLinkState()
180 {
181     Page::allVisitedStateChanged(PageGroup::pageGroup(pageGroupName));
182 }
183 
willEnterModalLoop()184 void WebView::willEnterModalLoop()
185 {
186     // It is not valid to nest more than once.
187     ASSERT(!pageGroupLoadDeferrer);
188 
189     PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
190     ASSERT(pageGroup);
191     ASSERT(!pageGroup->pages().isEmpty());
192 
193     // Pick any page in the page group since we are deferring all pages.
194     pageGroupLoadDeferrer = new PageGroupLoadDeferrer(*pageGroup->pages().begin(), true);
195 }
196 
didExitModalLoop()197 void WebView::didExitModalLoop()
198 {
199     // The embedder must have called willEnterNestedEventLoop.
200     ASSERT(pageGroupLoadDeferrer);
201 
202     delete pageGroupLoadDeferrer;
203     pageGroupLoadDeferrer = 0;
204 }
205 
initializeMainFrame(WebFrameClient * frameClient)206 void WebViewImpl::initializeMainFrame(WebFrameClient* frameClient)
207 {
208     // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame
209     // and releases that reference once the corresponding Frame is destroyed.
210     RefPtr<WebFrameImpl> frame = WebFrameImpl::create(frameClient);
211 
212     frame->initializeAsMainFrame(this);
213 
214     // Restrict the access to the local file system
215     // (see WebView.mm WebView::_commonInitializationWithFrameName).
216     SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForLocalOnly);
217 }
218 
WebViewImpl(WebViewClient * client)219 WebViewImpl::WebViewImpl(WebViewClient* client)
220     : m_client(client)
221     , m_backForwardListClientImpl(this)
222     , m_chromeClientImpl(this)
223     , m_contextMenuClientImpl(this)
224     , m_dragClientImpl(this)
225     , m_editorClientImpl(this)
226     , m_inspectorClientImpl(this)
227     , m_observedNewNavigation(false)
228 #ifndef NDEBUG
229     , m_newNavigationLoader(0)
230 #endif
231     , m_zoomLevel(0)
232     , m_contextMenuAllowed(false)
233     , m_doingDragAndDrop(false)
234     , m_ignoreInputEvents(false)
235     , m_suppressNextKeypressEvent(false)
236     , m_initialNavigationPolicy(WebNavigationPolicyIgnore)
237     , m_imeAcceptEvents(true)
238     , m_dragTargetDispatch(false)
239     , m_dragIdentity(0)
240     , m_dropEffect(DropEffectDefault)
241     , m_operationsAllowed(WebDragOperationNone)
242     , m_dragOperation(WebDragOperationNone)
243     , m_suggestionsPopupShowing(false)
244     , m_suggestionsPopupClient(0)
245     , m_suggestionsPopup(0)
246     , m_isTransparent(false)
247     , m_tabsToLinks(false)
248 {
249     // WebKit/win/WebView.cpp does the same thing, except they call the
250     // KJS specific wrapper around this method. We need to have threading
251     // initialized because CollatorICU requires it.
252     WTF::initializeThreading();
253 
254     // set to impossible point so we always get the first mouse pos
255     m_lastMousePosition = WebPoint(-1, -1);
256 
257     // the page will take ownership of the various clients
258     m_page.set(new Page(&m_chromeClientImpl,
259                         &m_contextMenuClientImpl,
260                         &m_editorClientImpl,
261                         &m_dragClientImpl,
262                         &m_inspectorClientImpl,
263                         0,
264                         0));
265 
266     m_page->backForwardList()->setClient(&m_backForwardListClientImpl);
267     m_page->setGroupName(pageGroupName);
268 }
269 
~WebViewImpl()270 WebViewImpl::~WebViewImpl()
271 {
272     ASSERT(!m_page);
273 }
274 
theme() const275 RenderTheme* WebViewImpl::theme() const
276 {
277     return m_page.get() ? m_page->theme() : RenderTheme::defaultTheme().get();
278 }
279 
mainFrameImpl()280 WebFrameImpl* WebViewImpl::mainFrameImpl()
281 {
282     return m_page.get() ? WebFrameImpl::fromFrame(m_page->mainFrame()) : 0;
283 }
284 
tabKeyCyclesThroughElements() const285 bool WebViewImpl::tabKeyCyclesThroughElements() const
286 {
287     ASSERT(m_page.get());
288     return m_page->tabKeyCyclesThroughElements();
289 }
290 
setTabKeyCyclesThroughElements(bool value)291 void WebViewImpl::setTabKeyCyclesThroughElements(bool value)
292 {
293     if (m_page)
294         m_page->setTabKeyCyclesThroughElements(value);
295 }
296 
mouseMove(const WebMouseEvent & event)297 void WebViewImpl::mouseMove(const WebMouseEvent& event)
298 {
299     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
300         return;
301 
302     m_lastMousePosition = WebPoint(event.x, event.y);
303 
304     // We call mouseMoved here instead of handleMouseMovedEvent because we need
305     // our ChromeClientImpl to receive changes to the mouse position and
306     // tooltip text, and mouseMoved handles all of that.
307     mainFrameImpl()->frame()->eventHandler()->mouseMoved(
308         PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
309 }
310 
mouseLeave(const WebMouseEvent & event)311 void WebViewImpl::mouseLeave(const WebMouseEvent& event)
312 {
313     // This event gets sent as the main frame is closing.  In that case, just
314     // ignore it.
315     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
316         return;
317 
318     m_client->setMouseOverURL(WebURL());
319 
320     mainFrameImpl()->frame()->eventHandler()->handleMouseMoveEvent(
321         PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
322 }
323 
mouseDown(const WebMouseEvent & event)324 void WebViewImpl::mouseDown(const WebMouseEvent& event)
325 {
326     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
327         return;
328 
329     m_lastMouseDownPoint = WebPoint(event.x, event.y);
330 
331     // If a text field that has focus is clicked again, we should display the
332     // suggestions popup.
333     RefPtr<Node> clickedNode;
334     if (event.button == WebMouseEvent::ButtonLeft) {
335         RefPtr<Node> focusedNode = focusedWebCoreNode();
336         if (focusedNode.get() && toHTMLInputElement(focusedNode.get())) {
337             IntPoint point(event.x, event.y);
338             point = m_page->mainFrame()->view()->windowToContents(point);
339             HitTestResult result(point);
340             result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, false);
341             if (result.innerNonSharedNode() == focusedNode) {
342                 // Already focused text field was clicked, let's remember this.  If
343                 // focus has not changed after the mouse event is processed, we'll
344                 // trigger the autocomplete.
345                 clickedNode = focusedNode;
346             }
347         }
348     }
349 
350     mainFrameImpl()->frame()->eventHandler()->handleMousePressEvent(
351         PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
352 
353     if (clickedNode.get() && clickedNode == focusedWebCoreNode()) {
354         // Focus has not changed, show the suggestions popup.
355         static_cast<EditorClientImpl*>(m_page->editorClient())->
356             showFormAutofillForNode(clickedNode.get());
357     }
358 
359     // Dispatch the contextmenu event regardless of if the click was swallowed.
360     // On Windows, we handle it on mouse up, not down.
361 #if OS(DARWIN)
362     if (event.button == WebMouseEvent::ButtonRight
363         || (event.button == WebMouseEvent::ButtonLeft
364             && event.modifiers & WebMouseEvent::ControlKey))
365         mouseContextMenu(event);
366 #elif OS(LINUX)
367     if (event.button == WebMouseEvent::ButtonRight)
368         mouseContextMenu(event);
369 #endif
370 }
371 
mouseContextMenu(const WebMouseEvent & event)372 void WebViewImpl::mouseContextMenu(const WebMouseEvent& event)
373 {
374     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
375         return;
376 
377     m_page->contextMenuController()->clearContextMenu();
378 
379     PlatformMouseEventBuilder pme(mainFrameImpl()->frameView(), event);
380 
381     // Find the right target frame. See issue 1186900.
382     HitTestResult result = hitTestResultForWindowPos(pme.pos());
383     Frame* targetFrame;
384     if (result.innerNonSharedNode())
385         targetFrame = result.innerNonSharedNode()->document()->frame();
386     else
387         targetFrame = m_page->focusController()->focusedOrMainFrame();
388 
389 #if OS(WINDOWS)
390     targetFrame->view()->setCursor(pointerCursor());
391 #endif
392 
393     m_contextMenuAllowed = true;
394     targetFrame->eventHandler()->sendContextMenuEvent(pme);
395     m_contextMenuAllowed = false;
396     // Actually showing the context menu is handled by the ContextMenuClient
397     // implementation...
398 }
399 
mouseUp(const WebMouseEvent & event)400 void WebViewImpl::mouseUp(const WebMouseEvent& event)
401 {
402     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
403         return;
404 
405 #if OS(LINUX)
406     // If the event was a middle click, attempt to copy text into the focused
407     // frame. We execute this before we let the page have a go at the event
408     // because the page may change what is focused during in its event handler.
409     //
410     // This code is in the mouse up handler. There is some debate about putting
411     // this here, as opposed to the mouse down handler.
412     //   xterm: pastes on up.
413     //   GTK: pastes on down.
414     //   Firefox: pastes on up.
415     //   Midori: couldn't paste at all with 0.1.2
416     //
417     // There is something of a webcompat angle to this well, as highlighted by
418     // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
419     // down then the text is pasted just before the onclick handler runs and
420     // clears the text box. So it's important this happens after the
421     // handleMouseReleaseEvent() earlier in this function
422     if (event.button == WebMouseEvent::ButtonMiddle) {
423         Frame* focused = focusedWebCoreFrame();
424         FrameView* view = m_page->mainFrame()->view();
425         IntPoint clickPoint(m_lastMouseDownPoint.x, m_lastMouseDownPoint.y);
426         IntPoint contentPoint = view->windowToContents(clickPoint);
427         HitTestResult hitTestResult = focused->eventHandler()->hitTestResultAtPoint(contentPoint, false, false, ShouldHitTestScrollbars);
428         // We don't want to send a paste when middle clicking a scroll bar or a
429         // link (which will navigate later in the code).  The main scrollbars
430         // have to be handled separately.
431         if (!hitTestResult.scrollbar() && !hitTestResult.isLiveLink() && focused && !view->scrollbarAtPoint(clickPoint)) {
432             Editor* editor = focused->editor();
433             Pasteboard* pasteboard = Pasteboard::generalPasteboard();
434             bool oldSelectionMode = pasteboard->isSelectionMode();
435             pasteboard->setSelectionMode(true);
436             editor->command(AtomicString("Paste")).execute();
437             pasteboard->setSelectionMode(oldSelectionMode);
438         }
439     }
440 #endif
441 
442     mouseCaptureLost();
443     mainFrameImpl()->frame()->eventHandler()->handleMouseReleaseEvent(
444         PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
445 
446 #if OS(WINDOWS)
447     // Dispatch the contextmenu event regardless of if the click was swallowed.
448     // On Mac/Linux, we handle it on mouse down, not up.
449     if (event.button == WebMouseEvent::ButtonRight)
450         mouseContextMenu(event);
451 #endif
452 }
453 
mouseWheel(const WebMouseWheelEvent & event)454 void WebViewImpl::mouseWheel(const WebMouseWheelEvent& event)
455 {
456     PlatformWheelEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
457     mainFrameImpl()->frame()->eventHandler()->handleWheelEvent(platformEvent);
458 }
459 
keyEvent(const WebKeyboardEvent & event)460 bool WebViewImpl::keyEvent(const WebKeyboardEvent& event)
461 {
462     ASSERT((event.type == WebInputEvent::RawKeyDown)
463         || (event.type == WebInputEvent::KeyDown)
464         || (event.type == WebInputEvent::KeyUp));
465 
466     // Please refer to the comments explaining the m_suppressNextKeypressEvent
467     // member.
468     // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
469     // Webkit. A keyDown event is typically associated with a keyPress(char)
470     // event and a keyUp event. We reset this flag here as this is a new keyDown
471     // event.
472     m_suppressNextKeypressEvent = false;
473 
474     // Give Autocomplete a chance to consume the key events it is interested in.
475     if (autocompleteHandleKeyEvent(event))
476         return true;
477 
478     Frame* frame = focusedWebCoreFrame();
479     if (!frame)
480         return false;
481 
482     EventHandler* handler = frame->eventHandler();
483     if (!handler)
484         return keyEventDefault(event);
485 
486 #if OS(WINDOWS) || OS(LINUX)
487     const WebInputEvent::Type contextMenuTriggeringEventType =
488 #if OS(WINDOWS)
489         WebInputEvent::KeyUp;
490 #elif OS(LINUX)
491         WebInputEvent::RawKeyDown;
492 #endif
493 
494     if (((!event.modifiers && (event.windowsKeyCode == VKEY_APPS))
495         || ((event.modifiers == WebInputEvent::ShiftKey) && (event.windowsKeyCode == VKEY_F10)))
496         && event.type == contextMenuTriggeringEventType) {
497         sendContextMenuEvent(event);
498         return true;
499     }
500 #endif
501 
502     // It's not clear if we should continue after detecting a capslock keypress.
503     // I'll err on the side of continuing, which is the pre-existing behaviour.
504     if (event.windowsKeyCode == VKEY_CAPITAL)
505         handler->capsLockStateMayHaveChanged();
506 
507     PlatformKeyboardEventBuilder evt(event);
508 
509     if (handler->keyEvent(evt)) {
510         if (WebInputEvent::RawKeyDown == event.type)
511             m_suppressNextKeypressEvent = true;
512         return true;
513     }
514 
515     return keyEventDefault(event);
516 }
517 
autocompleteHandleKeyEvent(const WebKeyboardEvent & event)518 bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event)
519 {
520     if (!m_suggestionsPopupShowing
521         // Home and End should be left to the text field to process.
522         || event.windowsKeyCode == VKEY_HOME
523         || event.windowsKeyCode == VKEY_END)
524       return false;
525 
526     // Pressing delete triggers the removal of the selected suggestion from the DB.
527     if (event.windowsKeyCode == VKEY_DELETE
528         && m_suggestionsPopup->selectedIndex() != -1) {
529         Node* node = focusedWebCoreNode();
530         if (!node || (node->nodeType() != Node::ELEMENT_NODE)) {
531             ASSERT_NOT_REACHED();
532             return false;
533         }
534         Element* element = static_cast<Element*>(node);
535         if (!element->hasLocalName(HTMLNames::inputTag)) {
536             ASSERT_NOT_REACHED();
537             return false;
538         }
539 
540         int selectedIndex = m_suggestionsPopup->selectedIndex();
541         HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(element);
542         WebString name = inputElement->name();
543         WebString value = m_autocompletePopupClient->itemText(selectedIndex);
544         m_client->removeAutofillSuggestions(name, value);
545         // Update the entries in the currently showing popup to reflect the
546         // deletion.
547         m_autocompletePopupClient->removeSuggestionAtIndex(selectedIndex);
548         refreshSuggestionsPopup();
549         return false;
550     }
551 
552     if (!m_suggestionsPopup->isInterestedInEventForKey(event.windowsKeyCode))
553         return false;
554 
555     if (m_suggestionsPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) {
556         // We need to ignore the next Char event after this otherwise pressing
557         // enter when selecting an item in the menu will go to the page.
558         if (WebInputEvent::RawKeyDown == event.type)
559             m_suppressNextKeypressEvent = true;
560         return true;
561     }
562 
563     return false;
564 }
565 
charEvent(const WebKeyboardEvent & event)566 bool WebViewImpl::charEvent(const WebKeyboardEvent& event)
567 {
568     ASSERT(event.type == WebInputEvent::Char);
569 
570     // Please refer to the comments explaining the m_suppressNextKeypressEvent
571     // member.  The m_suppressNextKeypressEvent is set if the KeyDown is
572     // handled by Webkit. A keyDown event is typically associated with a
573     // keyPress(char) event and a keyUp event. We reset this flag here as it
574     // only applies to the current keyPress event.
575     bool suppress = m_suppressNextKeypressEvent;
576     m_suppressNextKeypressEvent = false;
577 
578     Frame* frame = focusedWebCoreFrame();
579     if (!frame)
580         return suppress;
581 
582     EventHandler* handler = frame->eventHandler();
583     if (!handler)
584         return suppress || keyEventDefault(event);
585 
586     PlatformKeyboardEventBuilder evt(event);
587     if (!evt.isCharacterKey())
588         return true;
589 
590     // Accesskeys are triggered by char events and can't be suppressed.
591     if (handler->handleAccessKey(evt))
592         return true;
593 
594     // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
595     // the eventHandler::keyEvent. We mimic this behavior on all platforms since
596     // for now we are converting other platform's key events to windows key
597     // events.
598     if (evt.isSystemKey())
599         return false;
600 
601     if (!suppress && !handler->keyEvent(evt))
602         return keyEventDefault(event);
603 
604     return true;
605 }
606 
607 // The WebViewImpl::SendContextMenuEvent function is based on the Webkit
608 // function
609 // bool WebView::handleContextMenuEvent(WPARAM wParam, LPARAM lParam) in
610 // webkit\webkit\win\WebView.cpp. The only significant change in this
611 // function is the code to convert from a Keyboard event to the Right
612 // Mouse button up event.
613 //
614 // This function is an ugly copy/paste and should be cleaned up when the
615 // WebKitWin version is cleaned: https://bugs.webkit.org/show_bug.cgi?id=20438
616 #if OS(WINDOWS) || OS(LINUX)
617 // FIXME: implement on Mac
sendContextMenuEvent(const WebKeyboardEvent & event)618 bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event)
619 {
620     static const int kContextMenuMargin = 1;
621     Frame* mainFrameImpl = page()->mainFrame();
622     FrameView* view = mainFrameImpl->view();
623     if (!view)
624         return false;
625 
626     IntPoint coords(-1, -1);
627 #if OS(WINDOWS)
628     int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
629 #else
630     int rightAligned = 0;
631 #endif
632     IntPoint location;
633 
634 
635     Frame* focusedFrame = page()->focusController()->focusedOrMainFrame();
636     Node* focusedNode = focusedFrame->document()->focusedNode();
637     Position start = mainFrameImpl->selection()->selection().start();
638 
639     if (focusedFrame->editor() && focusedFrame->editor()->canEdit() && start.node()) {
640         RenderObject* renderer = start.node()->renderer();
641         if (!renderer)
642             return false;
643 
644         RefPtr<Range> selection = mainFrameImpl->selection()->toNormalizedRange();
645         IntRect firstRect = mainFrameImpl->firstRectForRange(selection.get());
646 
647         int x = rightAligned ? firstRect.right() : firstRect.x();
648         location = IntPoint(x, firstRect.bottom());
649     } else if (focusedNode)
650         location = focusedNode->getRect().bottomLeft();
651     else {
652         location = IntPoint(
653             rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
654             kContextMenuMargin);
655     }
656 
657     location = view->contentsToWindow(location);
658     // FIXME: The IntSize(0, -1) is a hack to get the hit-testing to result in
659     // the selected element. Ideally we'd have the position of a context menu
660     // event be separate from its target node.
661     coords = location + IntSize(0, -1);
662 
663     // The contextMenuController() holds onto the last context menu that was
664     // popped up on the page until a new one is created. We need to clear
665     // this menu before propagating the event through the DOM so that we can
666     // detect if we create a new menu for this event, since we won't create
667     // a new menu if the DOM swallows the event and the defaultEventHandler does
668     // not run.
669     page()->contextMenuController()->clearContextMenu();
670 
671     focusedFrame->view()->setCursor(pointerCursor());
672     WebMouseEvent mouseEvent;
673     mouseEvent.button = WebMouseEvent::ButtonRight;
674     mouseEvent.x = coords.x();
675     mouseEvent.y = coords.y();
676     mouseEvent.type = WebInputEvent::MouseUp;
677 
678     PlatformMouseEventBuilder platformEvent(view, mouseEvent);
679 
680     m_contextMenuAllowed = true;
681     bool handled = focusedFrame->eventHandler()->sendContextMenuEvent(platformEvent);
682     m_contextMenuAllowed = false;
683     return handled;
684 }
685 #endif
686 
keyEventDefault(const WebKeyboardEvent & event)687 bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event)
688 {
689     Frame* frame = focusedWebCoreFrame();
690     if (!frame)
691         return false;
692 
693     switch (event.type) {
694     case WebInputEvent::Char:
695         if (event.windowsKeyCode == VKEY_SPACE) {
696             int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT);
697             return scrollViewWithKeyboard(keyCode, event.modifiers);
698         }
699         break;
700     case WebInputEvent::RawKeyDown:
701         if (event.modifiers == WebInputEvent::ControlKey) {
702             switch (event.windowsKeyCode) {
703 #if !OS(DARWIN)
704             case 'A':
705                 focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll"));
706                 return true;
707             case VKEY_INSERT:
708             case 'C':
709                 focusedFrame()->executeCommand(WebString::fromUTF8("Copy"));
710                 return true;
711 #endif
712             // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
713             // key combinations which affect scrolling. Safari is buggy in the
714             // sense that it scrolls the page for all Ctrl+scrolling key
715             // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
716             case VKEY_HOME:
717             case VKEY_END:
718                 break;
719             default:
720                 return false;
721             }
722         }
723         if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey))
724             return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers);
725         break;
726     default:
727         break;
728     }
729     return false;
730 }
731 
scrollViewWithKeyboard(int keyCode,int modifiers)732 bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers)
733 {
734     ScrollDirection scrollDirection;
735     ScrollGranularity scrollGranularity;
736 
737     switch (keyCode) {
738     case VKEY_LEFT:
739         scrollDirection = ScrollLeft;
740         scrollGranularity = ScrollByLine;
741         break;
742     case VKEY_RIGHT:
743         scrollDirection = ScrollRight;
744         scrollGranularity = ScrollByLine;
745         break;
746     case VKEY_UP:
747         scrollDirection = ScrollUp;
748         scrollGranularity = ScrollByLine;
749         break;
750     case VKEY_DOWN:
751         scrollDirection = ScrollDown;
752         scrollGranularity = ScrollByLine;
753         break;
754     case VKEY_HOME:
755         scrollDirection = ScrollUp;
756         scrollGranularity = ScrollByDocument;
757         break;
758     case VKEY_END:
759         scrollDirection = ScrollDown;
760         scrollGranularity = ScrollByDocument;
761         break;
762     case VKEY_PRIOR:  // page up
763         scrollDirection = ScrollUp;
764         scrollGranularity = ScrollByPage;
765         break;
766     case VKEY_NEXT:  // page down
767         scrollDirection = ScrollDown;
768         scrollGranularity = ScrollByPage;
769         break;
770     default:
771         return false;
772     }
773 
774     return propagateScroll(scrollDirection, scrollGranularity);
775 }
776 
propagateScroll(ScrollDirection scrollDirection,ScrollGranularity scrollGranularity)777 bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection,
778                                   ScrollGranularity scrollGranularity)
779 {
780     Frame* frame = focusedWebCoreFrame();
781     if (!frame)
782         return false;
783 
784     bool scrollHandled =
785         frame->eventHandler()->scrollOverflow(scrollDirection,
786                                               scrollGranularity);
787     Frame* currentFrame = frame;
788     while (!scrollHandled && currentFrame) {
789         scrollHandled = currentFrame->view()->scroll(scrollDirection,
790                                                      scrollGranularity);
791         currentFrame = currentFrame->tree()->parent();
792     }
793     return scrollHandled;
794 }
795 
focusedWebCoreFrame()796 Frame* WebViewImpl::focusedWebCoreFrame()
797 {
798     return m_page.get() ? m_page->focusController()->focusedOrMainFrame() : 0;
799 }
800 
fromPage(Page * page)801 WebViewImpl* WebViewImpl::fromPage(Page* page)
802 {
803     if (!page)
804         return 0;
805 
806     return static_cast<ChromeClientImpl*>(page->chrome()->client())->webView();
807 }
808 
809 // WebWidget ------------------------------------------------------------------
810 
close()811 void WebViewImpl::close()
812 {
813     RefPtr<WebFrameImpl> mainFrameImpl;
814 
815     if (m_page.get()) {
816         // Initiate shutdown for the entire frameset.  This will cause a lot of
817         // notifications to be sent.
818         if (m_page->mainFrame()) {
819             mainFrameImpl = WebFrameImpl::fromFrame(m_page->mainFrame());
820             m_page->mainFrame()->loader()->frameDetached();
821         }
822         m_page.clear();
823     }
824 
825     // Should happen after m_page.clear().
826     if (m_devToolsAgent.get())
827         m_devToolsAgent.clear();
828 
829     // Reset the delegate to prevent notifications being sent as we're being
830     // deleted.
831     m_client = 0;
832 
833     deref();  // Balances ref() acquired in WebView::create
834 }
835 
resize(const WebSize & newSize)836 void WebViewImpl::resize(const WebSize& newSize)
837 {
838     if (m_size == newSize)
839         return;
840     m_size = newSize;
841 
842     if (mainFrameImpl()->frameView()) {
843         mainFrameImpl()->frameView()->resize(m_size.width, m_size.height);
844         mainFrameImpl()->frame()->eventHandler()->sendResizeEvent();
845     }
846 
847     if (m_client) {
848         WebRect damagedRect(0, 0, m_size.width, m_size.height);
849         m_client->didInvalidateRect(damagedRect);
850     }
851 }
852 
layout()853 void WebViewImpl::layout()
854 {
855     WebFrameImpl* webframe = mainFrameImpl();
856     if (webframe) {
857         // In order for our child HWNDs (NativeWindowWidgets) to update properly,
858         // they need to be told that we are updating the screen.  The problem is
859         // that the native widgets need to recalculate their clip region and not
860         // overlap any of our non-native widgets.  To force the resizing, call
861         // setFrameRect().  This will be a quick operation for most frames, but
862         // the NativeWindowWidgets will update a proper clipping region.
863         FrameView* view = webframe->frameView();
864         if (view)
865             view->setFrameRect(view->frameRect());
866 
867         // setFrameRect may have the side-effect of causing existing page
868         // layout to be invalidated, so layout needs to be called last.
869 
870         webframe->layout();
871     }
872 }
873 
paint(WebCanvas * canvas,const WebRect & rect)874 void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect)
875 {
876     WebFrameImpl* webframe = mainFrameImpl();
877     if (webframe)
878         webframe->paint(canvas, rect);
879 }
880 
881 // FIXME: m_currentInputEvent should be removed once ChromeClient::show() can
882 // get the current-event information from WebCore.
883 const WebInputEvent* WebViewImpl::m_currentInputEvent = 0;
884 
handleInputEvent(const WebInputEvent & inputEvent)885 bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
886 {
887     // If we've started a drag and drop operation, ignore input events until
888     // we're done.
889     if (m_doingDragAndDrop)
890         return true;
891 
892     if (m_ignoreInputEvents)
893         return true;
894 
895     // FIXME: Remove m_currentInputEvent.
896     // This only exists to allow ChromeClient::show() to know which mouse button
897     // triggered a window.open event.
898     // Safari must perform a similar hack, ours is in our WebKit glue layer
899     // theirs is in the application.  This should go when WebCore can be fixed
900     // to pass more event information to ChromeClient::show()
901     m_currentInputEvent = &inputEvent;
902 
903     bool handled = true;
904 
905     // FIXME: WebKit seems to always return false on mouse events processing
906     // methods. For now we'll assume it has processed them (as we are only
907     // interested in whether keyboard events are processed).
908     switch (inputEvent.type) {
909     case WebInputEvent::MouseMove:
910         mouseMove(*static_cast<const WebMouseEvent*>(&inputEvent));
911         break;
912 
913     case WebInputEvent::MouseLeave:
914         mouseLeave(*static_cast<const WebMouseEvent*>(&inputEvent));
915         break;
916 
917     case WebInputEvent::MouseWheel:
918         mouseWheel(*static_cast<const WebMouseWheelEvent*>(&inputEvent));
919         break;
920 
921     case WebInputEvent::MouseDown:
922         mouseDown(*static_cast<const WebMouseEvent*>(&inputEvent));
923         break;
924 
925     case WebInputEvent::MouseUp:
926         mouseUp(*static_cast<const WebMouseEvent*>(&inputEvent));
927         break;
928 
929     case WebInputEvent::RawKeyDown:
930     case WebInputEvent::KeyDown:
931     case WebInputEvent::KeyUp:
932         handled = keyEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent));
933         break;
934 
935     case WebInputEvent::Char:
936         handled = charEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent));
937         break;
938 
939     default:
940         handled = false;
941     }
942 
943     m_currentInputEvent = 0;
944 
945     return handled;
946 }
947 
mouseCaptureLost()948 void WebViewImpl::mouseCaptureLost()
949 {
950 }
951 
setFocus(bool enable)952 void WebViewImpl::setFocus(bool enable)
953 {
954     m_page->focusController()->setFocused(enable);
955     if (enable) {
956         // Note that we don't call setActive() when disabled as this cause extra
957         // focus/blur events to be dispatched.
958         m_page->focusController()->setActive(true);
959         RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
960         if (focusedFrame) {
961             Node* focusedNode = focusedFrame->document()->focusedNode();
962             if (focusedNode && focusedNode->isElementNode()
963                 && focusedFrame->selection()->selection().isNone()) {
964                 // If the selection was cleared while the WebView was not
965                 // focused, then the focus element shows with a focus ring but
966                 // no caret and does respond to keyboard inputs.
967                 Element* element = static_cast<Element*>(focusedNode);
968                 if (element->isTextFormControl())
969                     element->updateFocusAppearance(true);
970                 else if (focusedNode->isContentEditable()) {
971                     // updateFocusAppearance() selects all the text of
972                     // contentseditable DIVs. So we set the selection explicitly
973                     // instead. Note that this has the side effect of moving the
974                     // caret back to the beginning of the text.
975                     Position position(focusedNode, 0,
976                                       Position::PositionIsOffsetInAnchor);
977                     focusedFrame->selection()->setSelection(
978                         VisibleSelection(position, SEL_DEFAULT_AFFINITY));
979                 }
980             }
981         }
982         m_imeAcceptEvents = true;
983     } else {
984         hideSuggestionsPopup();
985 
986         // Clear focus on the currently focused frame if any.
987         if (!m_page.get())
988             return;
989 
990         Frame* frame = m_page->mainFrame();
991         if (!frame)
992             return;
993 
994         RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame();
995         if (focusedFrame.get()) {
996             // Finish an ongoing composition to delete the composition node.
997             Editor* editor = focusedFrame->editor();
998             if (editor && editor->hasComposition())
999                 editor->confirmComposition();
1000             m_imeAcceptEvents = false;
1001         }
1002     }
1003 }
1004 
handleCompositionEvent(WebCompositionCommand command,int cursorPosition,int targetStart,int targetEnd,const WebString & imeString)1005 bool WebViewImpl::handleCompositionEvent(WebCompositionCommand command,
1006                                          int cursorPosition,
1007                                          int targetStart,
1008                                          int targetEnd,
1009                                          const WebString& imeString)
1010 {
1011     Frame* focused = focusedWebCoreFrame();
1012     if (!focused || !m_imeAcceptEvents)
1013         return false;
1014     Editor* editor = focused->editor();
1015     if (!editor)
1016         return false;
1017     if (!editor->canEdit()) {
1018         // The input focus has been moved to another WebWidget object.
1019         // We should use this |editor| object only to complete the ongoing
1020         // composition.
1021         if (!editor->hasComposition())
1022             return false;
1023     }
1024 
1025     // We should verify the parent node of this IME composition node are
1026     // editable because JavaScript may delete a parent node of the composition
1027     // node. In this case, WebKit crashes while deleting texts from the parent
1028     // node, which doesn't exist any longer.
1029     PassRefPtr<Range> range = editor->compositionRange();
1030     if (range) {
1031         const Node* node = range->startPosition().node();
1032         if (!node || !node->isContentEditable())
1033             return false;
1034     }
1035 
1036     if (command == WebCompositionCommandDiscard) {
1037         // A browser process sent an IPC message which does not contain a valid
1038         // string, which means an ongoing composition has been canceled.
1039         // If the ongoing composition has been canceled, replace the ongoing
1040         // composition string with an empty string and complete it.
1041         String emptyString;
1042         Vector<CompositionUnderline> emptyUnderlines;
1043         editor->setComposition(emptyString, emptyUnderlines, 0, 0);
1044     } else {
1045         // A browser process sent an IPC message which contains a string to be
1046         // displayed in this Editor object.
1047         // To display the given string, set the given string to the
1048         // m_compositionNode member of this Editor object and display it.
1049         if (targetStart < 0)
1050             targetStart = 0;
1051         if (targetEnd < 0)
1052             targetEnd = static_cast<int>(imeString.length());
1053         String compositionString(imeString);
1054         // Create custom underlines.
1055         // To emphasize the selection, the selected region uses a solid black
1056         // for its underline while other regions uses a pale gray for theirs.
1057         Vector<CompositionUnderline> underlines(3);
1058         underlines[0].startOffset = 0;
1059         underlines[0].endOffset = targetStart;
1060         underlines[0].thick = true;
1061         underlines[0].color.setRGB(0xd3, 0xd3, 0xd3);
1062         underlines[1].startOffset = targetStart;
1063         underlines[1].endOffset = targetEnd;
1064         underlines[1].thick = true;
1065         underlines[1].color.setRGB(0x00, 0x00, 0x00);
1066         underlines[2].startOffset = targetEnd;
1067         underlines[2].endOffset = static_cast<int>(imeString.length());
1068         underlines[2].thick = true;
1069         underlines[2].color.setRGB(0xd3, 0xd3, 0xd3);
1070         // When we use custom underlines, WebKit ("InlineTextBox.cpp" Line 282)
1071         // prevents from writing a text in between 'selectionStart' and
1072         // 'selectionEnd' somehow.
1073         // Therefore, we use the 'cursorPosition' for these arguments so that
1074         // there are not any characters in the above region.
1075         editor->setComposition(compositionString, underlines,
1076                                cursorPosition, cursorPosition);
1077         // The given string is a result string, which means the ongoing
1078         // composition has been completed. I have to call the
1079         // Editor::confirmCompletion() and complete this composition.
1080         if (command == WebCompositionCommandConfirm)
1081             editor->confirmComposition();
1082     }
1083 
1084     return editor->hasComposition();
1085 }
1086 
queryCompositionStatus(bool * enableIME,WebRect * caretRect)1087 bool WebViewImpl::queryCompositionStatus(bool* enableIME, WebRect* caretRect)
1088 {
1089     // Store whether the selected node needs IME and the caret rectangle.
1090     // This process consists of the following four steps:
1091     //  1. Retrieve the selection controller of the focused frame;
1092     //  2. Retrieve the caret rectangle from the controller;
1093     //  3. Convert the rectangle, which is relative to the parent view, to the
1094     //     one relative to the client window, and;
1095     //  4. Store the converted rectangle.
1096     const Frame* focused = focusedWebCoreFrame();
1097     if (!focused)
1098         return false;
1099 
1100     const Editor* editor = focused->editor();
1101     if (!editor || !editor->canEdit())
1102         return false;
1103 
1104     SelectionController* controller = focused->selection();
1105     if (!controller)
1106         return false;
1107 
1108     const Node* node = controller->start().node();
1109     if (!node)
1110         return false;
1111 
1112     *enableIME = node->shouldUseInputMethod() && !controller->isInPasswordField();
1113     const FrameView* view = node->document()->view();
1114     if (!view)
1115         return false;
1116 
1117     *caretRect = view->contentsToWindow(controller->absoluteCaretBounds());
1118     return true;
1119 }
1120 
setTextDirection(WebTextDirection direction)1121 void WebViewImpl::setTextDirection(WebTextDirection direction)
1122 {
1123     // The Editor::setBaseWritingDirection() function checks if we can change
1124     // the text direction of the selected node and updates its DOM "dir"
1125     // attribute and its CSS "direction" property.
1126     // So, we just call the function as Safari does.
1127     const Frame* focused = focusedWebCoreFrame();
1128     if (!focused)
1129         return;
1130 
1131     Editor* editor = focused->editor();
1132     if (!editor || !editor->canEdit())
1133         return;
1134 
1135     switch (direction) {
1136     case WebTextDirectionDefault:
1137         editor->setBaseWritingDirection(NaturalWritingDirection);
1138         break;
1139 
1140     case WebTextDirectionLeftToRight:
1141         editor->setBaseWritingDirection(LeftToRightWritingDirection);
1142         break;
1143 
1144     case WebTextDirectionRightToLeft:
1145         editor->setBaseWritingDirection(RightToLeftWritingDirection);
1146         break;
1147 
1148     default:
1149         notImplemented();
1150         break;
1151     }
1152 }
1153 
1154 // WebView --------------------------------------------------------------------
1155 
settings()1156 WebSettings* WebViewImpl::settings()
1157 {
1158     if (!m_webSettings.get())
1159         m_webSettings.set(new WebSettingsImpl(m_page->settings()));
1160     ASSERT(m_webSettings.get());
1161     return m_webSettings.get();
1162 }
1163 
pageEncoding() const1164 WebString WebViewImpl::pageEncoding() const
1165 {
1166     if (!m_page.get())
1167         return WebString();
1168 
1169     return m_page->mainFrame()->loader()->encoding();
1170 }
1171 
setPageEncoding(const WebString & encodingName)1172 void WebViewImpl::setPageEncoding(const WebString& encodingName)
1173 {
1174     if (!m_page.get())
1175         return;
1176 
1177     // Only change override encoding, don't change default encoding.
1178     // Note that the new encoding must be 0 if it isn't supposed to be set.
1179     String newEncodingName;
1180     if (!encodingName.isEmpty())
1181         newEncodingName = encodingName;
1182     m_page->mainFrame()->loader()->reloadWithOverrideEncoding(newEncodingName);
1183 }
1184 
dispatchBeforeUnloadEvent()1185 bool WebViewImpl::dispatchBeforeUnloadEvent()
1186 {
1187     // FIXME: This should really cause a recursive depth-first walk of all
1188     // frames in the tree, calling each frame's onbeforeunload.  At the moment,
1189     // we're consistent with Safari 3.1, not IE/FF.
1190     Frame* frame = m_page->mainFrame();
1191     if (!frame)
1192         return true;
1193 
1194     return frame->shouldClose();
1195 }
1196 
dispatchUnloadEvent()1197 void WebViewImpl::dispatchUnloadEvent()
1198 {
1199     // Run unload handlers.
1200     m_page->mainFrame()->loader()->closeURL();
1201 }
1202 
mainFrame()1203 WebFrame* WebViewImpl::mainFrame()
1204 {
1205     return mainFrameImpl();
1206 }
1207 
findFrameByName(const WebString & name,WebFrame * relativeToFrame)1208 WebFrame* WebViewImpl::findFrameByName(
1209     const WebString& name, WebFrame* relativeToFrame)
1210 {
1211     if (!relativeToFrame)
1212         relativeToFrame = mainFrame();
1213     Frame* frame = static_cast<WebFrameImpl*>(relativeToFrame)->frame();
1214     frame = frame->tree()->find(name);
1215     return WebFrameImpl::fromFrame(frame);
1216 }
1217 
focusedFrame()1218 WebFrame* WebViewImpl::focusedFrame()
1219 {
1220     return WebFrameImpl::fromFrame(focusedWebCoreFrame());
1221 }
1222 
setFocusedFrame(WebFrame * frame)1223 void WebViewImpl::setFocusedFrame(WebFrame* frame)
1224 {
1225     if (!frame) {
1226         // Clears the focused frame if any.
1227         Frame* frame = focusedWebCoreFrame();
1228         if (frame)
1229             frame->selection()->setFocused(false);
1230         return;
1231     }
1232     WebFrameImpl* frameImpl = static_cast<WebFrameImpl*>(frame);
1233     Frame* webcoreFrame = frameImpl->frame();
1234     webcoreFrame->page()->focusController()->setFocusedFrame(webcoreFrame);
1235 }
1236 
setInitialFocus(bool reverse)1237 void WebViewImpl::setInitialFocus(bool reverse)
1238 {
1239     if (!m_page.get())
1240         return;
1241 
1242     // Since we don't have a keyboard event, we'll create one.
1243     WebKeyboardEvent keyboardEvent;
1244     keyboardEvent.type = WebInputEvent::RawKeyDown;
1245     if (reverse)
1246         keyboardEvent.modifiers = WebInputEvent::ShiftKey;
1247 
1248     // VK_TAB which is only defined on Windows.
1249     keyboardEvent.windowsKeyCode = 0x09;
1250     PlatformKeyboardEventBuilder platformEvent(keyboardEvent);
1251     RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0);
1252     page()->focusController()->setInitialFocus(
1253         reverse ? FocusDirectionBackward : FocusDirectionForward,
1254         webkitEvent.get());
1255 }
1256 
clearFocusedNode()1257 void WebViewImpl::clearFocusedNode()
1258 {
1259     if (!m_page.get())
1260         return;
1261 
1262     RefPtr<Frame> frame = m_page->mainFrame();
1263     if (!frame.get())
1264         return;
1265 
1266     RefPtr<Document> document = frame->document();
1267     if (!document.get())
1268         return;
1269 
1270     RefPtr<Node> oldFocusedNode = document->focusedNode();
1271 
1272     // Clear the focused node.
1273     document->setFocusedNode(0);
1274 
1275     if (!oldFocusedNode.get())
1276         return;
1277 
1278     // If a text field has focus, we need to make sure the selection controller
1279     // knows to remove selection from it. Otherwise, the text field is still
1280     // processing keyboard events even though focus has been moved to the page and
1281     // keystrokes get eaten as a result.
1282     if (oldFocusedNode->hasTagName(HTMLNames::textareaTag)
1283         || (oldFocusedNode->hasTagName(HTMLNames::inputTag)
1284             && static_cast<HTMLInputElement*>(oldFocusedNode.get())->isTextField())) {
1285         // Clear the selection.
1286         SelectionController* selection = frame->selection();
1287         selection->clear();
1288     }
1289 }
1290 
zoomLevel()1291 int WebViewImpl::zoomLevel()
1292 {
1293     return m_zoomLevel;
1294 }
1295 
setZoomLevel(bool textOnly,int zoomLevel)1296 int WebViewImpl::setZoomLevel(bool textOnly, int zoomLevel)
1297 {
1298     float zoomFactor = static_cast<float>(
1299         std::max(std::min(std::pow(textSizeMultiplierRatio, zoomLevel),
1300                           maxTextSizeMultiplier),
1301                  minTextSizeMultiplier));
1302     Frame* frame = mainFrameImpl()->frame();
1303     if (zoomFactor != frame->zoomFactor()) {
1304         m_zoomLevel = zoomLevel;
1305         frame->setZoomFactor(zoomFactor, textOnly);
1306     }
1307     return m_zoomLevel;
1308 }
1309 
performMediaPlayerAction(const WebMediaPlayerAction & action,const WebPoint & location)1310 void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action,
1311                                            const WebPoint& location)
1312 {
1313     HitTestResult result =
1314         hitTestResultForWindowPos(location);
1315     RefPtr<Node> node = result.innerNonSharedNode();
1316     if (!node->hasTagName(HTMLNames::videoTag) && !node->hasTagName(HTMLNames::audioTag))
1317       return;
1318 
1319     RefPtr<HTMLMediaElement> mediaElement =
1320         static_pointer_cast<HTMLMediaElement>(node);
1321     switch (action.type) {
1322     case WebMediaPlayerAction::Play:
1323         if (action.enable)
1324             mediaElement->play(mediaElement->processingUserGesture());
1325         else
1326             mediaElement->pause(mediaElement->processingUserGesture());
1327         break;
1328     case WebMediaPlayerAction::Mute:
1329         mediaElement->setMuted(action.enable);
1330         break;
1331     case WebMediaPlayerAction::Loop:
1332         mediaElement->setLoop(action.enable);
1333         break;
1334     default:
1335         ASSERT_NOT_REACHED();
1336     }
1337 }
1338 
copyImageAt(const WebPoint & point)1339 void WebViewImpl::copyImageAt(const WebPoint& point)
1340 {
1341     if (!m_page.get())
1342         return;
1343 
1344     HitTestResult result = hitTestResultForWindowPos(point);
1345 
1346     if (result.absoluteImageURL().isEmpty()) {
1347         // There isn't actually an image at these coordinates.  Might be because
1348         // the window scrolled while the context menu was open or because the page
1349         // changed itself between when we thought there was an image here and when
1350         // we actually tried to retreive the image.
1351         //
1352         // FIXME: implement a cache of the most recent HitTestResult to avoid having
1353         //        to do two hit tests.
1354         return;
1355     }
1356 
1357     m_page->mainFrame()->editor()->copyImage(result);
1358 }
1359 
dragSourceEndedAt(const WebPoint & clientPoint,const WebPoint & screenPoint,WebDragOperation operation)1360 void WebViewImpl::dragSourceEndedAt(
1361     const WebPoint& clientPoint,
1362     const WebPoint& screenPoint,
1363     WebDragOperation operation)
1364 {
1365     PlatformMouseEvent pme(clientPoint,
1366                            screenPoint,
1367                            LeftButton, MouseEventMoved, 0, false, false, false,
1368                            false, 0);
1369     m_page->mainFrame()->eventHandler()->dragSourceEndedAt(pme,
1370         static_cast<DragOperation>(operation));
1371 }
1372 
dragSourceSystemDragEnded()1373 void WebViewImpl::dragSourceSystemDragEnded()
1374 {
1375     // It's possible for us to get this callback while not doing a drag if
1376     // it's from a previous page that got unloaded.
1377     if (m_doingDragAndDrop) {
1378         m_page->dragController()->dragEnded();
1379         m_doingDragAndDrop = false;
1380     }
1381 }
1382 
dragTargetDragEnter(const WebDragData & webDragData,int identity,const WebPoint & clientPoint,const WebPoint & screenPoint,WebDragOperationsMask operationsAllowed)1383 WebDragOperation WebViewImpl::dragTargetDragEnter(
1384     const WebDragData& webDragData, int identity,
1385     const WebPoint& clientPoint,
1386     const WebPoint& screenPoint,
1387     WebDragOperationsMask operationsAllowed)
1388 {
1389     ASSERT(!m_currentDragData.get());
1390 
1391     m_currentDragData = webDragData;
1392     m_dragIdentity = identity;
1393     m_operationsAllowed = operationsAllowed;
1394 
1395     DragData dragData(
1396         m_currentDragData.get(),
1397         clientPoint,
1398         screenPoint,
1399         static_cast<DragOperation>(operationsAllowed));
1400 
1401     m_dropEffect = DropEffectDefault;
1402     m_dragTargetDispatch = true;
1403     DragOperation effect = m_page->dragController()->dragEntered(&dragData);
1404     // Mask the operation against the drag source's allowed operations.
1405     if ((effect & dragData.draggingSourceOperationMask()) != effect)
1406         effect = DragOperationNone;
1407     m_dragTargetDispatch = false;
1408 
1409     if (m_dropEffect != DropEffectDefault) {
1410         m_dragOperation = (m_dropEffect != DropEffectNone) ? WebDragOperationCopy
1411                                                            : WebDragOperationNone;
1412     } else
1413         m_dragOperation = static_cast<WebDragOperation>(effect);
1414     return m_dragOperation;
1415 }
1416 
dragTargetDragOver(const WebPoint & clientPoint,const WebPoint & screenPoint,WebDragOperationsMask operationsAllowed)1417 WebDragOperation WebViewImpl::dragTargetDragOver(
1418     const WebPoint& clientPoint,
1419     const WebPoint& screenPoint,
1420     WebDragOperationsMask operationsAllowed)
1421 {
1422     ASSERT(m_currentDragData.get());
1423 
1424     m_operationsAllowed = operationsAllowed;
1425     DragData dragData(
1426         m_currentDragData.get(),
1427         clientPoint,
1428         screenPoint,
1429         static_cast<DragOperation>(operationsAllowed));
1430 
1431     m_dropEffect = DropEffectDefault;
1432     m_dragTargetDispatch = true;
1433     DragOperation effect = m_page->dragController()->dragUpdated(&dragData);
1434     // Mask the operation against the drag source's allowed operations.
1435     if ((effect & dragData.draggingSourceOperationMask()) != effect)
1436         effect = DragOperationNone;
1437     m_dragTargetDispatch = false;
1438 
1439     if (m_dropEffect != DropEffectDefault) {
1440         m_dragOperation = (m_dropEffect != DropEffectNone) ? WebDragOperationCopy
1441                                                            : WebDragOperationNone;
1442     } else
1443         m_dragOperation = static_cast<WebDragOperation>(effect);
1444     return m_dragOperation;
1445 }
1446 
dragTargetDragLeave()1447 void WebViewImpl::dragTargetDragLeave()
1448 {
1449     ASSERT(m_currentDragData.get());
1450 
1451     DragData dragData(
1452         m_currentDragData.get(),
1453         IntPoint(),
1454         IntPoint(),
1455         static_cast<DragOperation>(m_operationsAllowed));
1456 
1457     m_dragTargetDispatch = true;
1458     m_page->dragController()->dragExited(&dragData);
1459     m_dragTargetDispatch = false;
1460 
1461     m_currentDragData = 0;
1462     m_dropEffect = DropEffectDefault;
1463     m_dragOperation = WebDragOperationNone;
1464     m_dragIdentity = 0;
1465 }
1466 
dragTargetDrop(const WebPoint & clientPoint,const WebPoint & screenPoint)1467 void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint,
1468                                  const WebPoint& screenPoint)
1469 {
1470     ASSERT(m_currentDragData.get());
1471 
1472     // If this webview transitions from the "drop accepting" state to the "not
1473     // accepting" state, then our IPC message reply indicating that may be in-
1474     // flight, or else delayed by javascript processing in this webview.  If a
1475     // drop happens before our IPC reply has reached the browser process, then
1476     // the browser forwards the drop to this webview.  So only allow a drop to
1477     // proceed if our webview m_dragOperation state is not DragOperationNone.
1478 
1479     if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop.
1480         dragTargetDragLeave();
1481         return;
1482     }
1483 
1484     DragData dragData(
1485         m_currentDragData.get(),
1486         clientPoint,
1487         screenPoint,
1488         static_cast<DragOperation>(m_operationsAllowed));
1489 
1490     m_dragTargetDispatch = true;
1491     m_page->dragController()->performDrag(&dragData);
1492     m_dragTargetDispatch = false;
1493 
1494     m_currentDragData = 0;
1495     m_dropEffect = DropEffectDefault;
1496     m_dragOperation = WebDragOperationNone;
1497     m_dragIdentity = 0;
1498 }
1499 
dragIdentity()1500 int WebViewImpl::dragIdentity()
1501 {
1502     if (m_dragTargetDispatch)
1503         return m_dragIdentity;
1504     return 0;
1505 }
1506 
createUniqueIdentifierForRequest()1507 unsigned long WebViewImpl::createUniqueIdentifierForRequest() {
1508     if (m_page)
1509         return m_page->progress()->createUniqueIdentifier();
1510     return 0;
1511 }
1512 
inspectElementAt(const WebPoint & point)1513 void WebViewImpl::inspectElementAt(const WebPoint& point)
1514 {
1515     if (!m_page.get())
1516         return;
1517 
1518     if (point.x == -1 || point.y == -1)
1519         m_page->inspectorController()->inspect(0);
1520     else {
1521         HitTestResult result = hitTestResultForWindowPos(point);
1522 
1523         if (!result.innerNonSharedNode())
1524             return;
1525 
1526         m_page->inspectorController()->inspect(result.innerNonSharedNode());
1527     }
1528 }
1529 
inspectorSettings() const1530 WebString WebViewImpl::inspectorSettings() const
1531 {
1532     return m_inspectorSettings;
1533 }
1534 
setInspectorSettings(const WebString & settings)1535 void WebViewImpl::setInspectorSettings(const WebString& settings)
1536 {
1537     m_inspectorSettings = settings;
1538 }
1539 
devToolsAgent()1540 WebDevToolsAgent* WebViewImpl::devToolsAgent()
1541 {
1542     return m_devToolsAgent.get();
1543 }
1544 
setDevToolsAgent(WebDevToolsAgent * devToolsAgent)1545 void WebViewImpl::setDevToolsAgent(WebDevToolsAgent* devToolsAgent)
1546 {
1547     ASSERT(!m_devToolsAgent.get()); // May only set once!
1548     m_devToolsAgent.set(static_cast<WebDevToolsAgentPrivate*>(devToolsAgent));
1549 }
1550 
accessibilityObject()1551 WebAccessibilityObject WebViewImpl::accessibilityObject()
1552 {
1553     if (!mainFrameImpl())
1554         return WebAccessibilityObject();
1555 
1556     Document* document = mainFrameImpl()->frame()->document();
1557     return WebAccessibilityObject(
1558         document->axObjectCache()->getOrCreate(document->renderer()));
1559 }
1560 
applyAutofillSuggestions(const WebNode & node,const WebVector<WebString> & suggestions,int defaultSuggestionIndex)1561 void WebViewImpl::applyAutofillSuggestions(
1562     const WebNode& node,
1563     const WebVector<WebString>& suggestions,
1564     int defaultSuggestionIndex)
1565 {
1566     applyAutocompleteSuggestions(node, suggestions, defaultSuggestionIndex);
1567 }
1568 
applyAutoFillSuggestions(const WebNode & node,const WebVector<WebString> & names,const WebVector<WebString> & labels,int defaultSuggestionIndex)1569 void WebViewImpl::applyAutoFillSuggestions(
1570     const WebNode& node,
1571     const WebVector<WebString>& names,
1572     const WebVector<WebString>& labels,
1573     int defaultSuggestionIndex)
1574 {
1575     ASSERT(names.size() == labels.size());
1576     ASSERT(defaultSuggestionIndex < static_cast<int>(names.size()));
1577 
1578     if (names.isEmpty()) {
1579         hideSuggestionsPopup();
1580         return;
1581     }
1582 
1583     RefPtr<Node> focusedNode = focusedWebCoreNode();
1584     // If the node for which we queried the AutoFill suggestions is not the
1585     // focused node, then we have nothing to do.  FIXME: also check the
1586     // caret is at the end and that the text has not changed.
1587     if (!focusedNode || focusedNode != PassRefPtr<Node>(node)) {
1588         hideSuggestionsPopup();
1589         return;
1590     }
1591 
1592     HTMLInputElement* inputElem =
1593         static_cast<HTMLInputElement*>(focusedNode.get());
1594 
1595     // The first time the AutoFill popup is shown we'll create the client and
1596     // the popup.
1597     if (!m_autoFillPopupClient.get())
1598         m_autoFillPopupClient.set(new AutoFillPopupMenuClient);
1599 
1600     m_autoFillPopupClient->initialize(inputElem, names, labels,
1601                                       defaultSuggestionIndex);
1602 
1603     if (m_suggestionsPopupClient != m_autoFillPopupClient.get()) {
1604         hideSuggestionsPopup();
1605         m_suggestionsPopupClient = m_autoFillPopupClient.get();
1606     }
1607 
1608     if (!m_autoFillPopup.get()) {
1609         m_autoFillPopup = PopupContainer::create(m_suggestionsPopupClient,
1610                                                  suggestionsPopupSettings);
1611     }
1612 
1613     if (m_suggestionsPopup != m_autoFillPopup.get())
1614         m_suggestionsPopup = m_autoFillPopup.get();
1615 
1616     if (m_suggestionsPopupShowing) {
1617         m_autoFillPopupClient->setSuggestions(names, labels);
1618         refreshSuggestionsPopup();
1619     } else {
1620         m_suggestionsPopup->show(focusedNode->getRect(),
1621                                  focusedNode->ownerDocument()->view(), 0);
1622         m_suggestionsPopupShowing = true;
1623     }
1624 }
1625 
applyAutocompleteSuggestions(const WebNode & node,const WebVector<WebString> & suggestions,int defaultSuggestionIndex)1626 void WebViewImpl::applyAutocompleteSuggestions(
1627     const WebNode& node,
1628     const WebVector<WebString>& suggestions,
1629     int defaultSuggestionIndex)
1630 {
1631     ASSERT(defaultSuggestionIndex < static_cast<int>(suggestions.size()));
1632 
1633     if (!m_page.get() || suggestions.isEmpty()) {
1634         hideSuggestionsPopup();
1635         return;
1636     }
1637 
1638     RefPtr<Node> focusedNode = focusedWebCoreNode();
1639     // If the node for which we queried the Autocomplete suggestions is not the
1640     // focused node, then we have nothing to do.  FIXME: also check the
1641     // caret is at the end and that the text has not changed.
1642     if (!focusedNode || focusedNode != PassRefPtr<Node>(node)) {
1643         hideSuggestionsPopup();
1644         return;
1645     }
1646 
1647     HTMLInputElement* inputElem =
1648         static_cast<HTMLInputElement*>(focusedNode.get());
1649 
1650     // The first time the Autocomplete is shown we'll create the client and the
1651     // popup.
1652     if (!m_autocompletePopupClient.get())
1653         m_autocompletePopupClient.set(new AutocompletePopupMenuClient);
1654 
1655     m_autocompletePopupClient->initialize(inputElem, suggestions,
1656                                           defaultSuggestionIndex);
1657 
1658     if (m_suggestionsPopupClient != m_autocompletePopupClient.get()) {
1659         hideSuggestionsPopup();
1660         m_suggestionsPopupClient = m_autocompletePopupClient.get();
1661     }
1662 
1663     if (!m_autocompletePopup.get()) {
1664         m_autocompletePopup = PopupContainer::create(m_suggestionsPopupClient,
1665                                                      suggestionsPopupSettings);
1666     }
1667 
1668     if (m_suggestionsPopup != m_autocompletePopup.get())
1669         m_suggestionsPopup = m_autocompletePopup.get();
1670 
1671     if (m_suggestionsPopupShowing) {
1672         m_autocompletePopupClient->setSuggestions(suggestions);
1673         refreshSuggestionsPopup();
1674     } else {
1675         m_suggestionsPopup->show(focusedNode->getRect(),
1676                                  focusedNode->ownerDocument()->view(), 0);
1677         m_suggestionsPopupShowing = true;
1678     }
1679 }
1680 
hideAutofillPopup()1681 void WebViewImpl::hideAutofillPopup()
1682 {
1683     hideSuggestionsPopup();
1684 }
1685 
hideSuggestionsPopup()1686 void WebViewImpl::hideSuggestionsPopup()
1687 {
1688     if (m_suggestionsPopupShowing) {
1689         m_suggestionsPopup->hidePopup();
1690         m_suggestionsPopupShowing = false;
1691     }
1692 }
1693 
performCustomContextMenuAction(unsigned action)1694 void WebViewImpl::performCustomContextMenuAction(unsigned action)
1695 {
1696     if (!m_page)
1697         return;
1698     ContextMenu* menu = m_page->contextMenuController()->contextMenu();
1699     if (!menu)
1700         return;
1701     ContextMenuItem* item = menu->itemWithAction(static_cast<ContextMenuAction>(ContextMenuItemBaseCustomTag + action));
1702     if (item)
1703         m_page->contextMenuController()->contextMenuItemSelected(item);
1704     m_page->contextMenuController()->clearContextMenu();
1705 }
1706 
1707 // WebView --------------------------------------------------------------------
1708 
setDropEffect(bool accept)1709 bool WebViewImpl::setDropEffect(bool accept)
1710 {
1711     if (m_dragTargetDispatch) {
1712         m_dropEffect = accept ? DropEffectCopy : DropEffectNone;
1713         return true;
1714     }
1715     return false;
1716 }
1717 
setIsTransparent(bool isTransparent)1718 void WebViewImpl::setIsTransparent(bool isTransparent)
1719 {
1720     // Set any existing frames to be transparent.
1721     Frame* frame = m_page->mainFrame();
1722     while (frame) {
1723         frame->view()->setTransparent(isTransparent);
1724         frame = frame->tree()->traverseNext();
1725     }
1726 
1727     // Future frames check this to know whether to be transparent.
1728     m_isTransparent = isTransparent;
1729 }
1730 
isTransparent() const1731 bool WebViewImpl::isTransparent() const
1732 {
1733     return m_isTransparent;
1734 }
1735 
setIsActive(bool active)1736 void WebViewImpl::setIsActive(bool active)
1737 {
1738     if (page() && page()->focusController())
1739         page()->focusController()->setActive(active);
1740 }
1741 
isActive() const1742 bool WebViewImpl::isActive() const
1743 {
1744     return (page() && page()->focusController()) ? page()->focusController()->isActive() : false;
1745 }
1746 
setScrollbarColors(unsigned inactiveColor,unsigned activeColor,unsigned trackColor)1747 void WebViewImpl::setScrollbarColors(unsigned inactiveColor,
1748                                      unsigned activeColor,
1749                                      unsigned trackColor) {
1750 #if OS(LINUX)
1751     RenderThemeChromiumLinux::setScrollbarColors(inactiveColor,
1752                                                  activeColor,
1753                                                  trackColor);
1754 #endif
1755 }
1756 
setSelectionColors(unsigned activeBackgroundColor,unsigned activeForegroundColor,unsigned inactiveBackgroundColor,unsigned inactiveForegroundColor)1757 void WebViewImpl::setSelectionColors(unsigned activeBackgroundColor,
1758                                      unsigned activeForegroundColor,
1759                                      unsigned inactiveBackgroundColor,
1760                                      unsigned inactiveForegroundColor) {
1761 #if OS(LINUX)
1762     RenderThemeChromiumLinux::setSelectionColors(activeBackgroundColor,
1763                                                  activeForegroundColor,
1764                                                  inactiveBackgroundColor,
1765                                                  inactiveForegroundColor);
1766     theme()->platformColorsDidChange();
1767 #endif
1768 }
1769 
addUserScript(const WebString & sourceCode,bool runAtStart)1770 void WebViewImpl::addUserScript(const WebString& sourceCode, bool runAtStart)
1771 {
1772     PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
1773     RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create());
1774     pageGroup->addUserScriptToWorld(world.get(), sourceCode, WebURL(), 0, 0,
1775                                     runAtStart ? InjectAtDocumentStart : InjectAtDocumentEnd);
1776 }
1777 
removeAllUserContent()1778 void WebViewImpl::removeAllUserContent()
1779 {
1780     PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
1781     pageGroup->removeAllUserContent();
1782 }
1783 
didCommitLoad(bool * isNewNavigation)1784 void WebViewImpl::didCommitLoad(bool* isNewNavigation)
1785 {
1786     if (isNewNavigation)
1787         *isNewNavigation = m_observedNewNavigation;
1788 
1789 #ifndef NDEBUG
1790     ASSERT(!m_observedNewNavigation
1791         || m_page->mainFrame()->loader()->documentLoader() == m_newNavigationLoader);
1792     m_newNavigationLoader = 0;
1793 #endif
1794     m_observedNewNavigation = false;
1795 }
1796 
navigationPolicyFromMouseEvent(unsigned short button,bool ctrl,bool shift,bool alt,bool meta,WebNavigationPolicy * policy)1797 bool WebViewImpl::navigationPolicyFromMouseEvent(unsigned short button,
1798                                                  bool ctrl, bool shift,
1799                                                  bool alt, bool meta,
1800                                                  WebNavigationPolicy* policy)
1801 {
1802 #if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD)
1803     const bool newTabModifier = (button == 1) || ctrl;
1804 #elif OS(DARWIN)
1805     const bool newTabModifier = (button == 1) || meta;
1806 #endif
1807     if (!newTabModifier && !shift && !alt)
1808       return false;
1809 
1810     ASSERT(policy);
1811     if (newTabModifier) {
1812         if (shift)
1813           *policy = WebNavigationPolicyNewForegroundTab;
1814         else
1815           *policy = WebNavigationPolicyNewBackgroundTab;
1816     } else {
1817         if (shift)
1818           *policy = WebNavigationPolicyNewWindow;
1819         else
1820           *policy = WebNavigationPolicyDownload;
1821     }
1822     return true;
1823 }
1824 
startDragging(const WebPoint & eventPos,const WebDragData & dragData,WebDragOperationsMask mask)1825 void WebViewImpl::startDragging(const WebPoint& eventPos,
1826                                 const WebDragData& dragData,
1827                                 WebDragOperationsMask mask)
1828 {
1829     if (!m_client)
1830         return;
1831     ASSERT(!m_doingDragAndDrop);
1832     m_doingDragAndDrop = true;
1833     m_client->startDragging(eventPos, dragData, mask);
1834 }
1835 
setCurrentHistoryItem(HistoryItem * item)1836 void WebViewImpl::setCurrentHistoryItem(HistoryItem* item)
1837 {
1838     m_backForwardListClientImpl.setCurrentHistoryItem(item);
1839 }
1840 
previousHistoryItem()1841 HistoryItem* WebViewImpl::previousHistoryItem()
1842 {
1843     return m_backForwardListClientImpl.previousHistoryItem();
1844 }
1845 
observeNewNavigation()1846 void WebViewImpl::observeNewNavigation()
1847 {
1848     m_observedNewNavigation = true;
1849 #ifndef NDEBUG
1850     m_newNavigationLoader = m_page->mainFrame()->loader()->documentLoader();
1851 #endif
1852 }
1853 
setIgnoreInputEvents(bool newValue)1854 void WebViewImpl::setIgnoreInputEvents(bool newValue)
1855 {
1856     ASSERT(m_ignoreInputEvents != newValue);
1857     m_ignoreInputEvents = newValue;
1858 }
1859 
1860 #if ENABLE(NOTIFICATIONS)
notificationPresenterImpl()1861 NotificationPresenterImpl* WebViewImpl::notificationPresenterImpl()
1862 {
1863     if (!m_notificationPresenter.isInitialized() && m_client)
1864         m_notificationPresenter.initialize(m_client->notificationPresenter());
1865     return &m_notificationPresenter;
1866 }
1867 #endif
1868 
refreshSuggestionsPopup()1869 void WebViewImpl::refreshSuggestionsPopup()
1870 {
1871     ASSERT(m_suggestionsPopupShowing);
1872 
1873     // Hide the popup if it has become empty.
1874     if (!m_autocompletePopupClient->listSize()) {
1875         hideSuggestionsPopup();
1876         return;
1877     }
1878 
1879     IntRect oldBounds = m_suggestionsPopup->boundsRect();
1880     m_suggestionsPopup->refresh();
1881     IntRect newBounds = m_suggestionsPopup->boundsRect();
1882     // Let's resize the backing window if necessary.
1883     if (oldBounds != newBounds) {
1884         WebPopupMenuImpl* popupMenu =
1885             static_cast<WebPopupMenuImpl*>(m_suggestionsPopup->client());
1886         popupMenu->client()->setWindowRect(newBounds);
1887     }
1888 }
1889 
focusedWebCoreNode()1890 Node* WebViewImpl::focusedWebCoreNode()
1891 {
1892     Frame* frame = m_page->focusController()->focusedFrame();
1893     if (!frame)
1894         return 0;
1895 
1896     Document* document = frame->document();
1897     if (!document)
1898         return 0;
1899 
1900     return document->focusedNode();
1901 }
1902 
hitTestResultForWindowPos(const IntPoint & pos)1903 HitTestResult WebViewImpl::hitTestResultForWindowPos(const IntPoint& pos)
1904 {
1905     IntPoint docPoint(m_page->mainFrame()->view()->windowToContents(pos));
1906     return m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(docPoint, false);
1907 }
1908 
setTabsToLinks(bool enable)1909 void WebViewImpl::setTabsToLinks(bool enable)
1910 {
1911     m_tabsToLinks = enable;
1912 }
1913 
tabsToLinks() const1914 bool WebViewImpl::tabsToLinks() const
1915 {
1916     return m_tabsToLinks;
1917 }
1918 
1919 } // namespace WebKit
1920