summaryrefslogtreecommitdiffstats
path: root/webkit/glue/webview_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'webkit/glue/webview_impl.cc')
-rw-r--r--webkit/glue/webview_impl.cc213
1 files changed, 209 insertions, 4 deletions
diff --git a/webkit/glue/webview_impl.cc b/webkit/glue/webview_impl.cc
index 814d168..5d3101c 100644
--- a/webkit/glue/webview_impl.cc
+++ b/webkit/glue/webview_impl.cc
@@ -35,6 +35,7 @@
#include "base/compiler_specific.h"
MSVC_PUSH_WARNING_LEVEL(0);
+#include "CSSStyleSelector.h"
#if defined(OS_WIN)
#include "Cursor.h"
#endif
@@ -50,6 +51,8 @@ MSVC_PUSH_WARNING_LEVEL(0);
#include "FrameTree.h"
#include "FrameView.h"
#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "HTMLInputElement.h"
#include "HitTestResult.h"
#include "Image.h"
#include "InspectorController.h"
@@ -61,9 +64,11 @@ MSVC_PUSH_WARNING_LEVEL(0);
#include "PlatformMouseEvent.h"
#include "PlatformWheelEvent.h"
#include "PluginInfoStore.h"
+#include "PopupMenuClient.h"
#if defined(OS_WIN)
#include "RenderThemeWin.h"
#endif
+#include "RenderView.h"
#include "ResourceHandle.h"
#include "SelectionController.h"
#include "Settings.h"
@@ -94,6 +99,7 @@ MSVC_POP_WARNING();
#include "webkit/glue/webview_delegate.h"
#include "webkit/glue/webview_impl.h"
#include "webkit/glue/webwidget_impl.h"
+#include "webkit/port/platform/chromium/PopupMenuChromium.h"
#include "webkit/port/platform/graphics/PlatformContextSkia.h"
// Get rid of WTF's pow define so we can use std::pow.
@@ -115,6 +121,126 @@ static const double kMaxTextSizeMultiplier = 3.0;
static const WebCore::DragOperation kDropTargetOperation =
static_cast<WebCore::DragOperation>(DragOperationCopy | DragOperationLink);
+// AutocompletePopupMenuClient
+class AutocompletePopupMenuClient
+ : public RefCounted<AutocompletePopupMenuClient>,
+ public WebCore::PopupMenuClient {
+ public:
+ AutocompletePopupMenuClient(WebViewImpl* webview,
+ WebCore::HTMLInputElement* text_field,
+ const std::vector<std::wstring>& suggestions,
+ int default_suggestion_index)
+ : text_field_(text_field),
+ selected_index_(default_suggestion_index),
+ webview_(webview) {
+ for (std::vector<std::wstring>::const_iterator iter = suggestions.begin();
+ iter != suggestions.end(); ++iter) {
+ suggestions_.push_back(webkit_glue::StdWStringToString(*iter));
+ }
+ }
+ virtual ~AutocompletePopupMenuClient() {
+ }
+
+ 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 menuStyle();
+ }
+
+ virtual PopupMenuStyle menuStyle() const {
+ RenderStyle* style = text_field_->renderStyle() ?
+ text_field_->renderStyle() :
+ text_field_->computedStyle();
+ return PopupMenuStyle(style->color(), Color::white, style->font(),
+ style->visibility() == VISIBLE);
+ }
+
+ virtual int clientInsetLeft() const {
+ return 0;
+ }
+ virtual int clientInsetRight() const {
+ return 0;
+ }
+ virtual int clientPaddingLeft() const {
+#if defined(OS_WIN)
+ return theme()->popupInternalPaddingLeft(text_field_->computedStyle());
+#else
+ NOTIMPLEMENTED();
+ return 0;
+#endif
+ }
+ virtual int clientPaddingRight() const {
+#if defined(OS_WIN)
+ return theme()->popupInternalPaddingRight(text_field_->computedStyle());
+#else
+ NOTIMPLEMENTED();
+ return 0;
+#endif
+ }
+ 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();
+ }
+
+ private:
+ RefPtr<WebCore::HTMLInputElement> text_field_;
+ std::vector<WebCore::String> suggestions_;
+ int selected_index_;
+ WebViewImpl* webview_;
+};
+
// WebView ----------------------------------------------------------------
/*static*/
@@ -292,6 +418,18 @@ bool WebViewImpl::KeyEvent(const WebKeyboardEvent& event) {
// event.
suppress_next_keypress_event_ = false;
+ // Give autocomplete a chance to consume the key events it is interested in.
+ if (autocomplete_popup_ &&
+ autocomplete_popup_->isInterestedInEventForKey(event.key_code)) {
+ if (autocomplete_popup_->handleKeyEvent(MakePlatformKeyboardEvent(event)))
+ return true;
+ return false;
+ }
+
+ // A new key being pressed should hide the popup.
+ if (event.type == WebInputEvent::KEY_DOWN)
+ HideAutoCompletePopup();
+
Frame* frame = GetFocusedWebCoreFrame();
if (!frame)
return false;
@@ -714,7 +852,6 @@ bool WebViewImpl::HandleInputEvent(const WebInputEvent* input_event) {
// we're done.
if (doing_drag_and_drop_)
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.
@@ -782,6 +919,14 @@ void WebViewImpl::SetBackForwardListSize(int size) {
void WebViewImpl::SetFocus(bool enable) {
if (enable) {
+ // Hide the popup menu if any.
+ // TODO(jcampan): bug #3844: we should do that when we lose focus. The
+ // reason we are not doing it is because when clicking on the autofill
+ // popup, the page first loses focus before the mouse click is sent to the
+ // popup. So if we close when the focus is lost, the mouse click does not
+ // do anything.
+ HideAutoCompletePopup();
+
// 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.
@@ -803,8 +948,6 @@ void WebViewImpl::SetFocus(bool enable) {
// updated below.
ReleaseFocusReferences();
- // Clear focus on the currently focused frame if any.
-
if (!main_frame_)
return;
@@ -1020,7 +1163,8 @@ void WebViewImpl::SetInitialFocus(bool reverse) {
// We have to set the key type explicitly to avoid an assert in the
// KeyboardEvent constructor.
platform_event.SetKeyType(PlatformKeyboardEvent::RawKeyDown);
- RefPtr<KeyboardEvent> webkit_event = KeyboardEvent::create(platform_event, NULL);
+ RefPtr<KeyboardEvent> webkit_event = KeyboardEvent::create(platform_event,
+ NULL);
page()->focusController()->setInitialFocus(
reverse ? WebCore::FocusDirectionBackward :
WebCore::FocusDirectionForward,
@@ -1333,6 +1477,59 @@ SearchableFormData* WebViewImpl::CreateSearchableFormDataForFocusedNode() {
return NULL;
}
+void WebViewImpl::AutofillSuggestionsForNode(
+ int64 node_id,
+ const std::vector<std::wstring>& suggestions,
+ int default_suggestion_index) {
+ if (!main_frame_ || suggestions.empty())
+ return;
+
+ DCHECK(default_suggestion_index < static_cast<int>(suggestions.size()));
+
+ Frame* frame = main_frame_->frame();
+ if (!frame)
+ return;
+
+ if (RefPtr<Frame> focused =
+ frame->page()->focusController()->focusedFrame()) {
+ RefPtr<Document> document = focused->document();
+ if (!document.get())
+ 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)
+ return;
+
+ if (!focused_node->hasTagName(WebCore::HTMLNames::inputTag)) {
+ NOTREACHED();
+ return;
+ }
+
+ WebCore::HTMLInputElement* input_elem =
+ static_cast<WebCore::HTMLInputElement*>(focused_node.get());
+ // Hide any current autocomplete popup.
+ HideAutoCompletePopup();
+
+ if (suggestions.size() > 0) {
+ autocomplete_popup_client_ =
+ adoptRef(new AutocompletePopupMenuClient(this, input_elem,
+ suggestions,
+ default_suggestion_index));
+ // Autocomplete popup does not get focused. We need the page to still
+ // have focus so the user can keep typing when the popup is showing.
+ autocomplete_popup_ =
+ WebCore::PopupContainer::create(autocomplete_popup_client_.get(),
+ false);
+ autocomplete_popup_->show(focused_node->getRect(), frame->view(), 0);
+ }
+ }
+}
+
void WebViewImpl::DidCommitLoad(bool* is_new_navigation) {
if (is_new_navigation)
*is_new_navigation = observed_new_navigation_;
@@ -1481,3 +1678,11 @@ void WebViewImpl::DeleteImageResourceFetcher(ImageResourceFetcher* fetcher) {
// deletion.
MessageLoop::current()->DeleteSoon(FROM_HERE, fetcher);
}
+
+void WebViewImpl::HideAutoCompletePopup() {
+ if (autocomplete_popup_) {
+ autocomplete_popup_->hidePopup();
+ autocomplete_popup_.clear();
+ autocomplete_popup_client_.clear();
+ }
+}