From 65f03d4f644ce73618e5f4f50dd694b26f55ae12 Mon Sep 17 00:00:00 2001 From: Ben Murdoch Date: Fri, 13 May 2011 16:23:25 +0100 Subject: Merge WebKit at r75993: Initial merge by git. Change-Id: I602bbdc3974787a3b0450456a30a7868286921c3 --- .../UIProcess/mac/WebContextMenuProxyMac.mm | 232 +++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 Source/WebKit2/UIProcess/mac/WebContextMenuProxyMac.mm (limited to 'Source/WebKit2/UIProcess/mac/WebContextMenuProxyMac.mm') diff --git a/Source/WebKit2/UIProcess/mac/WebContextMenuProxyMac.mm b/Source/WebKit2/UIProcess/mac/WebContextMenuProxyMac.mm new file mode 100644 index 0000000..d76b997 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/WebContextMenuProxyMac.mm @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * 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 INC. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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. + */ + +#include "WebContextMenuProxyMac.h" + +#include "PageClientImpl.h" +#include "WebContextMenuItemData.h" +#include "WKView.h" + +#include +#include + +using namespace WebCore; + +@interface WebUserDataWrapper : NSObject { + RefPtr _webUserData; +} +- (id)initWithUserData:(WebKit::APIObject*)userData; +- (WebKit::APIObject*)userData; +@end + +@implementation WebUserDataWrapper + +- (id)initWithUserData:(WebKit::APIObject*)userData +{ + self = [super init]; + if (!self) + return nil; + + _webUserData = userData; + return self; +} + +- (WebKit::APIObject*)userData +{ + return _webUserData.get(); +} + +@end + +@interface WKMenuTarget : NSObject { + WebKit::WebContextMenuProxyMac* _menuProxy; +} ++ (WKMenuTarget*)sharedMenuTarget; +- (WebKit::WebContextMenuProxyMac*)menuProxy; +- (void)setMenuProxy:(WebKit::WebContextMenuProxyMac*)menuProxy; +- (void)forwardContextMenuAction:(id)sender; +@end + +@implementation WKMenuTarget + ++ (WKMenuTarget*)sharedMenuTarget +{ + static WKMenuTarget* target = [[WKMenuTarget alloc] init]; + return target; +} + +- (WebKit::WebContextMenuProxyMac*)menuProxy +{ + return _menuProxy; +} + +- (void)setMenuProxy:(WebKit::WebContextMenuProxyMac*)menuProxy +{ + _menuProxy = menuProxy; +} + +- (void)forwardContextMenuAction:(id)sender +{ + WebKit::WebContextMenuItemData item(ActionType, static_cast([sender tag]), [sender title], [sender isEnabled], [sender state] == NSOnState); + + if (id representedObject = [sender representedObject]) { + ASSERT([representedObject isKindOfClass:[WebUserDataWrapper class]]); + item.setUserData([static_cast(representedObject) userData]); + } + + _menuProxy->contextMenuItemSelected(item); +} + +@end + +namespace WebKit { + +WebContextMenuProxyMac::WebContextMenuProxyMac(WKView* webView, WebPageProxy* page) + : m_webView(webView) + , m_page(page) +{ +} + +WebContextMenuProxyMac::~WebContextMenuProxyMac() +{ + if (m_popup) + [m_popup.get() setControlView:nil]; +} + +void WebContextMenuProxyMac::contextMenuItemSelected(const WebContextMenuItemData& item) +{ + m_page->contextMenuItemSelected(item); +} + +static void populateNSMenu(NSMenu* menu, const Vector >& menuItemVector) +{ + for (unsigned i = 0; i < menuItemVector.size(); ++i) { + NSInteger oldState = [menuItemVector[i].get() state]; + [menu addItem:menuItemVector[i].get()]; + [menuItemVector[i].get() setState:oldState]; + } +} + +static Vector > nsMenuItemVector(const Vector& items) +{ + Vector > result; + + unsigned size = items.size(); + result.reserveCapacity(size); + for (unsigned i = 0; i < size; i++) { + switch (items[i].type()) { + case ActionType: + case CheckableActionType: { + NSMenuItem* menuItem = [[NSMenuItem alloc] initWithTitle:nsStringFromWebCoreString(items[i].title()) action:@selector(forwardContextMenuAction:) keyEquivalent:@""]; + [menuItem setTag:items[i].action()]; + [menuItem setEnabled:items[i].enabled()]; + [menuItem setState:items[i].checked() ? NSOnState : NSOffState]; + + if (items[i].userData()) { + WebUserDataWrapper *wrapper = [[WebUserDataWrapper alloc] initWithUserData:items[i].userData()]; + [menuItem setRepresentedObject:wrapper]; + [wrapper release]; + } + + result.append(RetainPtr(AdoptNS, menuItem)); + break; + } + case SeparatorType: + result.append([NSMenuItem separatorItem]); + break; + case SubmenuType: { + NSMenu* menu = [[NSMenu alloc] initWithTitle:nsStringFromWebCoreString(items[i].title())]; + [menu setAutoenablesItems:NO]; + populateNSMenu(menu, nsMenuItemVector(items[i].submenu())); + + NSMenuItem* menuItem = [[NSMenuItem alloc] initWithTitle:nsStringFromWebCoreString(items[i].title()) action:@selector(forwardContextMenuAction:) keyEquivalent:@""]; + [menuItem setEnabled:items[i].enabled()]; + [menuItem setSubmenu:menu]; + [menu release]; + + result.append(RetainPtr(AdoptNS, menuItem)); + + break; + } + default: + ASSERT_NOT_REACHED(); + } + } + + WKMenuTarget* target = [WKMenuTarget sharedMenuTarget]; + for (unsigned i = 0; i < size; ++i) + [result[i].get() setTarget:target]; + + return result; +} + +void WebContextMenuProxyMac::populate(const Vector& items) +{ + if (m_popup) + [m_popup.get() removeAllItems]; + else { + m_popup.adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]); + [m_popup.get() setUsesItemFromMenu:NO]; + [m_popup.get() setAutoenablesItems:NO]; + } + + NSMenu* menu = [m_popup.get() menu]; + populateNSMenu(menu, nsMenuItemVector(items)); +} + +void WebContextMenuProxyMac::showContextMenu(const IntPoint& menuLocation, const Vector& items) +{ + populate(items); + [[WKMenuTarget sharedMenuTarget] setMenuProxy:this]; + + NSRect menuRect = NSMakeRect(menuLocation.x(), menuLocation.y(), 0, 0); + + [m_popup.get() attachPopUpWithFrame:menuRect inView:m_webView]; + + NSMenu* menu = [m_popup.get() menu]; + + // These values were borrowed from AppKit to match their placement of the menu. + NSRect titleFrame = [m_popup.get() titleRectForBounds:menuRect]; + if (titleFrame.size.width <= 0 || titleFrame.size.height <= 0) + titleFrame = menuRect; + float vertOffset = roundf((NSMaxY(menuRect) - NSMaxY(titleFrame)) + NSHeight(titleFrame)); + NSPoint location = NSMakePoint(NSMinX(menuRect), NSMaxY(menuRect) - vertOffset); + + RetainPtr dummyView(AdoptNS, [[NSView alloc] initWithFrame:menuRect]); + [m_webView addSubview:dummyView.get()]; + location = [dummyView.get() convertPoint:location fromView:m_webView]; + + WKPopupMenu(menu, location, roundf(NSWidth(menuRect)), dummyView.get(), -1, nil); + + [m_popup.get() dismissPopUp]; + [dummyView.get() removeFromSuperview]; +} + +void WebContextMenuProxyMac::hideContextMenu() +{ + [m_popup.get() dismissPopUp]; +} + +} // namespace WebKit -- cgit v1.1