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