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