diff options
author | paulg@google.com <paulg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-24 19:05:03 +0000 |
---|---|---|
committer | paulg@google.com <paulg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-24 19:05:03 +0000 |
commit | 6b01318fe807d9a6dca2a31ce7f0242ef3c93453 (patch) | |
tree | 21d1c01eca0241e4b8526744b2dacb094967f2ac /webkit | |
parent | c4848bad345fa487c5abc4645d1721d38aa28ac5 (diff) | |
download | chromium_src-6b01318fe807d9a6dca2a31ce7f0242ef3c93453.zip chromium_src-6b01318fe807d9a6dca2a31ce7f0242ef3c93453.tar.gz chromium_src-6b01318fe807d9a6dca2a31ce7f0242ef3c93453.tar.bz2 |
First stage of implementing HTML select popup menus for
the Mac test_shell. Once the changes to
WebKit/WebCore/platform/chromium/PopupMenuChromium* have
been upstreamed (then landed in our tree), we can enable
them in test_shell.
The WebKit part is contained in this bug:
https://bugs.webkit.org/show_bug.cgi?id=24692
BUG=5095 (http://crbug.com/5095)
Review URL: http://codereview.chromium.org/48149
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12382 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/glue/chrome_client_impl.cc | 217 | ||||
-rw-r--r-- | webkit/glue/chrome_client_impl.h | 7 | ||||
-rw-r--r-- | webkit/glue/webwidget_delegate.h | 38 | ||||
-rw-r--r-- | webkit/glue/webwidget_impl.cc | 14 | ||||
-rw-r--r-- | webkit/glue/webwidget_impl.h | 8 | ||||
-rwxr-xr-x | webkit/tools/test_shell/mac/test_webview_delegate.mm | 145 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell_mac.mm | 3 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_webview_delegate.h | 5 | ||||
-rwxr-xr-x | webkit/tools/test_shell/test_webview_delegate_gtk.cc | 8 | ||||
-rwxr-xr-x | webkit/tools/test_shell/test_webview_delegate_win.cc | 8 |
10 files changed, 367 insertions, 86 deletions
diff --git a/webkit/glue/chrome_client_impl.cc b/webkit/glue/chrome_client_impl.cc index 972a643..6b574d5 100644 --- a/webkit/glue/chrome_client_impl.cc +++ b/webkit/glue/chrome_client_impl.cc @@ -15,6 +15,7 @@ MSVC_PUSH_WARNING_LEVEL(0); #include "HitTestResult.h" #include "IntRect.h" #include "Page.h" +#include "PopupMenuChromium.h" #include "ScriptController.h" #include "WindowFeatures.h" #if USE(V8) @@ -86,11 +87,11 @@ void ChromeClientImpl::chromeDestroyed() { } void ChromeClientImpl::setWindowRect(const WebCore::FloatRect& r) { - WebViewDelegate* d = webview_->delegate(); - if (d) { + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) { WebCore::IntRect ir(r); - d->SetWindowRect(webview_, - gfx::Rect(ir.x(), ir.y(), ir.width(), ir.height())); + delegate->SetWindowRect(webview_, + gfx::Rect(ir.x(), ir.y(), ir.width(), ir.height())); } } @@ -136,15 +137,15 @@ float ChromeClientImpl::scaleFactor() { } void ChromeClientImpl::focus() { - WebViewDelegate* d = webview_->delegate(); - if (d) - d->Focus(webview_); + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) + delegate->Focus(webview_); } void ChromeClientImpl::unfocus() { - WebViewDelegate* d = webview_->delegate(); - if (d) - d->Blur(webview_); + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) + delegate->Blur(webview_); } bool ChromeClientImpl::canTakeFocus(WebCore::FocusDirection) { @@ -154,23 +155,23 @@ bool ChromeClientImpl::canTakeFocus(WebCore::FocusDirection) { } void ChromeClientImpl::takeFocus(WebCore::FocusDirection direction) { - WebViewDelegate* d = webview_->delegate(); - if (d) { - d->TakeFocus(webview_, - direction == WebCore::FocusDirectionBackward); + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) { + delegate->TakeFocus(webview_, + direction == WebCore::FocusDirectionBackward); } } WebCore::Page* ChromeClientImpl::createWindow( WebCore::Frame* frame, const WebCore::FrameLoadRequest& r, const WebCore::WindowFeatures& features) { - WebViewDelegate* d = webview_->delegate(); - if (!d) + WebViewDelegate* delegate = webview_->delegate(); + if (!delegate) return NULL; bool userGesture = frame->script()->processingUserGesture(); WebViewImpl* new_view = static_cast<WebViewImpl*>( - d->CreateWebView(webview_, userGesture)); + delegate->CreateWebView(webview_, userGesture)); if (!new_view) return NULL; @@ -198,8 +199,8 @@ static inline bool CurrentEventShouldCauseBackgroundTab( } void ChromeClientImpl::show() { - WebViewDelegate* d = webview_->delegate(); - if (d) { + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) { // If our default configuration was modified by a script or wasn't // created by a user gesture, then show as a popup. Else, let this // new window be opened as a toplevel window. @@ -210,7 +211,7 @@ void ChromeClientImpl::show() { !scrollbars_visible_ || !menubar_visible_ || !resizable_ || - !d->WasOpenedByUserGesture(webview_); + !delegate->WasOpenedByUserGesture(webview_); WindowOpenDisposition disposition = NEW_FOREGROUND_TAB; if (as_popup) @@ -218,7 +219,7 @@ void ChromeClientImpl::show() { if (CurrentEventShouldCauseBackgroundTab(WebViewImpl::current_input_event())) disposition = NEW_BACKGROUND_TAB; - d->Show(webview_, disposition); + delegate->Show(webview_, disposition); } } @@ -227,9 +228,9 @@ bool ChromeClientImpl::canRunModal() { } void ChromeClientImpl::runModal() { - WebViewDelegate* d = webview_->delegate(); - if (d) - d->RunModal(webview_); + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) + delegate->RunModal(webview_); } void ChromeClientImpl::setToolbarsVisible(bool value) { @@ -275,11 +276,12 @@ void ChromeClientImpl::setResizable(bool value) { void ChromeClientImpl::addMessageToConsole(const WebCore::String& message, unsigned int line_no, const WebCore::String& source_id) { - WebViewDelegate* d = webview_->delegate(); - if (d) { + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) { std::wstring wstr_message = webkit_glue::StringToStdWString(message); std::wstring wstr_source_id = webkit_glue::StringToStdWString(source_id); - d->AddMessageToConsole(webview_, wstr_message, line_no, wstr_source_id); + delegate->AddMessageToConsole(webview_, wstr_message, + line_no, wstr_source_id); } } @@ -290,10 +292,11 @@ bool ChromeClientImpl::canRunBeforeUnloadConfirmPanel() { bool ChromeClientImpl::runBeforeUnloadConfirmPanel( const WebCore::String& message, WebCore::Frame* frame) { - WebViewDelegate* d = webview_->delegate(); - if (d) { + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) { std::wstring wstr = webkit_glue::StringToStdWString(message); - return d->RunBeforeUnloadConfirm(WebFrameImpl::FromFrame(frame), wstr); + return delegate->RunBeforeUnloadConfirm(WebFrameImpl::FromFrame(frame), + wstr); } return false; } @@ -305,9 +308,9 @@ void ChromeClientImpl::closeWindowSoon() { // Make sure that all loading is stopped. Ensures that JS stops executing! webview_->StopLoading(); - WebViewDelegate* d = webview_->delegate(); - if (d) - d->CloseWidgetSoon(webview_); + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) + delegate->CloseWidgetSoon(webview_); } // Although a WebCore::Frame is passed in, we don't actually use it, since we @@ -315,8 +318,8 @@ void ChromeClientImpl::closeWindowSoon() { void ChromeClientImpl::runJavaScriptAlert(WebCore::Frame* frame, const WebCore::String& message) { // Pass the request on to the WebView delegate, for more control. - WebViewDelegate* d = webview_->delegate(); - if (d) { + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) { #if USE(V8) // Before showing the JavaScript dialog, we give the proxy implementation // a chance to process any pending console messages. @@ -324,17 +327,17 @@ void ChromeClientImpl::runJavaScriptAlert(WebCore::Frame* frame, #endif std::wstring wstr = webkit_glue::StringToStdWString(message); - d->RunJavaScriptAlert(WebFrameImpl::FromFrame(frame), wstr); + delegate->RunJavaScriptAlert(WebFrameImpl::FromFrame(frame), wstr); } } // See comments for runJavaScriptAlert(). bool ChromeClientImpl::runJavaScriptConfirm(WebCore::Frame* frame, const WebCore::String& message) { - WebViewDelegate* d = webview_->delegate(); - if (d) { + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) { std::wstring wstr = webkit_glue::StringToStdWString(message); - return d->RunJavaScriptConfirm(WebFrameImpl::FromFrame(frame), wstr); + return delegate->RunJavaScriptConfirm(WebFrameImpl::FromFrame(frame), wstr); } return false; } @@ -344,15 +347,15 @@ bool ChromeClientImpl::runJavaScriptPrompt(WebCore::Frame* frame, const WebCore::String& message, const WebCore::String& defaultValue, WebCore::String& result) { - WebViewDelegate* d = webview_->delegate(); - if (d) { + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) { std::wstring wstr_message = webkit_glue::StringToStdWString(message); std::wstring wstr_default = webkit_glue::StringToStdWString(defaultValue); std::wstring wstr_result; - bool ok = d->RunJavaScriptPrompt(WebFrameImpl::FromFrame(frame), - wstr_message, - wstr_default, - &wstr_result); + bool ok = delegate->RunJavaScriptPrompt(WebFrameImpl::FromFrame(frame), + wstr_message, + wstr_default, + &wstr_result); if (ok) result = webkit_glue::StdWStringToString(wstr_result); return ok; @@ -361,10 +364,10 @@ bool ChromeClientImpl::runJavaScriptPrompt(WebCore::Frame* frame, } void ChromeClientImpl::setStatusbarText(const WebCore::String& message) { - WebViewDelegate* d = webview_->delegate(); - if (d) { + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) { std::wstring wstr = webkit_glue::StringToStdWString(message); - d->SetStatusbarText(webview_, wstr); + delegate->SetStatusbarText(webview_, wstr); } } @@ -400,19 +403,20 @@ void ChromeClientImpl::repaint( // Ignore spurious calls. if (!content_changed || paint_rect.isEmpty()) return; - WebViewDelegate* d = webview_->delegate(); - if (d) - d->DidInvalidateRect(webview_, webkit_glue::FromIntRect(paint_rect)); + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) + delegate->DidInvalidateRect(webview_, webkit_glue::FromIntRect(paint_rect)); } void ChromeClientImpl::scroll( const WebCore::IntSize& scroll_delta, const WebCore::IntRect& scroll_rect, const WebCore::IntRect& clip_rect) { - WebViewDelegate* d = webview_->delegate(); - if (d) { + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) { int dx = scroll_delta.width(); int dy = scroll_delta.height(); - d->DidScrollRect(webview_, dx, dy, webkit_glue::FromIntRect(clip_rect)); + delegate->DidScrollRect(webview_, dx, dy, + webkit_glue::FromIntRect(clip_rect)); } } @@ -426,10 +430,10 @@ WebCore::IntRect ChromeClientImpl::windowToScreen( const WebCore::IntRect& rect) const { WebCore::IntRect screen_rect(rect); - WebViewDelegate* d = webview_->delegate(); - if (d) { + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) { gfx::Rect window_rect; - d->GetWindowRect(webview_, &window_rect); + delegate->GetWindowRect(webview_, &window_rect); screen_rect.move(window_rect.x(), window_rect.y()); } @@ -437,19 +441,20 @@ WebCore::IntRect ChromeClientImpl::windowToScreen( } PlatformWidget ChromeClientImpl::platformWindow() const { - WebViewDelegate* d = webview_->delegate(); - return d ? d->GetContainingView(webview_) : NULL; + WebViewDelegate* delegate = webview_->delegate(); + return delegate ? delegate->GetContainingView(webview_) : NULL; } void ChromeClientImpl::mouseDidMoveOverElement( const WebCore::HitTestResult& result, unsigned modifierFlags) { // Find out if the mouse is over a link, and if so, let our UI know... somehow - WebViewDelegate* d = webview_->delegate(); - if (d) { + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) { if (result.isLiveLink() && !result.absoluteLinkURL().string().isEmpty()) { - d->UpdateTargetURL(webview_, webkit_glue::KURLToGURL(result.absoluteLinkURL())); + delegate->UpdateTargetURL( + webview_, webkit_glue::KURLToGURL(result.absoluteLinkURL())); } else { - d->UpdateTargetURL(webview_, GURL()); + delegate->UpdateTargetURL(webview_, GURL()); } } } @@ -463,9 +468,9 @@ void ChromeClientImpl::setToolTip(const WebCore::String& tooltip_text) { } void ChromeClientImpl::print(WebCore::Frame* frame) { - WebViewDelegate* d = webview_->delegate(); - if (d) { - d->ScriptedPrint(WebFrameImpl::FromFrame(frame)); + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) { + delegate->ScriptedPrint(WebFrameImpl::FromFrame(frame)); } } @@ -494,24 +499,72 @@ void ChromeClientImpl::runOpenPanel(WebCore::Frame* frame, void ChromeClientImpl::popupOpened(WebCore::FramelessScrollView* popup_view, const WebCore::IntRect& bounds, bool activatable) { - WebViewDelegate* d = webview_->delegate(); - if (d) { + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) { WebWidgetImpl* webwidget = - static_cast<WebWidgetImpl*>(d->CreatePopupWidget(webview_, - activatable)); + static_cast<WebWidgetImpl*>(delegate->CreatePopupWidget(webview_, + activatable)); webwidget->Init(popup_view, webkit_glue::FromIntRect(bounds)); } } +void ChromeClientImpl::popupOpenedWithItems( + WebCore::FramelessScrollView* popup_view, + const WebCore::IntRect& bounds, + bool activatable, + int item_height, + int selected_index, + const WTF::Vector<WebCore::PopupListData*>& items) { + /* + Uncomment this section once the changes to + WebKit/WebCore/platform/chromium/PopupMenuChromium* have landed in our tree. + + WebViewDelegate* delegate = webview_->delegate(); + if (!delegate) + return; + + WebWidgetImpl* webwidget = + static_cast<WebWidgetImpl*>(delegate->CreatePopupWidget(webview_, + activatable)); + // Convert WebKit types for Chromium. + std::vector<MenuItem> popup_items; + for (int i = 0; i < items.size(); ++i) { + MenuItem menu_item; + menu_item.label = webkit_glue::StringToString16(items[i]->label); + menu_item.enabled = items[i]->enabled; + switch (items[i]->type) { + case WebCore::PopupListData::TypeOption: + menu_item.type = MenuItem::OPTION; + break; + case WebCore::PopupListData::TypeGroup: + menu_item.type = MenuItem::GROUP; + break; + case WebCore::PopupListData::TypeSeparator: + menu_item.type = MenuItem::SEPARATOR; + break; + default: + NOTIMPLEMENTED(); + } + popup_items.push_back(menu_item); + } + + webwidget->InitWithItems(popup_view, + webkit_glue::FromIntRect(bounds), + item_height, + selected_index, + popup_items); + */ +} + void ChromeClientImpl::SetCursor(const WebCursor& cursor) { if (ignore_next_set_cursor_) { ignore_next_set_cursor_ = false; return; } - WebViewDelegate* d = webview_->delegate(); - if (d) - d->SetCursor(webview_, cursor); + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) + delegate->SetCursor(webview_, cursor); } void ChromeClientImpl::SetCursorForPlugin(const WebCursor& cursor) { @@ -523,19 +576,19 @@ void ChromeClientImpl::SetCursorForPlugin(const WebCursor& cursor) { } void ChromeClientImpl::enableSuddenTermination() { - WebViewDelegate* d = webview_->delegate(); - if (d) - d->EnableSuddenTermination(); + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) + delegate->EnableSuddenTermination(); } void ChromeClientImpl::disableSuddenTermination() { - WebViewDelegate* d = webview_->delegate(); - if (d) - d->DisableSuddenTermination(); + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) + delegate->DisableSuddenTermination(); } void ChromeClientImpl::formStateDidChange(const WebCore::Node*) { - WebViewDelegate* d = webview_->delegate(); - if (d) - d->OnNavStateChanged(webview_); + WebViewDelegate* delegate = webview_->delegate(); + if (delegate) + delegate->OnNavStateChanged(webview_); } diff --git a/webkit/glue/chrome_client_impl.h b/webkit/glue/chrome_client_impl.h index 2c6fc22..bf515d2 100644 --- a/webkit/glue/chrome_client_impl.h +++ b/webkit/glue/chrome_client_impl.h @@ -15,6 +15,7 @@ class WebCursor; class WebViewImpl; namespace WebCore { +struct PopupListData; class SecurityOrigin; struct WindowFeatures; } @@ -118,6 +119,12 @@ class ChromeClientImpl : public WebCore::ChromeClientChromium { virtual void popupOpened(WebCore::FramelessScrollView* popup_view, const WebCore::IntRect& bounds, bool activatable); + void popupOpenedWithItems(WebCore::FramelessScrollView* popupView, + const WebCore::IntRect& bounds, + bool activatable, + int item_height, + int selected_index, + const WTF::Vector<WebCore::PopupListData*>& items); void SetCursor(const WebCursor& cursor); void SetCursorForPlugin(const WebCursor& cursor); diff --git a/webkit/glue/webwidget_delegate.h b/webkit/glue/webwidget_delegate.h index 010a7d0..05ed760 100644 --- a/webkit/glue/webwidget_delegate.h +++ b/webkit/glue/webwidget_delegate.h @@ -5,7 +5,11 @@ #ifndef WEBKIT_GLUE_WEBWIDGET_DELEGATE_H__ #define WEBKIT_GLUE_WEBWIDGET_DELEGATE_H__ +#include <string> +#include <vector> + #include "base/gfx/native_widget_types.h" +#include "base/string16.h" #include "webkit/glue/window_open_disposition.h" namespace gfx { @@ -17,6 +21,22 @@ class WebWidget; class WebCursor; struct WebPluginGeometry; +struct MenuItem { + // Container for information about entries in an HTML select popup menu. + // Types must be kept in sync with PopupListBox::ListItemType in + // WebCore/platform/chromium/PopupMenuChromium.h. This won't change often + // (if ever). + enum Type { + OPTION = 0, + GROUP, + SEPARATOR + }; + + string16 label; + Type type; + bool enabled; +}; + class WebWidgetDelegate { public: // Returns the view in which the WebWidget is embedded. @@ -36,6 +56,22 @@ class WebWidgetDelegate { // window should be displayed, but generally only means something for WebViews. virtual void Show(WebWidget* webwidget, WindowOpenDisposition disposition) = 0; + // Used for displaying HTML select elements as popup menus on Mac OS X (other + // platforms will use Show() above). |bounds| represents the positioning on + // the screen (in WebKit coordinates, origin at the top left corner) of the + // button that will display the menu. It will be used, along with + // |item_height| (which refers to the size of each entry in the menu), to + // position the menu on the screen. |selected_index| indicates the menu item + // that should be drawn as selected when the menu initially is displayed. + // |items| contains information about each of the entries in the popup menu, + // such as the type (separator, option, group), the text representation and + // the item's enabled status. + virtual void ShowWithItems(WebWidget* webwidget, + const gfx::Rect& bounds, + int item_height, + int selected_index, + const std::vector<MenuItem>& items) = 0; + // This method is called to instruct the window containing the WebWidget to // close. Note: This method should just be the trigger that causes the // WebWidget to eventually close. It should not actually be destroyed until @@ -91,7 +127,7 @@ class WebWidgetDelegate { virtual ~WebWidgetDelegate() { } private: - DISALLOW_EVIL_CONSTRUCTORS(WebWidgetDelegate); + DISALLOW_COPY_AND_ASSIGN(WebWidgetDelegate); }; #endif // #ifndef WEBKIT_GLUE_WEBWIDGET_DELEGATE_H__ diff --git a/webkit/glue/webwidget_impl.cc b/webkit/glue/webwidget_impl.cc index b745a66..5cf6bbe 100644 --- a/webkit/glue/webwidget_impl.cc +++ b/webkit/glue/webwidget_impl.cc @@ -62,6 +62,20 @@ void WebWidgetImpl::Init(WebCore::FramelessScrollView* widget, } } +void WebWidgetImpl::InitWithItems(WebCore::FramelessScrollView* widget, + const gfx::Rect& bounds, + int item_height, + int selected_index, + const std::vector<MenuItem>& items) { + widget_ = widget; + widget_->setClient(this); + + if (delegate_) { + delegate_->SetWindowRect(this, bounds); + delegate_->ShowWithItems(this, bounds, item_height, selected_index, items); + } +} + void WebWidgetImpl::MouseMove(const WebMouseEvent& event) { // don't send mouse move messages if the mouse hasn't moved. if (event.x != last_mouse_position_.x() || diff --git a/webkit/glue/webwidget_impl.h b/webkit/glue/webwidget_impl.h index efb1b65..e6decf4 100644 --- a/webkit/glue/webwidget_impl.h +++ b/webkit/glue/webwidget_impl.h @@ -25,6 +25,7 @@ namespace WebCore { class Widget; } +struct MenuItem; class WebKeyboardEvent; class WebMouseEvent; class WebMouseWheelEvent; @@ -53,6 +54,11 @@ class WebWidgetImpl : public WebWidget, // WebWidgetImpl void Init(WebCore::FramelessScrollView* widget, const gfx::Rect& bounds); + void InitWithItems(WebCore::FramelessScrollView* widget, + const gfx::Rect& bounds, + int item_height, + int selected_index, + const std::vector<MenuItem>& items); const gfx::Size& size() const { return size_; } @@ -110,7 +116,7 @@ class WebWidgetImpl : public WebWidget, WebCore::FramelessScrollView* widget_; private: - DISALLOW_EVIL_CONSTRUCTORS(WebWidgetImpl); + DISALLOW_COPY_AND_ASSIGN(WebWidgetImpl); }; #endif // WEBKIT_GLUE_WEBWIDGET_IMPL_H__ diff --git a/webkit/tools/test_shell/mac/test_webview_delegate.mm b/webkit/tools/test_shell/mac/test_webview_delegate.mm index e80f75a..039e34f3 100755 --- a/webkit/tools/test_shell/mac/test_webview_delegate.mm +++ b/webkit/tools/test_shell/mac/test_webview_delegate.mm @@ -5,6 +5,7 @@ #include "webkit/tools/test_shell/test_webview_delegate.h" #import <Cocoa/Cocoa.h> +#include "base/sys_string_conversions.h" #include "base/string_util.h" #include "webkit/glue/webcursor.h" #include "webkit/glue/webview.h" @@ -12,6 +13,63 @@ #include "webkit/glue/plugins/webplugin_delegate_impl.h" #include "webkit/tools/test_shell/test_shell.h" +// MenuDelegate ---------------------------------------------------------------- +// A class for determining whether an item was selected from an HTML select +// control, or if the menu was dismissed without making a selection. If a menu +// item is selected, MenuDelegate is informed and sets a flag which can be +// queried after the menu has finished running. + +@interface MenuDelegate : NSObject { + @private + NSMenu* menu_; // Non-owning + BOOL menuItemWasChosen_; +} +- (id)initWithItems:(const std::vector<MenuItem>&)items forMenu:(NSMenu*)menu; +- (void)addItem:(const MenuItem&)item; +- (BOOL)menuItemWasChosen; +- (void)menuItemSelected:(id)sender; +@end + +@implementation MenuDelegate + +- (id)initWithItems:(const std::vector<MenuItem>&)items forMenu:(NSMenu*)menu { + if ((self = [super init])) { + menu_ = menu; + menuItemWasChosen_ = NO; + for (int i = 0; i < static_cast<int>(items.size()); ++i) + [self addItem:items[i]]; + } + return self; +} + +- (void)addItem:(const MenuItem&)item { + if (item.type == MenuItem::SEPARATOR) { + [menu_ addItem:[NSMenuItem separatorItem]]; + return; + } + + NSString* title = base::SysUTF16ToNSString(item.label); + NSMenuItem* menu_item = [menu_ addItemWithTitle:title + action:@selector(menuItemSelected:) + keyEquivalent:@""]; + [menu_item setEnabled:(item.enabled && item.type != MenuItem::GROUP)]; + [menu_item setTarget:self]; +} + +// Reflects the result of the user's interaction with the popup menu. If NO, the +// menu was dismissed without the user choosing an item, which can happen if the +// user clicked outside the menu region or hit the escape key. If YES, the user +// selected an item from the menu. +- (BOOL)menuItemWasChosen { + return menuItemWasChosen_; +} + +- (void)menuItemSelected:(id)sender { + menuItemWasChosen_ = YES; +} + +@end // MenuDelegate + // WebViewDelegate ----------------------------------------------------------- @@ -60,6 +118,93 @@ void TestWebViewDelegate::Show(WebWidget* webview, WindowOpenDisposition disposition) { } +// Display a HTML select menu. +void TestWebViewDelegate::ShowWithItems( + WebWidget* webview, + const gfx::Rect& bounds, + int item_height, + int selected_index, + const std::vector<MenuItem>& items) { + // Populate the menu. + NSMenu* menu = [[[NSMenu alloc] initWithTitle:@""] autorelease]; + [menu setAutoenablesItems:NO]; + MenuDelegate* menu_delegate = + [[[MenuDelegate alloc] initWithItems:items forMenu:menu] autorelease]; + + // Set up the button cell, converting to NSView coordinates. The menu is + // positioned such that the currently selected menu item appears over the + // popup button, which is the expected Mac popup menu behavior. + NSPopUpButtonCell* button = [[NSPopUpButtonCell alloc] initTextCell:@"" + pullsDown:NO]; + [button autorelease]; + [button setMenu:menu]; + [button selectItemAtIndex:selected_index]; + NSView* web_view = shell_->webViewWnd(); + NSRect view_rect = [web_view bounds]; + int y_offset = bounds.y() + bounds.height(); + NSRect position = NSMakeRect(bounds.x(), view_rect.size.height - y_offset, + bounds.width(), bounds.height()); + + // Display the menu, and set a flag to determine if something was chosen. If + // nothing was chosen (i.e., the user dismissed the popup by the "ESC" key or + // clicking outside popup's region), send a dismiss message to WebKit. + [button performClickWithFrame:position inView:shell_->webViewWnd()]; + + // Get the selected item and forward to WebKit. WebKit expects an input event + // (mouse down, keyboard activity) for this, so we calculate the proper + // position based on the selected index and provided bounds. + WebWidgetHost* popup = shell_->popupHost(); + NSEvent* event = nil; + double event_time = (double)(AbsoluteToDuration(UpTime())) / 1000.0; + int window_num = [shell_->mainWnd() windowNumber]; + + if ([menu_delegate menuItemWasChosen]) { + // Construct a mouse up event to simulate the selection of an appropriate + // menu item. + NSPoint click_pos; + click_pos.x = position.size.width / 2; + + // This is going to be hard to calculate since the button is painted by + // WebKit, the menu by Cocoa, and we have to translate the selected_item + // index to a coordinate that WebKit's PopupMenu expects which uses a + // different font *and* expects to draw the menu below the button like we do + // on Windows. + // The WebKit popup menu thinks it will draw just below the button, so + // create the click at the offset based on the selected item's index and + // account for the different coordinate system used by NSView. + int item_offset = [button indexOfSelectedItem] * item_height + + item_height / 2; + click_pos.y = view_rect.size.height - item_offset; + event = [NSEvent mouseEventWithType:NSLeftMouseUp + location:click_pos + modifierFlags:0 + timestamp:event_time + windowNumber:window_num + context:nil + eventNumber:0 + clickCount:1 + pressure:1.0]; + popup->MouseEvent(event); + } else { + // Fake an ESC key event (keyCode = 0x1B, from webinputevent_mac.mm) and + // forward that to WebKit. + NSPoint key_pos; + key_pos.x = 0; + key_pos.y = 0; + event = [NSEvent keyEventWithType:NSKeyUp + location:key_pos + modifierFlags:0 + timestamp:event_time + windowNumber:window_num + context:nil + characters:@"" + charactersIgnoringModifiers:@"" + isARepeat:NO + keyCode:0x1B]; + popup->KeyEvent(event); + } +} + void TestWebViewDelegate::CloseWidgetSoon(WebWidget* webwidget) { if (webwidget == shell_->webView()) { NSWindow *win = shell_->mainWnd(); diff --git a/webkit/tools/test_shell/test_shell_mac.mm b/webkit/tools/test_shell/test_shell_mac.mm index a3cd0f1..5df878e 100644 --- a/webkit/tools/test_shell/test_shell_mac.mm +++ b/webkit/tools/test_shell/test_shell_mac.mm @@ -460,8 +460,7 @@ void TestShell::DestroyWindow(gfx::NativeWindow windowHandle) { WebWidget* TestShell::CreatePopupWidget(WebView* webview) { DCHECK(!m_popupHost); - m_popupHost = WebWidgetHost::Create(NULL, delegate_.get()); - // ShowWindow(popupWnd(), SW_SHOW); + m_popupHost = WebWidgetHost::Create(webViewWnd(), delegate_.get()); return m_popupHost->webwidget(); } diff --git a/webkit/tools/test_shell/test_webview_delegate.h b/webkit/tools/test_shell/test_webview_delegate.h index a0dcbf9..c24eccc 100644 --- a/webkit/tools/test_shell/test_webview_delegate.h +++ b/webkit/tools/test_shell/test_webview_delegate.h @@ -214,6 +214,11 @@ class TestWebViewDelegate : public base::RefCounted<TestWebViewDelegate>, virtual void DidScrollRect(WebWidget* webwidget, int dx, int dy, const gfx::Rect& clip_rect); virtual void Show(WebWidget* webview, WindowOpenDisposition disposition); + virtual void ShowWithItems(WebWidget* webwidget, + const gfx::Rect& bounds, + int item_height, + int selected_index, + const std::vector<MenuItem>& items); virtual void CloseWidgetSoon(WebWidget* webwidget); virtual void Focus(WebWidget* webwidget); virtual void Blur(WebWidget* webwidget); diff --git a/webkit/tools/test_shell/test_webview_delegate_gtk.cc b/webkit/tools/test_shell/test_webview_delegate_gtk.cc index 8c9399c..620de76 100755 --- a/webkit/tools/test_shell/test_webview_delegate_gtk.cc +++ b/webkit/tools/test_shell/test_webview_delegate_gtk.cc @@ -113,6 +113,14 @@ void TestWebViewDelegate::Show(WebWidget* webwidget, gtk_widget_show_all(window); } +void TestWebViewDelegate::ShowWithItems(WebWidget* webwidget, + const gfx::Rect& bounds, + int item_height, + int selected_index, + const std::vector<MenuItem>& items) { + NOTIMPLEMENTED(); +} + void TestWebViewDelegate::CloseWidgetSoon(WebWidget* webwidget) { if (webwidget == shell_->webView()) { MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction( diff --git a/webkit/tools/test_shell/test_webview_delegate_win.cc b/webkit/tools/test_shell/test_webview_delegate_win.cc index 6a10617..ff4a7e2 100755 --- a/webkit/tools/test_shell/test_webview_delegate_win.cc +++ b/webkit/tools/test_shell/test_webview_delegate_win.cc @@ -78,6 +78,14 @@ void TestWebViewDelegate::Show(WebWidget* webwidget, WindowOpenDisposition) { } } +void TestWebViewDelegate::ShowWithItems(WebWidget* webwidget, + const gfx::Rect& bounds, + int item_height, + int selected_index, + const std::vector<MenuItem>& items) { + NOTIMPLEMENTED(); +} + void TestWebViewDelegate::CloseWidgetSoon(WebWidget* webwidget) { if (webwidget == shell_->webView()) { PostMessage(shell_->mainWnd(), WM_CLOSE, 0, 0); |