blob: 4cc08578392084993dfa195f9a6208e0a9dd2774 [file] [log] [blame]
// 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];
}