2
* Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
7
* 1. Redistributions of source code must retain the above copyright
8
* notice, this list of conditions and the following disclaimer.
9
* 2. Redistributions in binary form must reproduce the above copyright
10
* notice, this list of conditions and the following disclaimer in the
11
* documentation and/or other materials provided with the distribution.
13
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23
* THE POSSIBILITY OF SUCH DAMAGE.
27
#import "WebPopupMenuProxyMac.h"
31
#import "NativeWebMouseEvent.h"
32
#import "PageClientImpl.h"
33
#import "PlatformPopupMenuData.h"
34
#import "StringUtilities.h"
36
#import "WebPopupItem.h"
37
#import <WebKitSystemInterface.h>
39
using namespace WebCore;
43
WebPopupMenuProxyMac::WebPopupMenuProxyMac(WKView *webView, WebPopupMenuProxy::Client* client)
44
: WebPopupMenuProxy(client)
49
WebPopupMenuProxyMac::~WebPopupMenuProxyMac()
52
[m_popup.get() setControlView:nil];
55
void WebPopupMenuProxyMac::populate(const Vector<WebPopupItem>& items, NSFont *font, TextDirection menuTextDirection)
58
[m_popup.get() removeAllItems];
60
m_popup.adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]);
61
[m_popup.get() setUsesItemFromMenu:NO];
62
[m_popup.get() setAutoenablesItems:NO];
65
int size = items.size();
67
for (int i = 0; i < size; i++) {
68
if (items[i].m_type == WebPopupItem::Separator)
69
[[m_popup.get() menu] addItem:[NSMenuItem separatorItem]];
71
[m_popup.get() addItemWithTitle:@""];
72
NSMenuItem *menuItem = [m_popup.get() lastItem];
74
RetainPtr<NSMutableParagraphStyle> paragraphStyle(AdoptNS, [[NSParagraphStyle defaultParagraphStyle] mutableCopy]);
75
NSWritingDirection writingDirection = items[i].m_textDirection == LTR ? NSWritingDirectionLeftToRight : NSWritingDirectionRightToLeft;
76
[paragraphStyle.get() setBaseWritingDirection:writingDirection];
77
[paragraphStyle.get() setAlignment:menuTextDirection == LTR ? NSLeftTextAlignment : NSRightTextAlignment];
78
RetainPtr<NSMutableDictionary> attributes(AdoptNS, [[NSMutableDictionary alloc] initWithObjectsAndKeys:
79
paragraphStyle.get(), NSParagraphStyleAttributeName,
80
font, NSFontAttributeName,
82
if (items[i].m_hasTextDirectionOverride) {
83
RetainPtr<NSNumber> writingDirectionValue(AdoptNS, [[NSNumber alloc] initWithInteger:writingDirection + NSTextWritingDirectionOverride]);
84
RetainPtr<NSArray> writingDirectionArray(AdoptNS, [[NSArray alloc] initWithObjects:writingDirectionValue.get(), nil]);
85
[attributes.get() setObject:writingDirectionArray.get() forKey:NSWritingDirectionAttributeName];
87
RetainPtr<NSAttributedString> string(AdoptNS, [[NSAttributedString alloc] initWithString:nsStringFromWebCoreString(items[i].m_text) attributes:attributes.get()]);
89
[menuItem setAttributedTitle:string.get()];
90
// We set the title as well as the attributed title here. The attributed title will be displayed in the menu,
91
// but typeahead will use the non-attributed string that doesn't contain any leading or trailing whitespace.
92
[menuItem setTitle:[[string.get() string] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
93
[menuItem setEnabled:items[i].m_isEnabled];
94
[menuItem setToolTip:nsStringFromWebCoreString(items[i].m_toolTip)];
99
void WebPopupMenuProxyMac::showPopupMenu(const IntRect& rect, TextDirection textDirection, double pageScaleFactor, const Vector<WebPopupItem>& items, const PlatformPopupMenuData& data, int32_t selectedIndex)
102
if (data.fontInfo.fontAttributeDictionary) {
103
NSFontDescriptor *fontDescriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:(NSDictionary *)data.fontInfo.fontAttributeDictionary.get()];
104
font = [NSFont fontWithDescriptor:fontDescriptor size:((pageScaleFactor != 1) ? [fontDescriptor pointSize] * pageScaleFactor : 0)];
106
font = [NSFont menuFontOfSize:0];
108
populate(items, font, textDirection);
110
[m_popup.get() attachPopUpWithFrame:rect inView:m_webView];
111
[m_popup.get() selectItemAtIndex:selectedIndex];
112
[m_popup.get() setUserInterfaceLayoutDirection:textDirection == LTR ? NSUserInterfaceLayoutDirectionLeftToRight : NSUserInterfaceLayoutDirectionRightToLeft];
114
NSMenu *menu = [m_popup.get() menu];
116
// These values were borrowed from AppKit to match their placement of the menu.
117
const int popOverHorizontalAdjust = -10;
118
const int popUnderHorizontalAdjust = 6;
119
const int popUnderVerticalAdjust = 6;
121
// Menus that pop-over directly obscure the node that generated the popup menu.
122
// Menus that pop-under are offset underneath it.
124
if (data.shouldPopOver) {
125
NSRect titleFrame = [m_popup.get() titleRectForBounds:rect];
126
if (titleFrame.size.width <= 0 || titleFrame.size.height <= 0)
128
float vertOffset = roundf((NSMaxY(rect) - NSMaxY(titleFrame)) + NSHeight(titleFrame));
129
location = NSMakePoint(NSMinX(rect) + popOverHorizontalAdjust, NSMaxY(rect) - vertOffset);
131
location = NSMakePoint(NSMinX(rect) + popUnderHorizontalAdjust, NSMaxY(rect) + popUnderVerticalAdjust);
133
RetainPtr<NSView> dummyView(AdoptNS, [[NSView alloc] initWithFrame:rect]);
134
[m_webView addSubview:dummyView.get()];
135
location = [dummyView.get() convertPoint:location fromView:m_webView];
137
WKPopupMenu(menu, location, roundf(NSWidth(rect)), dummyView.get(), selectedIndex, font);
139
[m_popup.get() dismissPopUp];
140
[dummyView.get() removeFromSuperview];
145
m_client->valueChangedForPopupMenu(this, [m_popup.get() indexOfSelectedItem]);
147
// <https://bugs.webkit.org/show_bug.cgi?id=57904> This code is adopted from EventHandler::sendFakeEventsAfterWidgetTracking().
148
if (!m_client->currentlyProcessedMouseDownEvent())
151
NSEvent* initiatingNSEvent = m_client->currentlyProcessedMouseDownEvent()->nativeEvent();
152
if ([initiatingNSEvent type] != NSLeftMouseDown)
155
NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
156
location:[initiatingNSEvent locationInWindow]
157
modifierFlags:[initiatingNSEvent modifierFlags]
158
timestamp:[initiatingNSEvent timestamp]
159
windowNumber:[initiatingNSEvent windowNumber]
160
context:[initiatingNSEvent context]
161
eventNumber:[initiatingNSEvent eventNumber]
162
clickCount:[initiatingNSEvent clickCount]
163
pressure:[initiatingNSEvent pressure]];
165
[NSApp postEvent:fakeEvent atStart:YES];
166
fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
167
location:[[m_webView window] convertScreenToBase:[NSEvent mouseLocation]]
168
modifierFlags:[initiatingNSEvent modifierFlags]
169
timestamp:[initiatingNSEvent timestamp]
170
windowNumber:[initiatingNSEvent windowNumber]
171
context:[initiatingNSEvent context]
175
[NSApp postEvent:fakeEvent atStart:YES];
178
void WebPopupMenuProxyMac::hidePopupMenu()
180
[m_popup.get() dismissPopUp];
183
} // namespace WebKit
185
#endif // USE(APPKIT)