| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "webkit/tools/test_shell/test_webview_delegate.h" |
| |
| #import <Cocoa/Cocoa.h> |
| #include "base/sys_string_conversions.h" |
| #include "base/utf_string_conversions.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenu.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" |
| #include "webkit/glue/webcursor.h" |
| #include "webkit/glue/webmenurunner_mac.h" |
| #include "webkit/plugins/npapi/plugin_list.h" |
| #include "webkit/plugins/npapi/webplugin_delegate_impl.h" |
| #include "webkit/tools/test_shell/test_shell.h" |
| |
| using webkit::npapi::WebPluginDelegateImpl; |
| using WebKit::WebCursorInfo; |
| using WebKit::WebNavigationPolicy; |
| using WebKit::WebPopupMenu; |
| using WebKit::WebPopupMenuInfo; |
| using WebKit::WebRect; |
| using WebKit::WebWidget; |
| |
| namespace { |
| |
| // Helper function for manufacturing input events to send to WebKit. |
| NSEvent* EventWithMenuAction(BOOL item_chosen, int window_num, |
| int item_height, int selected_index, |
| NSRect menu_bounds, NSRect view_bounds) { |
| NSEvent* event = nil; |
| double event_time = (double)(AbsoluteToDuration(UpTime())) / 1000.0; |
| |
| if (item_chosen) { |
| // Construct a mouse up event to simulate the selection of an appropriate |
| // menu item. |
| NSPoint click_pos; |
| click_pos.x = menu_bounds.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 = selected_index * item_height + item_height / 2; |
| click_pos.y = view_bounds.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]; |
| } 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; |
| NSString* escape_str = [NSString stringWithFormat:@"%c", 0x1B]; |
| event = [NSEvent keyEventWithType:NSKeyDown |
| location:key_pos |
| modifierFlags:0 |
| timestamp:event_time |
| windowNumber:window_num |
| context:nil |
| characters:@"" |
| charactersIgnoringModifiers:escape_str |
| isARepeat:NO |
| keyCode:0x1B]; |
| } |
| |
| return event; |
| } |
| |
| } // namespace |
| |
| // WebViewClient -------------------------------------------------------------- |
| |
| WebWidget* TestWebViewDelegate::createPopupMenu( |
| const WebPopupMenuInfo& info) { |
| WebWidget* webwidget = shell_->CreatePopupWidget(); |
| popup_menu_info_.reset(new WebPopupMenuInfo(info)); |
| return webwidget; |
| } |
| |
| // WebWidgetClient ------------------------------------------------------------ |
| |
| void TestWebViewDelegate::show(WebNavigationPolicy policy) { |
| if (!popup_menu_info_.get()) |
| return; |
| if (this != shell_->popup_delegate()) |
| return; |
| // Display a HTML select menu. |
| |
| std::vector<WebMenuItem> items; |
| for (size_t i = 0; i < popup_menu_info_->items.size(); ++i) |
| items.push_back(popup_menu_info_->items[i]); |
| |
| int item_height = popup_menu_info_->itemHeight; |
| double font_size = popup_menu_info_->itemFontSize; |
| int selected_index = popup_menu_info_->selectedIndex; |
| bool right_aligned = popup_menu_info_->rightAligned; |
| popup_menu_info_.reset(); // No longer needed. |
| |
| const WebRect& bounds = popup_bounds_; |
| |
| // Set up the menu position. |
| 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. |
| scoped_nsobject<WebMenuRunner> menu_runner; |
| menu_runner.reset([[WebMenuRunner alloc] initWithItems:items |
| fontSize:font_size |
| rightAligned:right_aligned]); |
| |
| [menu_runner runMenuInView:shell_->webViewWnd() |
| withBounds:position |
| initialIndex:selected_index]; |
| |
| // 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(); |
| int window_num = [shell_->mainWnd() windowNumber]; |
| NSEvent* event = EventWithMenuAction([menu_runner menuItemWasChosen], |
| window_num, item_height, |
| [menu_runner indexOfSelectedItem], |
| position, view_rect); |
| |
| if ([menu_runner menuItemWasChosen]) { |
| // Construct a mouse up event to simulate the selection of an appropriate |
| // menu item. |
| popup->MouseEvent(event); |
| } else { |
| // Fake an ESC key event (keyCode = 0x1B, from webinputevent_mac.mm) and |
| // forward that to WebKit. |
| popup->KeyEvent(event); |
| } |
| } |
| |
| void TestWebViewDelegate::closeWidgetSoon() { |
| if (this == shell_->delegate()) { |
| NSWindow *win = shell_->mainWnd(); |
| [win performSelector:@selector(performClose:) withObject:nil afterDelay:0]; |
| } else if (this == shell_->popup_delegate()) { |
| shell_->ClosePopup(); |
| } |
| } |
| |
| void TestWebViewDelegate::didChangeCursor(const WebCursorInfo& cursor_info) { |
| NSCursor* ns_cursor = WebCursor(cursor_info).GetNativeCursor(); |
| [ns_cursor set]; |
| } |
| |
| WebRect TestWebViewDelegate::windowRect() { |
| if (WebWidgetHost* host = GetWidgetHost()) { |
| NSView *view = host->view_handle(); |
| NSRect rect = [view frame]; |
| return gfx::Rect(NSRectToCGRect(rect)); |
| } |
| return WebRect(); |
| } |
| |
| void TestWebViewDelegate::setWindowRect(const WebRect& rect) { |
| if (this == shell_->delegate()) { |
| set_fake_window_rect(rect); |
| } else if (this == shell_->popup_delegate()) { |
| popup_bounds_ = rect; // The initial position of the popup. |
| } |
| } |
| |
| WebRect TestWebViewDelegate::rootWindowRect() { |
| if (using_fake_rect_) { |
| return fake_window_rect(); |
| } |
| if (WebWidgetHost* host = GetWidgetHost()) { |
| NSView *view = host->view_handle(); |
| NSRect rect = [[[view window] contentView] frame]; |
| return gfx::Rect(NSRectToCGRect(rect)); |
| } |
| return WebRect(); |
| } |
| |
| @interface NSWindow(OSInternals) |
| - (NSRect)_growBoxRect; |
| @end |
| |
| WebRect TestWebViewDelegate::windowResizerRect() { |
| NSRect resize_rect = NSMakeRect(0, 0, 0, 0); |
| WebWidgetHost* host = GetWidgetHost(); |
| // To match the WebKit screen shots, we need the resize area to overlap |
| // the scroll arrows, so in layout test mode, we don't return a real rect. |
| if (!(shell_->layout_test_mode()) && host) { |
| NSView *view = host->view_handle(); |
| NSWindow* window = [view window]; |
| resize_rect = [window _growBoxRect]; |
| // The scrollbar assumes that the resizer goes all the way down to the |
| // bottom corner, so we ignore any y offset to the rect itself and use the |
| // entire bottom corner. |
| resize_rect.origin.y = 0; |
| // Convert to view coordinates from window coordinates. |
| resize_rect = [view convertRect:resize_rect fromView:nil]; |
| // Flip the rect in view coordinates |
| resize_rect.origin.y = |
| [view frame].size.height - resize_rect.origin.y - |
| resize_rect.size.height; |
| } |
| return gfx::Rect(NSRectToCGRect(resize_rect)); |
| } |
| |
| void TestWebViewDelegate::runModal() { |
| NOTIMPLEMENTED(); |
| } |
| |
| // WebPluginPageDelegate ------------------------------------------------------ |
| |
| webkit::npapi::WebPluginDelegate* TestWebViewDelegate::CreatePluginDelegate( |
| const FilePath& path, |
| const std::string& mime_type) { |
| WebWidgetHost *host = GetWidgetHost(); |
| if (!host) |
| return NULL; |
| |
| gfx::PluginWindowHandle containing_view = gfx::kNullPluginWindow; |
| WebPluginDelegateImpl* delegate = |
| WebPluginDelegateImpl::Create(path, mime_type, containing_view); |
| if (delegate) |
| delegate->SetNoBufferContext(); |
| return delegate; |
| } |
| |
| void TestWebViewDelegate::CreatedPluginWindow( |
| gfx::PluginWindowHandle handle) { |
| } |
| |
| void TestWebViewDelegate::WillDestroyPluginWindow( |
| gfx::PluginWindowHandle handle) { |
| } |
| |
| void TestWebViewDelegate::DidMovePlugin( |
| const webkit::npapi::WebPluginGeometry& move) { |
| // TODO(port): add me once plugins work. |
| } |
| |
| // Public methods ------------------------------------------------------------- |
| |
| void TestWebViewDelegate::UpdateSelectionClipboard(bool is_empty_selection) { |
| // No selection clipboard on mac, do nothing. |
| } |
| |
| // Private methods ------------------------------------------------------------ |
| |
| void TestWebViewDelegate::ShowJavaScriptAlert(const string16& message) { |
| NSString *text = |
| [NSString stringWithUTF8String:UTF16ToUTF8(message).c_str()]; |
| NSAlert *alert = [NSAlert alertWithMessageText:@"JavaScript Alert" |
| defaultButton:@"OK" |
| alternateButton:nil |
| otherButton:nil |
| informativeTextWithFormat:@"%@", text]; |
| [alert runModal]; |
| } |
| |
| void TestWebViewDelegate::SetPageTitle(const string16& title) { |
| [[shell_->webViewHost()->view_handle() window] |
| setTitle:[NSString stringWithUTF8String:UTF16ToUTF8(title).c_str()]]; |
| } |
| |
| void TestWebViewDelegate::SetAddressBarURL(const GURL& url) { |
| const char* frameURL = url.spec().c_str(); |
| NSString *address = [NSString stringWithUTF8String:frameURL]; |
| [shell_->editWnd() setStringValue:address]; |
| } |