| /* |
| * Copyright 2007 Google Inc. All Rights Reserved. |
| * |
| * Portions Copyright (C) 2006 Apple Computer, Inc. All rights reserved. |
| * |
| * ***** BEGIN LICENSE BLOCK ***** |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * ***** END LICENSE BLOCK ***** |
| * |
| */ |
| |
| #include "config.h" |
| #include "build/build_config.h" |
| |
| #include "base/compiler_specific.h" |
| MSVC_PUSH_WARNING_LEVEL(0); |
| #include "CSSStyleSelector.h" |
| #include "CSSValueKeywords.h" |
| #include "Cursor.h" |
| #include "Document.h" |
| #include "DocumentLoader.h" |
| #include "DragController.h" |
| #include "DragData.h" |
| #include "Editor.h" |
| #include "EventHandler.h" |
| #include "FocusController.h" |
| #include "FontDescription.h" |
| #include "FrameLoader.h" |
| #include "FrameTree.h" |
| #include "FrameView.h" |
| #include "GraphicsContext.h" |
| #include "HTMLNames.h" |
| #include "HTMLInputElement.h" |
| #include "HitTestResult.h" |
| #include "Image.h" |
| #include "InspectorController.h" |
| #include "IntRect.h" |
| #include "KeyboardCodes.h" |
| #include "KeyboardEvent.h" |
| #include "MIMETypeRegistry.h" |
| #include "NodeRenderStyle.h" |
| #include "Page.h" |
| #include "PlatformContextSkia.h" |
| #include "PlatformKeyboardEvent.h" |
| #include "PlatformMouseEvent.h" |
| #include "PlatformWheelEvent.h" |
| #include "PluginInfoStore.h" |
| #include "PopupMenuChromium.h" |
| #include "PopupMenuClient.h" |
| #if defined(OS_WIN) |
| #include "RenderThemeChromiumWin.h" |
| #else |
| #include "RenderTheme.h" |
| #endif |
| #include "RenderView.h" |
| #include "ResourceHandle.h" |
| #include "SelectionController.h" |
| #include "Settings.h" |
| #include "TypingCommand.h" |
| MSVC_POP_WARNING(); |
| #undef LOG |
| |
| #include "base/gfx/rect.h" |
| #include "base/keyboard_codes.h" |
| #include "base/logging.h" |
| #include "base/message_loop.h" |
| #include "base/string_util.h" |
| #include "webkit/api/public/WebDragData.h" |
| #include "webkit/api/public/WebInputEvent.h" |
| #include "webkit/api/public/WebPoint.h" |
| #include "webkit/api/public/WebRect.h" |
| #include "webkit/glue/chrome_client_impl.h" |
| #include "webkit/glue/context_menu_client_impl.h" |
| #include "webkit/glue/dom_operations.h" |
| #include "webkit/glue/dragclient_impl.h" |
| #include "webkit/glue/editor_client_impl.h" |
| #include "webkit/glue/event_conversion.h" |
| #include "webkit/glue/glue_serialize.h" |
| #include "webkit/glue/glue_util.h" |
| #include "webkit/glue/image_resource_fetcher.h" |
| #include "webkit/glue/inspector_client_impl.h" |
| #include "webkit/glue/searchable_form_data.h" |
| #include "webkit/glue/webdevtoolsagent_impl.h" |
| #include "webkit/glue/webdropdata.h" |
| #include "webkit/glue/webkit_glue.h" |
| #include "webkit/glue/webpreferences.h" |
| #include "webkit/glue/webdevtoolsagent.h" |
| #include "webkit/glue/webdevtoolsclient.h" |
| #include "webkit/glue/webview_delegate.h" |
| #include "webkit/glue/webview_impl.h" |
| #include "webkit/glue/webwidget_impl.h" |
| |
| // Get rid of WTF's pow define so we can use std::pow. |
| #undef pow |
| #include <cmath> // for std::pow |
| |
| using namespace WebCore; |
| |
| using WebKit::WebDragData; |
| using WebKit::WebInputEvent; |
| using WebKit::WebKeyboardEvent; |
| using WebKit::WebMouseEvent; |
| using WebKit::WebMouseWheelEvent; |
| using WebKit::WebPoint; |
| using WebKit::WebRect; |
| using WebKit::WebSize; |
| |
| // Change the text zoom level by kTextSizeMultiplierRatio each time the user |
| // zooms text in or out (ie., change by 20%). The min and max values limit |
| // text zoom to half and 3x the original text size. These three values match |
| // those in Apple's port in WebKit/WebKit/WebView/WebView.mm |
| static const double kTextSizeMultiplierRatio = 1.2; |
| static const double kMinTextSizeMultiplier = 0.5; |
| static const double kMaxTextSizeMultiplier = 3.0; |
| |
| // The webcore drag operation type when something is trying to be dropped on |
| // the webview. These values are taken from Apple's windows port. |
| static const WebCore::DragOperation kDropTargetOperation = |
| static_cast<WebCore::DragOperation>(DragOperationCopy | DragOperationLink); |
| |
| // AutocompletePopupMenuClient |
| class AutocompletePopupMenuClient : public WebCore::PopupMenuClient { |
| public: |
| AutocompletePopupMenuClient(WebViewImpl* webview) : text_field_(NULL), |
| selected_index_(0), |
| webview_(webview) { |
| } |
| |
| void Init(WebCore::HTMLInputElement* text_field, |
| const std::vector<std::wstring>& suggestions, |
| int default_suggestion_index) { |
| DCHECK(default_suggestion_index < static_cast<int>(suggestions.size())); |
| text_field_ = text_field; |
| selected_index_ = default_suggestion_index; |
| SetSuggestions(suggestions); |
| |
| FontDescription font_description; |
| theme()->systemFont(CSSValueWebkitControl, font_description); |
| // Use a smaller font size to match IE/Firefox. |
| // TODO(jcampan): http://crbug.com/7376 use the system size instead of a |
| // fixed font size value. |
| font_description.setComputedSize(12.0); |
| Font font(font_description, 0, 0); |
| font.update(text_field->document()->styleSelector()->fontSelector()); |
| style_.reset(new PopupMenuStyle(Color::black, Color::white, font, true, |
| Length(WebCore::Fixed), LTR)); |
| } |
| |
| virtual ~AutocompletePopupMenuClient() { |
| } |
| |
| // WebCore::PopupMenuClient implementation. |
| virtual void valueChanged(unsigned listIndex, bool fireEvents = true) { |
| text_field_->setValue(suggestions_[listIndex]); |
| } |
| |
| virtual WebCore::String itemText(unsigned list_index) const { |
| return suggestions_[list_index]; |
| } |
| |
| virtual bool itemIsEnabled(unsigned listIndex) const { |
| return true; |
| } |
| |
| virtual PopupMenuStyle itemStyle(unsigned listIndex) const { |
| return *style_; |
| } |
| |
| virtual PopupMenuStyle menuStyle() const { |
| return *style_; |
| } |
| |
| virtual int clientInsetLeft() const { |
| return 0; |
| } |
| virtual int clientInsetRight() const { |
| return 0; |
| } |
| virtual int clientPaddingLeft() const { |
| // Bug http://crbug.com/7708 seems to indicate the style can be NULL. |
| WebCore::RenderStyle* style = GetTextFieldStyle(); |
| return style ? theme()->popupInternalPaddingLeft(style) : 0; |
| } |
| virtual int clientPaddingRight() const { |
| // Bug http://crbug.com/7708 seems to indicate the style can be NULL. |
| WebCore::RenderStyle* style = GetTextFieldStyle(); |
| return style ? theme()->popupInternalPaddingRight(style) : 0; |
| } |
| virtual int listSize() const { |
| return suggestions_.size(); |
| } |
| virtual int selectedIndex() const { |
| return selected_index_; |
| } |
| virtual void hidePopup() { |
| webview_->HideAutoCompletePopup(); |
| } |
| virtual bool itemIsSeparator(unsigned listIndex) const { |
| return false; |
| } |
| virtual bool itemIsLabel(unsigned listIndex) const { |
| return false; |
| } |
| virtual bool itemIsSelected(unsigned listIndex) const { |
| return false; |
| } |
| virtual bool shouldPopOver() const { |
| return false; |
| } |
| virtual bool valueShouldChangeOnHotTrack() const { |
| return false; |
| } |
| |
| virtual FontSelector* fontSelector() const { |
| return text_field_->document()->styleSelector()->fontSelector(); |
| } |
| |
| virtual void setTextFromItem(unsigned listIndex) { |
| text_field_->setValue(suggestions_[listIndex]); |
| } |
| |
| virtual HostWindow* hostWindow() const { |
| return text_field_->document()->view()->hostWindow(); |
| } |
| |
| virtual PassRefPtr<Scrollbar> createScrollbar( |
| ScrollbarClient* client, |
| ScrollbarOrientation orientation, |
| ScrollbarControlSize size) { |
| RefPtr<Scrollbar> widget = Scrollbar::createNativeScrollbar(client, |
| orientation, |
| size); |
| return widget.release(); |
| } |
| |
| // AutocompletePopupMenuClient specific methods: |
| void SetSuggestions(const std::vector<std::wstring>& suggestions) { |
| suggestions_.clear(); |
| for (std::vector<std::wstring>::const_iterator iter = suggestions.begin(); |
| iter != suggestions.end(); ++iter) { |
| suggestions_.push_back(webkit_glue::StdWStringToString(*iter)); |
| } |
| // Try to preserve selection if possible. |
| if (selected_index_ >= static_cast<int>(suggestions.size())) |
| selected_index_ = -1; |
| } |
| |
| void RemoveItemAtIndex(int index) { |
| DCHECK(index >= 0 && index < static_cast<int>(suggestions_.size())); |
| suggestions_.erase(suggestions_.begin() + index); |
| } |
| |
| WebCore::HTMLInputElement* text_field() const { |
| return text_field_.get(); |
| } |
| |
| WebCore::RenderStyle* GetTextFieldStyle() const { |
| WebCore::RenderStyle* style = text_field_->computedStyle(); |
| if (!style) { |
| // It seems we can only have an NULL style in a TextField if the node is |
| // dettached, in which case we the popup shoud not be showing. |
| NOTREACHED() << "Please report this in http://crbug.com/7708 and include " |
| "the page you were visiting."; |
| } |
| return style; |
| } |
| |
| private: |
| RefPtr<WebCore::HTMLInputElement> text_field_; |
| std::vector<WebCore::String> suggestions_; |
| int selected_index_; |
| WebViewImpl* webview_; |
| scoped_ptr<PopupMenuStyle> style_; |
| }; |
| |
| // Note that focusOnShow is false so that the autocomplete popup is shown not |
| // activated. We need the page to still have focus so the user can keep typing |
| // while the popup is showing. |
| static const WebCore::PopupContainerSettings kAutocompletePopupSettings = { |
| false, // focusOnShow |
| false, // setTextOnIndexChange |
| false, // acceptOnAbandon |
| true, // loopSelectionNavigation |
| }; |
| |
| // WebView ---------------------------------------------------------------- |
| |
| /*static*/ |
| WebView* WebView::Create(WebViewDelegate* delegate, |
| const WebPreferences& prefs) { |
| WebViewImpl* instance = new WebViewImpl(); |
| instance->AddRef(); |
| instance->SetPreferences(prefs); |
| |
| // Here, we construct a new WebFrameImpl with a reference count of 0. That |
| // is bumped up to 1 by InitMainFrame. The reference count is decremented |
| // when the corresponding WebCore::Frame object is destroyed. |
| WebFrameImpl* main_frame = new WebFrameImpl(); |
| main_frame->InitMainFrame(instance); |
| |
| // Set the delegate after initializing the main frame, to avoid trying to |
| // respond to notifications before we're fully initialized. |
| instance->delegate_ = delegate; |
| |
| WebDevToolsAgentDelegate* tools_delegate = |
| delegate->GetWebDevToolsAgentDelegate(); |
| if (tools_delegate) { |
| instance->devtools_agent_.reset( |
| new WebDevToolsAgentImpl(instance, tools_delegate)); |
| } |
| |
| // Restrict the access to the local file system |
| // (see WebView.mm WebView::_commonInitializationWithFrameName). |
| FrameLoader::setLocalLoadPolicy( |
| FrameLoader::AllowLocalLoadsForLocalOnly); |
| return instance; |
| } |
| |
| WebViewImpl::WebViewImpl() |
| : ALLOW_THIS_IN_INITIALIZER_LIST(back_forward_list_client_impl_(this)), |
| observed_new_navigation_(false), |
| #ifndef NDEBUG |
| new_navigation_loader_(NULL), |
| #endif |
| zoom_level_(0), |
| context_menu_allowed_(false), |
| doing_drag_and_drop_(false), |
| ignore_input_events_(false), |
| suppress_next_keypress_event_(false), |
| window_open_disposition_(IGNORE_ACTION), |
| ime_accept_events_(true), |
| drag_target_dispatch_(false), |
| drag_identity_(0), |
| drop_effect_(DROP_EFFECT_DEFAULT), |
| drop_accept_(false), |
| autocomplete_popup_showing_(false), |
| is_transparent_(false) { |
| // WebKit/win/WebView.cpp does the same thing, except they call the |
| // KJS specific wrapper around this method. We need to have threading |
| // initialized because CollatorICU requires it. |
| WTF::initializeThreading(); |
| |
| // set to impossible point so we always get the first mouse pos |
| last_mouse_position_ = WebPoint(-1, -1); |
| |
| // the page will take ownership of the various clients |
| page_.reset(new Page(new ChromeClientImpl(this), |
| new ContextMenuClientImpl(this), |
| new EditorClientImpl(this), |
| new DragClientImpl(this), |
| new WebInspectorClient(this))); |
| |
| page_->backForwardList()->setClient(&back_forward_list_client_impl_); |
| |
| // The group name identifies a namespace of pages. I'm not sure how it's |
| // intended to be used, but keeping all pages in the same group works for us. |
| page_->setGroupName("default"); |
| } |
| |
| WebViewImpl::~WebViewImpl() { |
| DCHECK(page_ == NULL); |
| ReleaseFocusReferences(); |
| for (std::set<ImageResourceFetcher*>::iterator i = image_fetchers_.begin(); |
| i != image_fetchers_.end(); ++i) { |
| delete *i; |
| } |
| } |
| |
| void WebViewImpl::SetUseEditorDelegate(bool value) { |
| ASSERT(page_ != 0); // The macro doesn't like (!page_) with a scoped_ptr. |
| ASSERT(page_->editorClient()); |
| EditorClientImpl* editor_client = |
| static_cast<EditorClientImpl*>(page_->editorClient()); |
| editor_client->SetUseEditorDelegate(value); |
| } |
| |
| void WebViewImpl::SetTabKeyCyclesThroughElements(bool value) { |
| if (page_ != NULL) { |
| page_->setTabKeyCyclesThroughElements(value); |
| } |
| } |
| |
| void WebViewImpl::MouseMove(const WebMouseEvent& event) { |
| if (!main_frame() || !main_frame()->frameview()) |
| return; |
| |
| last_mouse_position_ = WebPoint(event.x, event.y); |
| |
| // We call mouseMoved here instead of handleMouseMovedEvent because we need |
| // our ChromeClientImpl to receive changes to the mouse position and |
| // tooltip text, and mouseMoved handles all of that. |
| main_frame()->frame()->eventHandler()->mouseMoved( |
| MakePlatformMouseEvent(main_frame()->frameview(), event)); |
| } |
| |
| void WebViewImpl::MouseLeave(const WebMouseEvent& event) { |
| // This event gets sent as the main frame is closing. In that case, just |
| // ignore it. |
| if (!main_frame() || !main_frame()->frameview()) |
| return; |
| |
| delegate_->UpdateTargetURL(this, GURL()); |
| |
| main_frame()->frame()->eventHandler()->handleMouseMoveEvent( |
| MakePlatformMouseEvent(main_frame()->frameview(), event)); |
| } |
| |
| void WebViewImpl::MouseDown(const WebMouseEvent& event) { |
| if (!main_frame() || !main_frame()->frameview()) |
| return; |
| |
| last_mouse_down_point_ = gfx::Point(event.x, event.y); |
| |
| // If a text field that has focus is clicked again, we should display the |
| // autocomplete popup. |
| RefPtr<Node> clicked_node; |
| if (event.button == WebMouseEvent::ButtonLeft) { |
| RefPtr<Node> focused_node = GetFocusedNode(); |
| if (focused_node.get() && |
| webkit_glue::NodeToHTMLInputElement(focused_node.get())) { |
| IntPoint point(event.x, event.y); |
| HitTestResult result(point); |
| result = page_->mainFrame()->eventHandler()->hitTestResultAtPoint(point, |
| false); |
| if (result.innerNonSharedNode() == focused_node) { |
| // Already focused text field was clicked, let's remember this. If |
| // focus has not changed after the mouse event is processed, we'll |
| // trigger the autocomplete. |
| clicked_node = focused_node; |
| } |
| } |
| } |
| |
| main_frame()->frame()->eventHandler()->handleMousePressEvent( |
| MakePlatformMouseEvent(main_frame()->frameview(), event)); |
| |
| if (clicked_node.get() && clicked_node == GetFocusedNode()) { |
| // Focus has not changed, show the autocomplete popup. |
| static_cast<EditorClientImpl*>(page_->editorClient())-> |
| ShowFormAutofillForNode(clicked_node.get()); |
| } |
| |
| // Dispatch the contextmenu event regardless of if the click was swallowed. |
| // On Windows, we handle it on mouse up, not down. |
| #if defined(OS_MACOSX) |
| if (event.button == WebMouseEvent::ButtonRight || |
| (event.button == WebMouseEvent::ButtonLeft && |
| event.modifiers & WebMouseEvent::ControlKey)) { |
| MouseContextMenu(event); |
| } |
| #elif defined(OS_LINUX) |
| if (event.button == WebMouseEvent::ButtonRight) |
| MouseContextMenu(event); |
| #endif |
| |
| #if defined(OS_LINUX) |
| // If the event was a middle click, attempt to copy text into the focused |
| // frame. |
| if (event.button == WebMouseEvent::ButtonMiddle) { |
| Frame* focused = GetFocusedWebCoreFrame(); |
| if (!focused) |
| return; |
| Editor* editor = focused->editor(); |
| if (!editor || !editor->canEdit()) |
| return; |
| |
| delegate_->PasteFromSelectionClipboard(); |
| } |
| #endif |
| } |
| |
| void WebViewImpl::MouseContextMenu(const WebMouseEvent& event) { |
| if (!main_frame() || !main_frame()->frameview()) |
| return; |
| |
| page_->contextMenuController()->clearContextMenu(); |
| |
| MakePlatformMouseEvent pme(main_frame()->frameview(), event); |
| |
| // Find the right target frame. See issue 1186900. |
| HitTestResult result = HitTestResultForWindowPos(pme.pos()); |
| Frame* target_frame; |
| if (result.innerNonSharedNode()) |
| target_frame = result.innerNonSharedNode()->document()->frame(); |
| else |
| target_frame = page_->focusController()->focusedOrMainFrame(); |
| |
| #if defined(OS_WIN) |
| target_frame->view()->setCursor(pointerCursor()); |
| #endif |
| |
| context_menu_allowed_ = true; |
| target_frame->eventHandler()->sendContextMenuEvent(pme); |
| context_menu_allowed_ = false; |
| // Actually showing the context menu is handled by the ContextMenuClient |
| // implementation... |
| } |
| |
| void WebViewImpl::MouseUp(const WebMouseEvent& event) { |
| if (!main_frame() || !main_frame()->frameview()) |
| return; |
| |
| MouseCaptureLost(); |
| main_frame()->frame()->eventHandler()->handleMouseReleaseEvent( |
| MakePlatformMouseEvent(main_frame()->frameview(), event)); |
| |
| #if defined(OS_WIN) |
| // Dispatch the contextmenu event regardless of if the click was swallowed. |
| // On Mac/Linux, we handle it on mouse down, not up. |
| if (event.button == WebMouseEvent::ButtonRight) |
| MouseContextMenu(event); |
| #endif |
| } |
| |
| void WebViewImpl::MouseWheel(const WebMouseWheelEvent& event) { |
| MakePlatformWheelEvent platform_event(main_frame()->frameview(), event); |
| main_frame()->frame()->eventHandler()->handleWheelEvent(platform_event); |
| } |
| |
| bool WebViewImpl::KeyEvent(const WebKeyboardEvent& event) { |
| DCHECK((event.type == WebInputEvent::RawKeyDown) || |
| (event.type == WebInputEvent::KeyDown) || |
| (event.type == WebInputEvent::KeyUp)); |
| |
| // Please refer to the comments explaining the suppress_next_keypress_event_ |
| // member. |
| // The suppress_next_keypress_event_ is set if the KeyDown is handled by |
| // Webkit. A keyDown event is typically associated with a keyPress(char) |
| // event and a keyUp event. We reset this flag here as this is a new keyDown |
| // event. |
| suppress_next_keypress_event_ = false; |
| |
| // Give autocomplete a chance to consume the key events it is interested in. |
| if (AutocompleteHandleKeyEvent(event)) |
| return true; |
| |
| Frame* frame = GetFocusedWebCoreFrame(); |
| if (!frame) |
| return false; |
| |
| EventHandler* handler = frame->eventHandler(); |
| if (!handler) |
| return KeyEventDefault(event); |
| |
| #if defined(OS_WIN) |
| // TODO(pinkerton): figure out these keycodes on non-windows |
| if (((event.modifiers == 0) && (event.windowsKeyCode == VK_APPS)) || |
| ((event.modifiers == WebInputEvent::ShiftKey) && |
| (event.windowsKeyCode == VK_F10))) { |
| SendContextMenuEvent(event); |
| return true; |
| } |
| #endif |
| |
| MakePlatformKeyboardEvent evt(event); |
| |
| if (WebInputEvent::RawKeyDown == event.type) { |
| if (handler->keyEvent(evt) && !evt.isSystemKey()) { |
| suppress_next_keypress_event_ = true; |
| return true; |
| } |
| } else { |
| if (handler->keyEvent(evt)) { |
| return true; |
| } |
| } |
| |
| return KeyEventDefault(event); |
| } |
| |
| bool WebViewImpl::AutocompleteHandleKeyEvent(const WebKeyboardEvent& event) { |
| if (!autocomplete_popup_showing_ || |
| // Home and End should be left to the text field to process. |
| event.windowsKeyCode == base::VKEY_HOME || |
| event.windowsKeyCode == base::VKEY_END) { |
| return false; |
| } |
| |
| // Pressing delete triggers the removal of the selected suggestion from the |
| // DB. |
| if (event.windowsKeyCode == base::VKEY_DELETE && |
| autocomplete_popup_->selectedIndex() != -1) { |
| Node* node = GetFocusedNode(); |
| if (!node || (node->nodeType() != WebCore::Node::ELEMENT_NODE)) { |
| NOTREACHED(); |
| return false; |
| } |
| WebCore::Element* element = static_cast<WebCore::Element*>(node); |
| if (!element->hasLocalName(WebCore::HTMLNames::inputTag)) { |
| NOTREACHED(); |
| return false; |
| } |
| |
| int selected_index = autocomplete_popup_->selectedIndex(); |
| WebCore::HTMLInputElement* input_element = |
| static_cast<WebCore::HTMLInputElement*>(element); |
| std::wstring name = webkit_glue::StringToStdWString(input_element->name()); |
| std::wstring value = webkit_glue::StringToStdWString( |
| autocomplete_popup_client_->itemText(selected_index )); |
| delegate()->RemoveStoredAutofillEntry(name, value); |
| // Update the entries in the currently showing popup to reflect the |
| // deletion. |
| autocomplete_popup_client_->RemoveItemAtIndex(selected_index); |
| RefreshAutofillPopup(); |
| return false; |
| } |
| |
| if (!autocomplete_popup_->isInterestedInEventForKey(event.windowsKeyCode)) |
| return false; |
| |
| if (autocomplete_popup_->handleKeyEvent(MakePlatformKeyboardEvent(event))) { |
| #if defined(OS_WIN) |
| // We need to ignore the next Char event after this otherwise pressing |
| // enter when selecting an item in the menu will go to the page. |
| if (WebInputEvent::RawKeyDown == event.type) |
| suppress_next_keypress_event_ = true; |
| #endif |
| return true; |
| } |
| |
| return false; |
| } |
| |
| bool WebViewImpl::CharEvent(const WebKeyboardEvent& event) { |
| DCHECK(event.type == WebInputEvent::Char); |
| |
| // Please refer to the comments explaining the suppress_next_keypress_event_ |
| // member. |
| // The suppress_next_keypress_event_ is set if the KeyDown is handled by |
| // Webkit. A keyDown event is typically associated with a keyPress(char) |
| // event and a keyUp event. We reset this flag here as it only applies |
| // to the current keyPress event. |
| if (suppress_next_keypress_event_) { |
| suppress_next_keypress_event_ = false; |
| return true; |
| } |
| |
| Frame* frame = GetFocusedWebCoreFrame(); |
| if (!frame) |
| return false; |
| |
| EventHandler* handler = frame->eventHandler(); |
| if (!handler) |
| return KeyEventDefault(event); |
| |
| MakePlatformKeyboardEvent evt(event); |
| if (!evt.IsCharacterKey()) |
| return true; |
| |
| // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to |
| // the eventHandler::keyEvent. We mimic this behavior on all platforms since |
| // for now we are converting other platform's key events to windows key |
| // events. |
| if (evt.isSystemKey()) |
| return handler->handleAccessKey(evt); |
| |
| if (!handler->keyEvent(evt)) |
| return KeyEventDefault(event); |
| |
| return true; |
| } |
| |
| /* |
| * The WebViewImpl::SendContextMenuEvent function is based on the Webkit |
| * function |
| * bool WebView::handleContextMenuEvent(WPARAM wParam, LPARAM lParam) in |
| * webkit\webkit\win\WebView.cpp. The only significant change in this |
| * function is the code to convert from a Keyboard event to the Right |
| * Mouse button up event. |
| * |
| * This function is an ugly copy/paste and should be cleaned up when the |
| * WebKitWin version is cleaned: https://bugs.webkit.org/show_bug.cgi?id=20438 |
| */ |
| #if defined(OS_WIN) |
| // TODO(pinkerton): implement on non-windows |
| bool WebViewImpl::SendContextMenuEvent(const WebKeyboardEvent& event) { |
| static const int kContextMenuMargin = 1; |
| Frame* main_frame = page()->mainFrame(); |
| FrameView* view = main_frame->view(); |
| if (!view) |
| return false; |
| |
| IntPoint coords(-1, -1); |
| int right_aligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT); |
| IntPoint location; |
| |
| // The context menu event was generated from the keyboard, so show the |
| // context menu by the current selection. |
| Position start = main_frame->selection()->selection().start(); |
| Position end = main_frame->selection()->selection().end(); |
| |
| if (!start.node() || !end.node()) { |
| location = |
| IntPoint(right_aligned ? view->contentsWidth() - kContextMenuMargin |
| : kContextMenuMargin, kContextMenuMargin); |
| } else { |
| RenderObject* renderer = start.node()->renderer(); |
| if (!renderer) |
| return false; |
| |
| RefPtr<Range> selection = main_frame->selection()->toNormalizedRange(); |
| IntRect first_rect = main_frame->firstRectForRange(selection.get()); |
| |
| int x = right_aligned ? first_rect.right() : first_rect.x(); |
| location = IntPoint(x, first_rect.bottom()); |
| } |
| |
| location = view->contentsToWindow(location); |
| // FIXME: The IntSize(0, -1) is a hack to get the hit-testing to result in |
| // the selected element. Ideally we'd have the position of a context menu |
| // event be separate from its target node. |
| coords = location + IntSize(0, -1); |
| |
| // The contextMenuController() holds onto the last context menu that was |
| // popped up on the page until a new one is created. We need to clear |
| // this menu before propagating the event through the DOM so that we can |
| // detect if we create a new menu for this event, since we won't create |
| // a new menu if the DOM swallows the event and the defaultEventHandler does |
| // not run. |
| page()->contextMenuController()->clearContextMenu(); |
| |
| Frame* focused_frame = page()->focusController()->focusedOrMainFrame(); |
| focused_frame->view()->setCursor(pointerCursor()); |
| WebMouseEvent mouse_event; |
| mouse_event.button = WebMouseEvent::ButtonRight; |
| mouse_event.x = coords.x(); |
| mouse_event.y = coords.y(); |
| mouse_event.type = WebInputEvent::MouseUp; |
| |
| MakePlatformMouseEvent platform_event(view, mouse_event); |
| |
| context_menu_allowed_ = true; |
| bool handled = |
| focused_frame->eventHandler()->sendContextMenuEvent(platform_event); |
| context_menu_allowed_ = false; |
| return handled; |
| } |
| #endif |
| |
| bool WebViewImpl::KeyEventDefault(const WebKeyboardEvent& event) { |
| Frame* frame = GetFocusedWebCoreFrame(); |
| if (!frame) |
| return false; |
| |
| switch (event.type) { |
| case WebInputEvent::Char: { |
| if (event.windowsKeyCode == VKEY_SPACE) { |
| int key_code = ((event.modifiers & WebInputEvent::ShiftKey) ? |
| VKEY_PRIOR : VKEY_NEXT); |
| return ScrollViewWithKeyboard(key_code); |
| } |
| break; |
| } |
| |
| #if defined(OS_WIN) |
| case WebInputEvent::RawKeyDown: { |
| #else |
| case WebInputEvent::KeyDown: { |
| #endif |
| if (event.modifiers == WebInputEvent::ControlKey) { |
| switch (event.windowsKeyCode) { |
| case 'A': |
| GetFocusedFrame()->SelectAll(); |
| return true; |
| case VKEY_INSERT: |
| case 'C': |
| GetFocusedFrame()->Copy(); |
| return true; |
| // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl |
| // key combinations which affect scrolling. Safari is buggy in the |
| // sense that it scrolls the page for all Ctrl+scrolling key |
| // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc. |
| case VKEY_HOME: |
| case VKEY_END: |
| break; |
| default: |
| return false; |
| } |
| } |
| if (!event.isSystemKey) { |
| return ScrollViewWithKeyboard(event.windowsKeyCode); |
| } |
| break; |
| } |
| |
| default: |
| break; |
| } |
| return false; |
| } |
| |
| bool WebViewImpl::ScrollViewWithKeyboard(int key_code) { |
| Frame* frame = GetFocusedWebCoreFrame(); |
| if (!frame) |
| return false; |
| |
| ScrollDirection scroll_direction; |
| ScrollGranularity scroll_granularity; |
| |
| switch (key_code) { |
| case VKEY_LEFT: |
| scroll_direction = ScrollLeft; |
| scroll_granularity = ScrollByLine; |
| break; |
| case VKEY_RIGHT: |
| scroll_direction = ScrollRight; |
| scroll_granularity = ScrollByLine; |
| break; |
| case VKEY_UP: |
| scroll_direction = ScrollUp; |
| scroll_granularity = ScrollByLine; |
| break; |
| case VKEY_DOWN: |
| scroll_direction = ScrollDown; |
| scroll_granularity = ScrollByLine; |
| break; |
| case VKEY_HOME: |
| scroll_direction = ScrollUp; |
| scroll_granularity = ScrollByDocument; |
| break; |
| case VKEY_END: |
| scroll_direction = ScrollDown; |
| scroll_granularity = ScrollByDocument; |
| break; |
| case VKEY_PRIOR: // page up |
| scroll_direction = ScrollUp; |
| scroll_granularity = ScrollByPage; |
| break; |
| case VKEY_NEXT: // page down |
| scroll_direction = ScrollDown; |
| scroll_granularity = ScrollByPage; |
| break; |
| default: |
| return false; |
| } |
| |
| bool scroll_handled = |
| frame->eventHandler()->scrollOverflow(scroll_direction, |
| scroll_granularity); |
| Frame* current_frame = frame; |
| while (!scroll_handled && current_frame) { |
| scroll_handled = current_frame->view()->scroll(scroll_direction, |
| scroll_granularity); |
| current_frame = current_frame->tree()->parent(); |
| } |
| return scroll_handled; |
| } |
| |
| Frame* WebViewImpl::GetFocusedWebCoreFrame() { |
| return page_.get() ? page_->focusController()->focusedOrMainFrame() : NULL; |
| } |
| |
| // static |
| WebViewImpl* WebViewImpl::FromPage(WebCore::Page* page) { |
| return WebFrameImpl::FromFrame(page->mainFrame())->GetWebViewImpl(); |
| } |
| |
| // WebView -------------------------------------------------------------------- |
| |
| bool WebViewImpl::ShouldClose() { |
| // TODO(creis): This should really cause a recursive depth-first walk of all |
| // frames in the tree, calling each frame's onbeforeunload. At the moment, |
| // we're consistent with Safari 3.1, not IE/FF. |
| Frame* frame = page_->focusController()->focusedOrMainFrame(); |
| if (!frame) |
| return true; |
| |
| return frame->shouldClose(); |
| } |
| |
| void WebViewImpl::Close() { |
| // Do this first to prevent reentrant notifications from being sent to the |
| // initiator of the close. |
| delegate_ = NULL; |
| |
| if (page_.get()) { |
| // Initiate shutdown for the entire frameset. This will cause a lot of |
| // notifications to be sent. |
| if (page_->mainFrame()) |
| page_->mainFrame()->loader()->frameDetached(); |
| page_.reset(); |
| } |
| |
| // Should happen after page_.reset(). |
| devtools_agent_.reset(NULL); |
| |
| Release(); // Balances AddRef from WebView::Create |
| } |
| |
| WebViewDelegate* WebViewImpl::GetDelegate() { |
| return delegate_; |
| } |
| |
| void WebViewImpl::SetDelegate(WebViewDelegate* delegate) { |
| delegate_ = delegate; |
| } |
| |
| WebFrame* WebViewImpl::GetMainFrame() { |
| return main_frame(); |
| } |
| |
| WebFrame* WebViewImpl::GetFocusedFrame() { |
| Frame* frame = GetFocusedWebCoreFrame(); |
| return frame ? WebFrameImpl::FromFrame(frame) : NULL; |
| } |
| |
| void WebViewImpl::SetFocusedFrame(WebFrame* frame) { |
| if (!frame) { |
| // Clears the focused frame if any. |
| Frame* frame = GetFocusedWebCoreFrame(); |
| if (frame) |
| frame->selection()->setFocused(false); |
| return; |
| } |
| WebFrameImpl* frame_impl = static_cast<WebFrameImpl*>(frame); |
| WebCore::Frame* webcore_frame = frame_impl->frame(); |
| webcore_frame->page()->focusController()->setFocusedFrame(webcore_frame); |
| } |
| |
| WebFrame* WebViewImpl::GetFrameWithName(const std::wstring& name) { |
| String name_str = webkit_glue::StdWStringToString(name); |
| Frame* frame = page_->mainFrame()->tree()->find(name_str); |
| return frame ? WebFrameImpl::FromFrame(frame) : NULL; |
| } |
| |
| WebFrame* WebViewImpl::GetPreviousFrameBefore(WebFrame* frame, bool wrap) { |
| WebFrameImpl* frame_impl = static_cast<WebFrameImpl*>(frame); |
| WebCore::Frame* previous = |
| frame_impl->frame()->tree()->traversePreviousWithWrap(wrap); |
| return previous ? WebFrameImpl::FromFrame(previous) : NULL; |
| } |
| |
| WebFrame* WebViewImpl::GetNextFrameAfter(WebFrame* frame, bool wrap) { |
| WebFrameImpl* frame_impl = static_cast<WebFrameImpl*>(frame); |
| WebCore::Frame* next = |
| frame_impl->frame()->tree()->traverseNextWithWrap(wrap); |
| return next ? WebFrameImpl::FromFrame(next) : NULL; |
| } |
| |
| void WebViewImpl::Resize(const WebSize& new_size) { |
| if (size_ == new_size) |
| return; |
| size_ = new_size; |
| |
| if (main_frame()->frameview()) { |
| main_frame()->frameview()->resize(size_.width, size_.height); |
| main_frame()->frame()->eventHandler()->sendResizeEvent(); |
| } |
| |
| if (delegate_) { |
| WebRect damaged_rect(0, 0, size_.width, size_.height); |
| delegate_->DidInvalidateRect(this, damaged_rect); |
| } |
| } |
| |
| void WebViewImpl::Layout() { |
| WebFrameImpl* webframe = main_frame(); |
| if (webframe) { |
| // In order for our child HWNDs (NativeWindowWidgets) to update properly, |
| // they need to be told that we are updating the screen. The problem is |
| // that the native widgets need to recalculate their clip region and not |
| // overlap any of our non-native widgets. To force the resizing, call |
| // setFrameRect(). This will be a quick operation for most frames, but |
| // the NativeWindowWidgets will update a proper clipping region. |
| FrameView* view = webframe->frameview(); |
| if (view) |
| view->setFrameRect(view->frameRect()); |
| |
| // setFrameRect may have the side-effect of causing existing page |
| // layout to be invalidated, so layout needs to be called last. |
| |
| webframe->Layout(); |
| } |
| } |
| |
| void WebViewImpl::Paint(skia::PlatformCanvas* canvas, const WebRect& rect) { |
| WebFrameImpl* webframe = main_frame(); |
| if (webframe) |
| webframe->Paint(canvas, rect); |
| } |
| |
| // TODO(eseidel): g_current_input_event should be removed once |
| // ChromeClient:show() can get the current-event information from WebCore. |
| /* static */ |
| const WebInputEvent* WebViewImpl::g_current_input_event = NULL; |
| |
| bool WebViewImpl::HandleInputEvent(const WebInputEvent* input_event) { |
| // If we've started a drag and drop operation, ignore input events until |
| // we're done. |
| if (doing_drag_and_drop_) |
| return true; |
| |
| if (ignore_input_events_) |
| return true; |
| |
| // TODO(eseidel): Remove g_current_input_event. |
| // This only exists to allow ChromeClient::show() to know which mouse button |
| // triggered a window.open event. |
| // Safari must perform a similar hack, ours is in our WebKit glue layer |
| // theirs is in the application. This should go when WebCore can be fixed |
| // to pass more event information to ChromeClient::show() |
| g_current_input_event = input_event; |
| |
| bool handled = true; |
| |
| // TODO(jcampan): WebKit seems to always return false on mouse events |
| // processing methods. For now we'll assume it has processed them (as we are |
| // only interested in whether keyboard events are processed). |
| switch (input_event->type) { |
| case WebInputEvent::MouseMove: |
| MouseMove(*static_cast<const WebMouseEvent*>(input_event)); |
| break; |
| |
| case WebInputEvent::MouseLeave: |
| MouseLeave(*static_cast<const WebMouseEvent*>(input_event)); |
| break; |
| |
| case WebInputEvent::MouseWheel: |
| MouseWheel(*static_cast<const WebMouseWheelEvent*>(input_event)); |
| break; |
| |
| case WebInputEvent::MouseDown: |
| MouseDown(*static_cast<const WebMouseEvent*>(input_event)); |
| break; |
| |
| case WebInputEvent::MouseUp: |
| MouseUp(*static_cast<const WebMouseEvent*>(input_event)); |
| break; |
| |
| case WebInputEvent::RawKeyDown: |
| case WebInputEvent::KeyDown: |
| case WebInputEvent::KeyUp: |
| handled = KeyEvent(*static_cast<const WebKeyboardEvent*>(input_event)); |
| break; |
| |
| case WebInputEvent::Char: |
| handled = CharEvent(*static_cast<const WebKeyboardEvent*>(input_event)); |
| break; |
| default: |
| handled = false; |
| } |
| |
| g_current_input_event = NULL; |
| |
| return handled; |
| } |
| |
| void WebViewImpl::MouseCaptureLost() { |
| } |
| |
| // TODO(darin): these navigation methods should be killed |
| |
| void WebViewImpl::StopLoading() { |
| main_frame()->StopLoading(); |
| } |
| |
| void WebViewImpl::SetBackForwardListSize(int size) { |
| page_->backForwardList()->setCapacity(size); |
| } |
| |
| void WebViewImpl::ClearFocusedNode() { |
| // Get the last focused frame or the mainframe. |
| RefPtr<Frame> frame = last_focused_frame_; |
| if (!frame.get() && page_.get()) |
| frame = page_->mainFrame(); |
| if (!frame.get()) |
| return; |
| |
| RefPtr<Document> document = frame->document(); |
| if (!document.get()) |
| return; |
| |
| RefPtr<Node> old_focused_node = document->focusedNode(); |
| |
| // Clear the focused node. |
| document->setFocusedNode(NULL); |
| |
| if (!old_focused_node.get()) |
| return; |
| |
| // If a text field has focus, we need to make sure the selection controller |
| // knows to remove selection from it. Otherwise, the text field is still |
| // processing keyboard events even though focus has been moved to the page and |
| // keystrokes get eaten as a result. |
| if (old_focused_node->hasTagName(HTMLNames::textareaTag) || |
| (old_focused_node->hasTagName(HTMLNames::inputTag) && |
| static_cast<HTMLInputElement*>(old_focused_node.get())->isTextField())) { |
| // Clear the selection. |
| SelectionController* selection = frame->selection(); |
| selection->clear(); |
| } |
| } |
| |
| void WebViewImpl::SetFocus(bool enable) { |
| if (enable) { |
| // Getting the focused frame will have the side-effect of setting the main |
| // frame as the focused frame if it is not already focused. Otherwise, if |
| // there is already a focused frame, then this does nothing. |
| GetFocusedFrame(); |
| if (page_.get() && page_->mainFrame()) { |
| Frame* frame = page_->mainFrame(); |
| if (!frame->selection()->isFocusedAndActive()) { |
| // No one has focus yet, try to restore focus. |
| RestoreFocus(); |
| page_->focusController()->setActive(true); |
| } |
| Frame* focused_frame = page_->focusController()->focusedOrMainFrame(); |
| frame->selection()->setFocused(frame == focused_frame); |
| } |
| ime_accept_events_ = true; |
| } else { |
| HideAutoCompletePopup(); |
| |
| // Clear out who last had focus. If someone has focus, the refs will be |
| // updated below. |
| ReleaseFocusReferences(); |
| |
| // Clear focus on the currently focused frame if any. |
| if (!page_.get()) |
| return; |
| |
| Frame* frame = page_->mainFrame(); |
| if (!frame) |
| return; |
| |
| RefPtr<Frame> focused = page_->focusController()->focusedFrame(); |
| if (focused.get()) { |
| // Update the focus refs, this way we can give focus back appropriately. |
| // It's entirely possible to have a focused document, but not a focused |
| // node. |
| RefPtr<Document> document = focused->document(); |
| last_focused_frame_ = focused; |
| if (document.get()) { |
| RefPtr<Node> focused_node = document->focusedNode(); |
| if (focused_node.get()) { |
| // To workaround bug #792423, we do not blur the focused node. This |
| // should be reenabled when we merge a WebKit that has the fix for |
| // http://bugs.webkit.org/show_bug.cgi?id=16928. |
| // last_focused_node_ = focused_node; |
| // document->setFocusedNode(NULL); |
| } |
| } |
| page_->focusController()->setFocusedFrame(0); |
| |
| // Finish an ongoing composition to delete the composition node. |
| Editor* editor = focused->editor(); |
| if (editor && editor->hasComposition()) |
| editor->confirmComposition(); |
| ime_accept_events_ = false; |
| } |
| // Make sure the main frame doesn't think it has focus. |
| if (frame != focused.get()) |
| frame->selection()->setFocused(false); |
| } |
| } |
| |
| // TODO(jcampan): http://b/issue?id=1157486 this is needed to work-around |
| // issues caused by the fix for bug #792423 and should be removed when that |
| // bug is fixed. |
| void WebViewImpl::StoreFocusForFrame(WebFrame* frame) { |
| DCHECK(frame); |
| |
| // We only want to store focus info if we are the focused frame and if we have |
| // not stored it already. |
| WebCore::Frame* webcore_frame = static_cast<WebFrameImpl*>(frame)->frame(); |
| if (last_focused_frame_.get() != webcore_frame || last_focused_node_.get()) |
| return; |
| |
| // Clear out who last had focus. If someone has focus, the refs will be |
| // updated below. |
| ReleaseFocusReferences(); |
| |
| last_focused_frame_ = webcore_frame; |
| RefPtr<Document> document = last_focused_frame_->document(); |
| if (document.get()) { |
| RefPtr<Node> focused_node = document->focusedNode(); |
| if (focused_node.get()) { |
| last_focused_node_ = focused_node; |
| document->setFocusedNode(NULL); |
| } |
| } |
| } |
| |
| bool WebViewImpl::ImeSetComposition(int string_type, |
| int cursor_position, |
| int target_start, |
| int target_end, |
| const std::wstring& ime_string) { |
| Frame* focused = GetFocusedWebCoreFrame(); |
| if (!focused || !ime_accept_events_) { |
| return false; |
| } |
| Editor* editor = focused->editor(); |
| if (!editor) |
| return false; |
| if (!editor->canEdit()) { |
| // The input focus has been moved to another WebWidget object. |
| // We should use this |editor| object only to complete the ongoing |
| // composition. |
| if (!editor->hasComposition()) |
| return false; |
| } |
| |
| // We should verify the parent node of this IME composition node are |
| // editable because JavaScript may delete a parent node of the composition |
| // node. In this case, WebKit crashes while deleting texts from the parent |
| // node, which doesn't exist any longer. |
| PassRefPtr<Range> range = editor->compositionRange(); |
| if (range) { |
| const Node* node = range->startPosition().node(); |
| if (!node || !node->isContentEditable()) |
| return false; |
| } |
| |
| if (string_type == -1) { |
| // A browser process sent an IPC message which does not contain a valid |
| // string, which means an ongoing composition has been canceled. |
| // If the ongoing composition has been canceled, replace the ongoing |
| // composition string with an empty string and complete it. |
| WebCore::String empty_string; |
| WTF::Vector<WebCore::CompositionUnderline> empty_underlines; |
| editor->setComposition(empty_string, empty_underlines, 0, 0); |
| } else { |
| // A browser process sent an IPC message which contains a string to be |
| // displayed in this Editor object. |
| // To display the given string, set the given string to the |
| // m_compositionNode member of this Editor object and display it. |
| if (target_start < 0) target_start = 0; |
| if (target_end < 0) target_end = static_cast<int>(ime_string.length()); |
| WebCore::String composition_string( |
| webkit_glue::StdWStringToString(ime_string)); |
| // Create custom underlines. |
| // To emphasize the selection, the selected region uses a solid black |
| // for its underline while other regions uses a pale gray for theirs. |
| WTF::Vector<WebCore::CompositionUnderline> underlines(3); |
| underlines[0].startOffset = 0; |
| underlines[0].endOffset = target_start; |
| underlines[0].thick = true; |
| underlines[0].color.setRGB(0xd3, 0xd3, 0xd3); |
| underlines[1].startOffset = target_start; |
| underlines[1].endOffset = target_end; |
| underlines[1].thick = true; |
| underlines[1].color.setRGB(0x00, 0x00, 0x00); |
| underlines[2].startOffset = target_end; |
| underlines[2].endOffset = static_cast<int>(ime_string.length()); |
| underlines[2].thick = true; |
| underlines[2].color.setRGB(0xd3, 0xd3, 0xd3); |
| // When we use custom underlines, WebKit ("InlineTextBox.cpp" Line 282) |
| // prevents from writing a text in between 'selectionStart' and |
| // 'selectionEnd' somehow. |
| // Therefore, we use the 'cursor_position' for these arguments so that |
| // there are not any characters in the above region. |
| editor->setComposition(composition_string, underlines, |
| cursor_position, cursor_position); |
| // The given string is a result string, which means the ongoing |
| // composition has been completed. I have to call the |
| // Editor::confirmCompletion() and complete this composition. |
| if (string_type == 1) { |
| editor->confirmComposition(); |
| } |
| } |
| |
| return editor->hasComposition(); |
| } |
| |
| bool WebViewImpl::ImeUpdateStatus(bool* enable_ime, |
| WebRect* caret_rect) { |
| // Store whether the selected node needs IME and the caret rectangle. |
| // This process consists of the following four steps: |
| // 1. Retrieve the selection controller of the focused frame; |
| // 2. Retrieve the caret rectangle from the controller; |
| // 3. Convert the rectangle, which is relative to the parent view, to the |
| // one relative to the client window, and; |
| // 4. Store the converted rectangle. |
| const Frame* focused = GetFocusedWebCoreFrame(); |
| if (!focused) |
| return false; |
| |
| const Editor* editor = focused->editor(); |
| if (!editor || !editor->canEdit()) |
| return false; |
| |
| SelectionController* controller = focused->selection(); |
| if (!controller) |
| return false; |
| |
| const Node* node = controller->start().node(); |
| if (!node) |
| return false; |
| |
| *enable_ime = node->shouldUseInputMethod() && |
| !controller->isInPasswordField(); |
| const FrameView* view = node->document()->view(); |
| if (!view) |
| return false; |
| |
| *caret_rect = webkit_glue::IntRectToWebRect( |
| view->contentsToWindow(controller->absoluteCaretBounds())); |
| return true; |
| } |
| |
| void WebViewImpl::SetTextDirection(WebTextDirection direction) { |
| // The Editor::setBaseWritingDirection() function checks if we can change |
| // the text direction of the selected node and updates its DOM "dir" |
| // attribute and its CSS "direction" property. |
| // So, we just call the function as Safari does. |
| const Frame* focused = GetFocusedWebCoreFrame(); |
| if (!focused) |
| return; |
| |
| Editor* editor = focused->editor(); |
| if (!editor || !editor->canEdit()) |
| return; |
| |
| switch (direction) { |
| case WEB_TEXT_DIRECTION_DEFAULT: |
| editor->setBaseWritingDirection(WebCore::NaturalWritingDirection); |
| break; |
| |
| case WEB_TEXT_DIRECTION_LTR: |
| editor->setBaseWritingDirection(WebCore::LeftToRightWritingDirection); |
| break; |
| |
| case WEB_TEXT_DIRECTION_RTL: |
| editor->setBaseWritingDirection(WebCore::RightToLeftWritingDirection); |
| break; |
| |
| default: |
| NOTIMPLEMENTED(); |
| break; |
| } |
| } |
| |
| void WebViewImpl::RestoreFocus() { |
| if (last_focused_frame_.get()) { |
| if (last_focused_frame_->page()) { |
| // last_focused_frame_ can be detached from the frame tree, thus, |
| // its page can be null. |
| last_focused_frame_->page()->focusController()->setFocusedFrame( |
| last_focused_frame_.get()); |
| } |
| if (last_focused_node_.get()) { |
| // last_focused_node_ may be null, make sure it's valid before trying to |
| // focus it. |
| static_cast<Element*>(last_focused_node_.get())->focus(); |
| } |
| // And clear out the refs. |
| ReleaseFocusReferences(); |
| } |
| } |
| |
| void WebViewImpl::SetInitialFocus(bool reverse) { |
| if (page_.get()) { |
| // So RestoreFocus does not focus anything when it is called. |
| ReleaseFocusReferences(); |
| |
| // Since we don't have a keyboard event, we'll create one. |
| WebKeyboardEvent keyboard_event; |
| keyboard_event.type = WebInputEvent::RawKeyDown; |
| if (reverse) |
| keyboard_event.modifiers = WebInputEvent::ShiftKey; |
| // VK_TAB which is only defined on Windows. |
| keyboard_event.windowsKeyCode = 0x09; |
| MakePlatformKeyboardEvent platform_event(keyboard_event); |
| RefPtr<KeyboardEvent> webkit_event = |
| KeyboardEvent::create(platform_event, NULL); |
| page()->focusController()->setInitialFocus( |
| reverse ? WebCore::FocusDirectionBackward : |
| WebCore::FocusDirectionForward, |
| webkit_event.get()); |
| } |
| } |
| |
| // Releases references used to restore focus. |
| void WebViewImpl::ReleaseFocusReferences() { |
| if (last_focused_frame_.get()) { |
| last_focused_frame_.release(); |
| last_focused_node_.release(); |
| } |
| } |
| |
| bool WebViewImpl::DownloadImage(int id, const GURL& image_url, int image_size) { |
| if (!page_.get()) |
| return false; |
| image_fetchers_.insert( |
| new ImageResourceFetcher(this, id, image_url, image_size)); |
| return true; |
| } |
| |
| void WebViewImpl::SetPreferences(const WebPreferences& preferences) { |
| if (!page_.get()) |
| return; |
| |
| // Keep a local copy of the preferences struct for GetPreferences. |
| webprefs_ = preferences; |
| |
| Settings* settings = page_->settings(); |
| |
| settings->setStandardFontFamily(webkit_glue::StdWStringToString( |
| preferences.standard_font_family)); |
| settings->setFixedFontFamily(webkit_glue::StdWStringToString( |
| preferences.fixed_font_family)); |
| settings->setSerifFontFamily(webkit_glue::StdWStringToString( |
| preferences.serif_font_family)); |
| settings->setSansSerifFontFamily(webkit_glue::StdWStringToString( |
| preferences.sans_serif_font_family)); |
| settings->setCursiveFontFamily(webkit_glue::StdWStringToString( |
| preferences.cursive_font_family)); |
| settings->setFantasyFontFamily(webkit_glue::StdWStringToString( |
| preferences.fantasy_font_family)); |
| settings->setDefaultFontSize(preferences.default_font_size); |
| settings->setDefaultFixedFontSize(preferences.default_fixed_font_size); |
| settings->setMinimumFontSize(preferences.minimum_font_size); |
| settings->setMinimumLogicalFontSize(preferences.minimum_logical_font_size); |
| settings->setDefaultTextEncodingName(webkit_glue::StdWStringToString( |
| preferences.default_encoding)); |
| settings->setJavaScriptEnabled(preferences.javascript_enabled); |
| settings->setWebSecurityEnabled(preferences.web_security_enabled); |
| settings->setJavaScriptCanOpenWindowsAutomatically( |
| preferences.javascript_can_open_windows_automatically); |
| settings->setLoadsImagesAutomatically( |
| preferences.loads_images_automatically); |
| settings->setPluginsEnabled(preferences.plugins_enabled); |
| settings->setDOMPasteAllowed(preferences.dom_paste_enabled); |
| settings->setDeveloperExtrasEnabled(preferences.developer_extras_enabled); |
| settings->setShrinksStandaloneImagesToFit( |
| preferences.shrinks_standalone_images_to_fit); |
| settings->setUsesEncodingDetector(preferences.uses_universal_detector); |
| settings->setTextAreasAreResizable(preferences.text_areas_are_resizable); |
| settings->setAllowScriptsToCloseWindows( |
| preferences.allow_scripts_to_close_windows); |
| if (preferences.user_style_sheet_enabled) { |
| settings->setUserStyleSheetLocation(webkit_glue::GURLToKURL( |
| preferences.user_style_sheet_location)); |
| } else { |
| settings->setUserStyleSheetLocation(KURL()); |
| } |
| settings->setUsesPageCache(preferences.uses_page_cache); |
| settings->setDownloadableBinaryFontsEnabled(preferences.remote_fonts_enabled); |
| |
| // This setting affects the behavior of links in an editable region: |
| // clicking the link should select it rather than navigate to it. |
| // Safari uses the same default. It is unlikley an embedder would want to |
| // change this, since it would break existing rich text editors. |
| settings->setEditableLinkBehavior(WebCore::EditableLinkNeverLive); |
| |
| settings->setFontRenderingMode(NormalRenderingMode); |
| settings->setJavaEnabled(preferences.java_enabled); |
| |
| // Turn this on to cause WebCore to paint the resize corner for us. |
| settings->setShouldPaintCustomScrollbars(true); |
| |
| // Mitigate attacks from local HTML files by not granting file:// URLs |
| // universal access. |
| settings->setAllowUniversalAccessFromFileURLs(false); |
| |
| // We prevent WebKit from checking if it needs to add a "text direction" |
| // submenu to a context menu. it is not only because we don't need the result |
| // but also because it cause a possible crash in Editor::hasBidiSelection(). |
| settings->setTextDirectionSubmenuInclusionBehavior( |
| TextDirectionSubmenuNeverIncluded); |
| |
| #if defined(OS_WIN) |
| // RenderTheme is a singleton that needs to know the default font size to |
| // draw some form controls. We let it know each time the size changes. |
| WebCore::RenderThemeChromiumWin::setDefaultFontSize( |
| preferences.default_font_size); |
| #endif |
| } |
| |
| const WebPreferences& WebViewImpl::GetPreferences() { |
| return webprefs_; |
| } |
| |
| // Set the encoding of the current main frame to the one selected by |
| // a user in the encoding menu. |
| void WebViewImpl::SetPageEncoding(const std::wstring& encoding_name) { |
| if (!page_.get()) |
| return; |
| |
| if (!encoding_name.empty()) { |
| // only change override encoding, don't change default encoding |
| // TODO(brettw) use std::string for encoding names. |
| String new_encoding_name(webkit_glue::StdWStringToString(encoding_name)); |
| page_->mainFrame()->loader()->reloadWithOverrideEncoding(new_encoding_name); |
| } |
| } |
| |
| // Return the canonical encoding name of current main webframe in webview. |
| std::wstring WebViewImpl::GetMainFrameEncodingName() { |
| if (!page_.get()) |
| return std::wstring(); |
| |
| String encoding_name = page_->mainFrame()->loader()->encoding(); |
| return webkit_glue::StringToStdWString(encoding_name); |
| } |
| |
| void WebViewImpl::ZoomIn(bool text_only) { |
| Frame* frame = main_frame()->frame(); |
| double multiplier = std::min(std::pow(kTextSizeMultiplierRatio, |
| zoom_level_ + 1), |
| kMaxTextSizeMultiplier); |
| float zoom_factor = static_cast<float>(multiplier); |
| if (zoom_factor != frame->zoomFactor()) { |
| ++zoom_level_; |
| frame->setZoomFactor(zoom_factor, text_only); |
| } |
| } |
| |
| void WebViewImpl::ZoomOut(bool text_only) { |
| Frame* frame = main_frame()->frame(); |
| double multiplier = std::max(std::pow(kTextSizeMultiplierRatio, |
| zoom_level_ - 1), |
| kMinTextSizeMultiplier); |
| float zoom_factor = static_cast<float>(multiplier); |
| if (zoom_factor != frame->zoomFactor()) { |
| --zoom_level_; |
| frame->setZoomFactor(zoom_factor, text_only); |
| } |
| } |
| |
| void WebViewImpl::ResetZoom() { |
| // We don't change the zoom mode (text only vs. full page) here. We just want |
| // to reset whatever is already set. |
| zoom_level_ = 0; |
| main_frame()->frame()->setZoomFactor( |
| 1.0f, |
| main_frame()->frame()->isZoomFactorTextOnly()); |
| } |
| |
| void WebViewImpl::CopyImageAt(int x, int y) { |
| if (!page_.get()) |
| return; |
| |
| HitTestResult result = HitTestResultForWindowPos(IntPoint(x, y)); |
| |
| if (result.absoluteImageURL().isEmpty()) { |
| // There isn't actually an image at these coordinates. Might be because |
| // the window scrolled while the context menu was open or because the page |
| // changed itself between when we thought there was an image here and when |
| // we actually tried to retreive the image. |
| // |
| // TODO: implement a cache of the most recent HitTestResult to avoid having |
| // to do two hit tests. |
| return; |
| } |
| |
| page_->mainFrame()->editor()->copyImage(result); |
| } |
| |
| void WebViewImpl::InspectElement(int x, int y) { |
| if (!page_.get()) |
| return; |
| |
| if (x == -1 || y == -1) { |
| page_->inspectorController()->inspect(NULL); |
| } else { |
| HitTestResult result = HitTestResultForWindowPos(IntPoint(x, y)); |
| |
| if (!result.innerNonSharedNode()) |
| return; |
| |
| page_->inspectorController()->inspect(result.innerNonSharedNode()); |
| } |
| } |
| |
| void WebViewImpl::ShowJavaScriptConsole() { |
| page_->inspectorController()->showPanel(InspectorController::ConsolePanel); |
| } |
| |
| void WebViewImpl::DragSourceEndedAt( |
| const WebPoint& client_point, |
| const WebPoint& screen_point) { |
| PlatformMouseEvent pme(webkit_glue::WebPointToIntPoint(client_point), |
| webkit_glue::WebPointToIntPoint(screen_point), |
| NoButton, MouseEventMoved, 0, false, false, false, |
| false, 0); |
| page_->mainFrame()->eventHandler()->dragSourceEndedAt(pme, DragOperationCopy); |
| } |
| |
| void WebViewImpl::DragSourceMovedTo( |
| const WebPoint& client_point, |
| const WebPoint& screen_point) { |
| PlatformMouseEvent pme(webkit_glue::WebPointToIntPoint(client_point), |
| webkit_glue::WebPointToIntPoint(screen_point), |
| LeftButton, MouseEventMoved, 0, false, false, false, |
| false, 0); |
| page_->mainFrame()->eventHandler()->dragSourceMovedTo(pme); |
| } |
| |
| void WebViewImpl::DragSourceSystemDragEnded() { |
| page_->dragController()->dragEnded(); |
| DCHECK(doing_drag_and_drop_); |
| doing_drag_and_drop_ = false; |
| } |
| |
| bool WebViewImpl::DragTargetDragEnter( |
| const WebDragData& web_drag_data, |
| int identity, |
| const WebPoint& client_point, |
| const WebPoint& screen_point) { |
| DCHECK(!current_drag_data_.get()); |
| |
| current_drag_data_ = |
| webkit_glue::WebDragDataToChromiumDataObject(web_drag_data); |
| drag_identity_ = identity; |
| |
| DragData drag_data( |
| current_drag_data_.get(), |
| webkit_glue::WebPointToIntPoint(client_point), |
| webkit_glue::WebPointToIntPoint(screen_point), |
| kDropTargetOperation); |
| |
| drop_effect_ = DROP_EFFECT_DEFAULT; |
| drag_target_dispatch_ = true; |
| DragOperation effect = page_->dragController()->dragEntered(&drag_data); |
| drag_target_dispatch_ = false; |
| |
| if (drop_effect_ != DROP_EFFECT_DEFAULT) |
| return drop_accept_ = (drop_effect_ != DROP_EFFECT_NONE); |
| return drop_accept_ = (effect != DragOperationNone); |
| } |
| |
| bool WebViewImpl::DragTargetDragOver( |
| const WebPoint& client_point, |
| const WebPoint& screen_point) { |
| DCHECK(current_drag_data_.get()); |
| |
| DragData drag_data( |
| current_drag_data_.get(), |
| webkit_glue::WebPointToIntPoint(client_point), |
| webkit_glue::WebPointToIntPoint(screen_point), |
| kDropTargetOperation); |
| |
| drop_effect_ = DROP_EFFECT_DEFAULT; |
| drag_target_dispatch_ = true; |
| DragOperation effect = page_->dragController()->dragUpdated(&drag_data); |
| drag_target_dispatch_ = false; |
| |
| if (drop_effect_ != DROP_EFFECT_DEFAULT) |
| return drop_accept_ = (drop_effect_ != DROP_EFFECT_NONE); |
| return drop_accept_ = (effect != DragOperationNone); |
| } |
| |
| void WebViewImpl::DragTargetDragLeave() { |
| DCHECK(current_drag_data_.get()); |
| |
| DragData drag_data( |
| current_drag_data_.get(), |
| IntPoint(), |
| IntPoint(), |
| kDropTargetOperation); |
| |
| drag_target_dispatch_ = true; |
| page_->dragController()->dragExited(&drag_data); |
| drag_target_dispatch_ = false; |
| |
| current_drag_data_ = NULL; |
| drop_effect_ = DROP_EFFECT_DEFAULT; |
| drop_accept_ = false; |
| drag_identity_ = 0; |
| } |
| |
| void WebViewImpl::DragTargetDrop( |
| const WebPoint& client_point, |
| const WebPoint& screen_point) { |
| DCHECK(current_drag_data_.get()); |
| |
| // If this webview transitions from the "drop accepting" state to the "not |
| // accepting" state, then our IPC message reply indicating that may be in- |
| // flight, or else delayed by javascript processing in this webview. If a |
| // drop happens before our IPC reply has reached the browser process, then |
| // the browser forwards the drop to this webview. So only allow a drop to |
| // proceed if our webview drop_accept_ state is true. |
| |
| if (!drop_accept_) { // IPC RACE CONDITION: do not allow this drop. |
| DragTargetDragLeave(); |
| return; |
| } |
| |
| DragData drag_data( |
| current_drag_data_.get(), |
| webkit_glue::WebPointToIntPoint(client_point), |
| webkit_glue::WebPointToIntPoint(screen_point), |
| kDropTargetOperation); |
| |
| drag_target_dispatch_ = true; |
| page_->dragController()->performDrag(&drag_data); |
| drag_target_dispatch_ = false; |
| |
| current_drag_data_ = NULL; |
| drop_effect_ = DROP_EFFECT_DEFAULT; |
| drop_accept_ = false; |
| drag_identity_ = 0; |
| } |
| |
| int32 WebViewImpl::GetDragIdentity() { |
| if (drag_target_dispatch_) |
| return drag_identity_; |
| return 0; |
| } |
| |
| bool WebViewImpl::SetDropEffect(bool accept) { |
| if (drag_target_dispatch_) { |
| drop_effect_ = accept ? DROP_EFFECT_COPY : DROP_EFFECT_NONE; |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| SearchableFormData* WebViewImpl::CreateSearchableFormDataForFocusedNode() { |
| if (!page_.get()) |
| return NULL; |
| |
| if (RefPtr<Frame> focused = page_->focusController()->focusedFrame()) { |
| RefPtr<Document> document = focused->document(); |
| if (document.get()) { |
| RefPtr<Node> focused_node = document->focusedNode(); |
| if (focused_node.get() && |
| focused_node->nodeType() == Node::ELEMENT_NODE) { |
| return SearchableFormData::Create( |
| static_cast<Element*>(focused_node.get())); |
| } |
| } |
| } |
| return NULL; |
| } |
| |
| void WebViewImpl::AutofillSuggestionsForNode( |
| int64 node_id, |
| const std::vector<std::wstring>& suggestions, |
| int default_suggestion_index) { |
| if (!page_.get() || suggestions.empty()) { |
| HideAutoCompletePopup(); |
| return; |
| } |
| |
| DCHECK(default_suggestion_index < static_cast<int>(suggestions.size())); |
| |
| if (RefPtr<Frame> focused = page_->focusController()->focusedFrame()) { |
| RefPtr<Document> document = focused->document(); |
| if (!document.get()) { |
| HideAutoCompletePopup(); |
| return; |
| } |
| |
| RefPtr<Node> focused_node = document->focusedNode(); |
| // If the node for which we queried the autofill suggestions is not the |
| // focused node, then we have nothing to do. |
| // TODO(jcampan): also check the carret is at the end and that the text has |
| // not changed. |
| if (!focused_node.get() || |
| reinterpret_cast<int64>(focused_node.get()) != node_id) { |
| HideAutoCompletePopup(); |
| return; |
| } |
| |
| if (!focused_node->hasTagName(WebCore::HTMLNames::inputTag)) { |
| NOTREACHED(); |
| return; |
| } |
| |
| WebCore::HTMLInputElement* input_elem = |
| static_cast<WebCore::HTMLInputElement*>(focused_node.get()); |
| |
| // The first time the autocomplete is shown we'll create the client and the |
| // popup. |
| if (!autocomplete_popup_client_.get()) |
| autocomplete_popup_client_.reset(new AutocompletePopupMenuClient(this)); |
| autocomplete_popup_client_->Init(input_elem, |
| suggestions, |
| default_suggestion_index); |
| if (!autocomplete_popup_.get()) { |
| autocomplete_popup_ = |
| WebCore::PopupContainer::create(autocomplete_popup_client_.get(), |
| kAutocompletePopupSettings); |
| } |
| |
| if (autocomplete_popup_showing_) { |
| autocomplete_popup_client_->SetSuggestions(suggestions); |
| RefreshAutofillPopup(); |
| } else { |
| autocomplete_popup_->show(focused_node->getRect(), |
| focused_node->ownerDocument()->view(), 0); |
| autocomplete_popup_showing_ = true; |
| } |
| } |
| } |
| |
| WebDevToolsAgent* WebViewImpl::GetWebDevToolsAgent() { |
| return GetWebDevToolsAgentImpl(); |
| } |
| |
| WebDevToolsAgentImpl* WebViewImpl::GetWebDevToolsAgentImpl() { |
| return devtools_agent_.get(); |
| } |
| |
| void WebViewImpl::SetIsTransparent(bool is_transparent) { |
| // Set any existing frames to be transparent. |
| WebCore::Frame* frame = page_->mainFrame(); |
| while (frame) { |
| frame->view()->setTransparent(is_transparent); |
| frame = frame->tree()->traverseNext(); |
| } |
| |
| // Future frames check this to know whether to be transparent. |
| is_transparent_ = is_transparent; |
| } |
| |
| bool WebViewImpl::GetIsTransparent() const { |
| return is_transparent_; |
| } |
| |
| void WebViewImpl::DidCommitLoad(bool* is_new_navigation) { |
| if (is_new_navigation) |
| *is_new_navigation = observed_new_navigation_; |
| |
| #ifndef NDEBUG |
| DCHECK(!observed_new_navigation_ || |
| page_->mainFrame()->loader()->documentLoader() == new_navigation_loader_); |
| new_navigation_loader_ = NULL; |
| #endif |
| observed_new_navigation_ = false; |
| } |
| |
| void WebViewImpl::StartDragging(const WebDragData& drag_data) { |
| if (delegate_) { |
| DCHECK(!doing_drag_and_drop_); |
| doing_drag_and_drop_ = true; |
| delegate_->StartDragging(this, drag_data); |
| } |
| } |
| |
| void WebViewImpl::ImageResourceDownloadDone(ImageResourceFetcher* fetcher, |
| bool errored, |
| const SkBitmap& image) { |
| if (delegate_) { |
| delegate_->DidDownloadImage(fetcher->id(), fetcher->image_url(), errored, |
| image); |
| } |
| DeleteImageResourceFetcher(fetcher); |
| } |
| |
| void WebViewImpl::SetCurrentHistoryItem(WebCore::HistoryItem* item) { |
| back_forward_list_client_impl_.SetCurrentHistoryItem(item); |
| } |
| |
| WebCore::HistoryItem* WebViewImpl::GetPreviousHistoryItem() { |
| return back_forward_list_client_impl_.GetPreviousHistoryItem(); |
| } |
| |
| void WebViewImpl::ObserveNewNavigation() { |
| observed_new_navigation_ = true; |
| #ifndef NDEBUG |
| new_navigation_loader_ = page_->mainFrame()->loader()->documentLoader(); |
| #endif |
| } |
| |
| void WebViewImpl::DeleteImageResourceFetcher(ImageResourceFetcher* fetcher) { |
| DCHECK(image_fetchers_.find(fetcher) != image_fetchers_.end()); |
| image_fetchers_.erase(fetcher); |
| |
| // We're in the callback from the ImageResourceFetcher, best to delay |
| // deletion. |
| MessageLoop::current()->DeleteSoon(FROM_HERE, fetcher); |
| } |
| |
| void WebViewImpl::HideAutoCompletePopup() { |
| if (autocomplete_popup_showing_) { |
| autocomplete_popup_->hidePopup(); |
| autocomplete_popup_showing_ = false; |
| } |
| } |
| |
| void WebViewImpl::SetIgnoreInputEvents(bool new_value) { |
| DCHECK(ignore_input_events_ != new_value); |
| ignore_input_events_ = new_value; |
| } |
| |
| WebCore::Node* WebViewImpl::GetNodeForWindowPos(int x, int y) { |
| HitTestResult result = HitTestResultForWindowPos(IntPoint(x, y)); |
| return result.innerNonSharedNode(); |
| } |
| |
| void WebViewImpl::HideAutofillPopup() { |
| HideAutoCompletePopup(); |
| } |
| |
| void WebViewImpl::RefreshAutofillPopup() { |
| DCHECK(autocomplete_popup_showing_); |
| |
| // Hide the popup if it has become empty. |
| if (autocomplete_popup_client_->listSize() == 0) { |
| HideAutoCompletePopup(); |
| return; |
| } |
| |
| IntRect old_bounds = autocomplete_popup_->boundsRect(); |
| autocomplete_popup_->refresh(); |
| IntRect new_bounds = autocomplete_popup_->boundsRect(); |
| // Let's resize the backing window if necessary. |
| if (old_bounds != new_bounds) { |
| WebWidgetImpl* web_widget = |
| static_cast<WebWidgetImpl*>(autocomplete_popup_->client()); |
| web_widget->delegate()->SetWindowRect( |
| web_widget, webkit_glue::IntRectToWebRect(new_bounds)); |
| } |
| } |
| |
| Node* WebViewImpl::GetFocusedNode() { |
| Frame* frame = page_->focusController()->focusedFrame(); |
| if (!frame) |
| return NULL; |
| |
| Document* document = frame->document(); |
| if (!document) |
| return NULL; |
| |
| return document->focusedNode(); |
| } |
| |
| HitTestResult WebViewImpl::HitTestResultForWindowPos(const IntPoint& pos) { |
| IntPoint doc_point( |
| page_->mainFrame()->view()->windowToContents(pos)); |
| return page_->mainFrame()->eventHandler()-> |
| hitTestResultAtPoint(doc_point, false); |
| } |