summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpaul@chromium.org <paul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-24 21:12:11 +0000
committerpaul@chromium.org <paul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-24 21:12:11 +0000
commite344a05a48730f00fe670e6ceb00afdc8b1be414 (patch)
tree7d0ef6750ff61630da9eb1c5e52091711e4a950d
parent35e6071b402c63474795843629533a2444f8e8ad (diff)
downloadchromium_src-e344a05a48730f00fe670e6ceb00afdc8b1be414.zip
chromium_src-e344a05a48730f00fe670e6ceb00afdc8b1be414.tar.gz
chromium_src-e344a05a48730f00fe670e6ceb00afdc8b1be414.tar.bz2
Implement HTML selects as native Cocoa controls for Chrome.
BUG=8389 (http://crbug.com/8389) Review URL: http://codereview.chromium.org/57032 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14471 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/renderer_host/render_widget_host.cc18
-rw-r--r--chrome/browser/renderer_host/render_widget_host.h1
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view.h13
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.h9
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.mm40
-rw-r--r--chrome/browser/renderer_host/test_render_view_host.h6
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_mac.mm3
-rw-r--r--chrome/common/render_messages.h105
-rw-r--r--chrome/common/render_messages_internal.h5
-rw-r--r--chrome/renderer/render_widget.cc11
10 files changed, 205 insertions, 6 deletions
diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc
index 64fb609..9e07de7 100644
--- a/chrome/browser/renderer_host/render_widget_host.cc
+++ b/chrome/browser/renderer_host/render_widget_host.cc
@@ -114,6 +114,7 @@ IPC_DEFINE_MESSAGE_MAP(RenderWidgetHost)
IPC_MESSAGE_HANDLER(ViewHostMsg_Blur, OnMsgBlur)
IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnMsgSetCursor)
IPC_MESSAGE_HANDLER(ViewHostMsg_ImeUpdateStatus, OnMsgImeUpdateStatus)
+ IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_ShowPopup, OnMsgShowPopup(msg))
IPC_MESSAGE_UNHANDLED_ERROR()
IPC_END_MESSAGE_MAP()
@@ -662,6 +663,23 @@ void RenderWidgetHost::OnMsgImeUpdateStatus(int control,
}
}
+void RenderWidgetHost::OnMsgShowPopup(const IPC::Message& message) {
+#if defined(OS_MACOSX)
+ void* iter = NULL;
+ ViewHostMsg_ShowPopup_Params validated_params;
+ if (!IPC::ParamTraits<ViewHostMsg_ShowPopup_Params>::Read(&message, &iter,
+ &validated_params))
+ return;
+
+ view_->ShowPopupWithItems(validated_params.bounds,
+ validated_params.item_height,
+ validated_params.selected_item,
+ validated_params.popup_items);
+#else // OS_WIN || OS_LINUX
+ NOTREACHED();
+#endif
+}
+
void RenderWidgetHost::PaintBackingStoreRect(TransportDIB* bitmap,
const gfx::Rect& bitmap_rect,
const gfx::Size& view_size) {
diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h
index ad81ad8..0e93a84 100644
--- a/chrome/browser/renderer_host/render_widget_host.h
+++ b/chrome/browser/renderer_host/render_widget_host.h
@@ -318,6 +318,7 @@ class RenderWidgetHost : public IPC::Channel::Listener {
// Using int instead of ViewHostMsg_ImeControl for control's type to avoid
// having to bring in render_messages.h in a header file.
void OnMsgImeUpdateStatus(int control, const gfx::Rect& caret_rect);
+ void OnMsgShowPopup(const IPC::Message& message);
// Paints the given bitmap to the current backing store at the given location.
void PaintBackingStoreRect(TransportDIB* dib,
diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h
index beec90e..7053150 100644
--- a/chrome/browser/renderer_host/render_widget_host_view.h
+++ b/chrome/browser/renderer_host/render_widget_host_view.h
@@ -7,8 +7,9 @@
#include "base/gfx/native_widget_types.h"
#include "base/shared_memory.h"
-#include "webkit/glue/webplugin.h"
#include "skia/include/SkBitmap.h"
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/webwidget_delegate.h"
namespace gfx {
class Rect;
@@ -136,6 +137,14 @@ class RenderWidgetHostView {
// Allocate a backing store for this view
virtual BackingStore* AllocBackingStore(const gfx::Size& size) = 0;
+#if defined(OS_MACOSX)
+ // Display a native control popup menu for WebKit.
+ virtual void ShowPopupWithItems(gfx::Rect bounds,
+ int item_height,
+ int selected_item,
+ const std::vector<WebMenuItem>& items) = 0;
+#endif
+
void set_activatable(bool activatable) {
activatable_ = activatable;
}
@@ -151,7 +160,7 @@ class RenderWidgetHostView {
protected:
// Interface class only, do not construct.
RenderWidgetHostView() : activatable_(true) {}
-
+
// Whether the window can be activated. Autocomplete popup windows for example
// cannot be activated. Default is true.
bool activatable_;
diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.h b/chrome/browser/renderer_host/render_widget_host_view_mac.h
index 4c1e266..e04b822 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h
@@ -82,9 +82,15 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView {
virtual void Destroy();
virtual void SetTooltipText(const std::wstring& tooltip_text);
virtual BackingStore* AllocBackingStore(const gfx::Size& size);
+ virtual void ShowPopupWithItems(gfx::Rect bounds,
+ int item_height,
+ int selected_item,
+ const std::vector<WebMenuItem>& items);
void KillSelf();
+ void set_parent_view(BaseView* parent_view) { parent_view_ = parent_view; }
+
// These member variables should be private, but the associated ObjC class
// needs access to them and can't be made a friend.
@@ -131,6 +137,9 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView {
// Factory used to safely scope delayed calls to ShutdownHost().
ScopedRunnableMethodFactory<RenderWidgetHostViewMac> shutdown_factory_;
+ // Used for positioning a popup menu.
+ BaseView* parent_view_;
+
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewMac);
};
diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
index bfe0bfc..9e6b88f 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
@@ -14,6 +14,7 @@
#include "skia/ext/platform_canvas.h"
#include "third_party/WebKit/WebKit/chromium/public/mac/WebInputEventFactory.h"
#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
+#include "webkit/glue/webmenurunner_mac.h"
using WebKit::WebInputEventFactory;
using WebKit::WebMouseEvent;
@@ -46,7 +47,8 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget)
about_to_validate_and_paint_(false),
is_loading_(false),
is_hidden_(false),
- shutdown_factory_(this) {
+ shutdown_factory_(this),
+ parent_view_(NULL) {
cocoa_view_ = [[[RenderWidgetHostViewCocoa alloc]
initWithRenderWidgetHostViewMac:this] autorelease];
render_widget_host_->set_view(this);
@@ -267,6 +269,42 @@ BackingStore* RenderWidgetHostViewMac::AllocBackingStore(
return new BackingStore(size);
}
+// Display a popup menu for WebKit using Cocoa widgets.
+void RenderWidgetHostViewMac::ShowPopupWithItems(
+ gfx::Rect bounds,
+ int item_height,
+ int selected_item,
+ const std::vector<WebMenuItem>& items) {
+ NSRect view_rect = [cocoa_view_ bounds];
+ NSRect position = NSMakeRect(bounds.x(), bounds.y() - bounds.height(),
+ bounds.width(), bounds.height());
+
+ // Display the menu.
+ WebMenuRunner* menu_runner =
+ [[[WebMenuRunner alloc] initWithItems:items] autorelease];
+
+ [menu_runner runMenuInView:parent_view_
+ withBounds:position
+ initialIndex:selected_item];
+
+ int window_num = [[parent_view_ window] windowNumber];
+ NSEvent* event = CreateEventForMenuAction([menu_runner menuItemWasChosen],
+ window_num, item_height,
+ [menu_runner indexOfSelectedItem],
+ position, view_rect);
+
+ if ([menu_runner menuItemWasChosen]) {
+ // Simulate a menu selection event.
+ const WebMouseEvent& mouse_event =
+ WebInputEventFactory::mouseEvent(event, cocoa_view_);
+ render_widget_host_->ForwardMouseEvent(mouse_event);
+ } else {
+ // Simulate a menu dismiss event.
+ NativeWebKeyboardEvent keyboard_event(event);
+ render_widget_host_->ForwardKeyboardEvent(keyboard_event);
+ }
+}
+
void RenderWidgetHostViewMac::KillSelf() {
if (shutdown_factory_.empty()) {
[cocoa_view_ setHidden:YES];
diff --git a/chrome/browser/renderer_host/test_render_view_host.h b/chrome/browser/renderer_host/test_render_view_host.h
index 5f67ec1..0e93526 100644
--- a/chrome/browser/renderer_host/test_render_view_host.h
+++ b/chrome/browser/renderer_host/test_render_view_host.h
@@ -72,6 +72,12 @@ class TestRenderWidgetHostView : public RenderWidgetHostView {
virtual void PrepareToDestroy() {}
virtual void SetTooltipText(const std::wstring& tooltip_text) {}
virtual BackingStore* AllocBackingStore(const gfx::Size& size);
+#if defined(OS_MACOSX)
+ virtual void ShowPopupWithItems(gfx::Rect bounds,
+ int item_height,
+ int selected_item,
+ const std::vector<WebMenuItem>& items) {}
+#endif
bool is_showing() const { return is_showing_; }
diff --git a/chrome/browser/tab_contents/tab_contents_view_mac.mm b/chrome/browser/tab_contents/tab_contents_view_mac.mm
index 2f08d70..3d894c8 100644
--- a/chrome/browser/tab_contents/tab_contents_view_mac.mm
+++ b/chrome/browser/tab_contents/tab_contents_view_mac.mm
@@ -148,6 +148,9 @@ RenderWidgetHostView* TabContentsViewMac::CreateNewWidgetInternal(
static_cast<RenderWidgetHostViewMac*>(widget_view);
[widget_view_mac->native_view() retain];
+ // |widget_view_mac| needs to know how to position itself in our view.
+ widget_view_mac->set_parent_view(cocoa_view_);
+
return widget_view;
}
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index f711cf6..e0c6004 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -374,6 +374,23 @@ struct ViewHostMsg_Audio_CreateStream {
size_t packet_size;
};
+// This message is used for supporting popup menus on Mac OS X using native
+// Cocoa controls. The renderer sends us this message which we use to populate
+// the popup menu.
+struct ViewHostMsg_ShowPopup_Params {
+ // Position on the screen.
+ gfx::Rect bounds;
+
+ // The height of each item in the menu.
+ int item_height;
+
+ // The currently selected (displayed) item in the menu.
+ int selected_item;
+
+ // The entire list of items in the popup menu.
+ std::vector<WebMenuItem> popup_items;
+};
+
namespace IPC {
template <>
@@ -1832,6 +1849,94 @@ struct ParamTraits<WebAppCacheContext::ContextType> {
}
};
+template<>
+struct ParamTraits<WebMenuItem::Type> {
+ typedef WebMenuItem::Type param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteInt(p);
+ }
+ static bool Read(const Message* m, void** iter, param_type* p) {
+ int type;
+ if (!m->ReadInt(iter, &type))
+ return false;
+ *p = static_cast<WebMenuItem::Type>(type);
+ return true;
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ std::wstring type;
+ switch (p) {
+ case WebMenuItem::OPTION:
+ type = L"OPTION";
+ break;
+ case WebMenuItem::GROUP:
+ type = L"GROUP";
+ break;
+ case WebMenuItem::SEPARATOR:
+ type = L"SEPARATOR";
+ break;
+ default:
+ type = L"UNKNOWN";
+ break;
+ }
+ LogParam(type, l);
+ }
+};
+
+template<>
+struct ParamTraits<WebMenuItem> {
+ typedef WebMenuItem param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, p.label);
+ WriteParam(m, p.type);
+ WriteParam(m, p.enabled);
+ }
+ static bool Read(const Message* m, void** iter, param_type* p) {
+ return
+ ReadParam(m, iter, &p->label) &&
+ ReadParam(m, iter, &p->type) &&
+ ReadParam(m, iter, &p->enabled);
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(L"(");
+ LogParam(p.label, l);
+ l->append(L", ");
+ LogParam(p.type, l);
+ l->append(L", ");
+ LogParam(p.enabled, l);
+ l->append(L")");
+ }
+};
+
+// Traits for ViewHostMsg_ShowPopup_Params.
+template <>
+struct ParamTraits<ViewHostMsg_ShowPopup_Params> {
+ typedef ViewHostMsg_ShowPopup_Params param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, p.bounds);
+ WriteParam(m, p.item_height);
+ WriteParam(m, p.selected_item);
+ WriteParam(m, p.popup_items);
+ }
+ static bool Read(const Message* m, void** iter, param_type* p) {
+ return
+ ReadParam(m, iter, &p->bounds) &&
+ ReadParam(m, iter, &p->item_height) &&
+ ReadParam(m, iter, &p->selected_item) &&
+ ReadParam(m, iter, &p->popup_items);
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(L"(");
+ LogParam(p.bounds, l);
+ l->append(L", ");
+ LogParam(p.item_height, l);
+ l->append(L", ");
+ LogParam(p.selected_item, l);
+ l->append(L", ");
+ LogParam(p.popup_items, l);
+ l->append(L")");
+ }
+};
+
} // namespace IPC
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index fe0161e..ae14335 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -1337,4 +1337,9 @@ IPC_BEGIN_MESSAGES(ViewHost)
IPC_MESSAGE_CONTROL2(ViewHostMsg_ExtensionPostMessage,
int /* port_id */,
std::string /* message */)
+
+ // Message to show a popup menu using native cocoa controls (Mac only).
+ IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowPopup,
+ ViewHostMsg_ShowPopup_Params)
+
IPC_END_MESSAGES(ViewHost)
diff --git a/chrome/renderer/render_widget.cc b/chrome/renderer/render_widget.cc
index 23f27da..105ce11 100644
--- a/chrome/renderer/render_widget.cc
+++ b/chrome/renderer/render_widget.cc
@@ -313,7 +313,7 @@ void RenderWidget::PaintRect(const gfx::Rect& rect,
// If there is a custom background, tile it.
if (!background_.empty()) {
canvas->save();
-
+
SkIRect clipRect = { rect.x(), rect.y(), rect.right(), rect.bottom() };
canvas->setClipRegion(SkRegion(clipRect));
@@ -589,8 +589,13 @@ void RenderWidget::ShowAsPopupWithItems(WebWidget* webwidget,
int item_height,
int selected_index,
const std::vector<WebMenuItem>& items) {
- // TODO(paulg): Implement this for Mac HTML select menus in Chromium, bug
- // number: http://crbug.com/8389
+ ViewHostMsg_ShowPopup_Params params;
+ params.bounds = bounds;
+ params.item_height = item_height;
+ params.selected_item = selected_index;
+ params.popup_items = items;
+
+ Send(new ViewHostMsg_ShowPopup(routing_id_, params));
}
void RenderWidget::Focus(WebWidget* webwidget) {