diff --git a/cef.gyp b/cef.gyp index 00b5695a4..91ce3254f 100644 --- a/cef.gyp +++ b/cef.gyp @@ -388,7 +388,6 @@ 'libcef/browser_file_writer.h', 'libcef/browser_impl.cc', 'libcef/browser_impl.h', - 'libcef/browser_impl_win.cc', 'libcef/browser_navigation_controller.cc', 'libcef/browser_navigation_controller.h', 'libcef/browser_request_context.cc', @@ -447,6 +446,7 @@ 'libcef/browser_drag_delegate.h', 'libcef/browser_drop_delegate.cc', 'libcef/browser_drop_delegate.h', + 'libcef/browser_impl_win.cc', 'libcef/browser_webkit_glue_win.cc', 'libcef/browser_webview_delegate_win.cc', 'libcef/printing/print_settings.cc', @@ -461,8 +461,11 @@ 'sources': [ 'include/cef_types_mac.h', 'include/cef_mac.h', + 'libcef/browser_impl_mac.mm', 'libcef/browser_webkit_glue_mac.mm', 'libcef/browser_webview_delegate_mac.mm', + 'libcef/browser_webview_mac.h', + 'libcef/browser_webview_mac.mm', 'libcef/webview_host_mac.mm', 'libcef/webwidget_host_mac.mm', ], @@ -471,6 +474,7 @@ 'sources': [ 'include/cef_types_linux.h', 'include/cef_linux.h', + 'libcef/browser_impl_gtk.cc', 'libcef/browser_webkit_glue_gtk.cc', 'libcef/browser_webview_delegate_gtk.cc', 'libcef/webview_host_gtk.cc', diff --git a/include/cef_types_linux.h b/include/cef_types_linux.h index 344e3c902..f256ab94c 100644 --- a/include/cef_types_linux.h +++ b/include/cef_types_linux.h @@ -38,6 +38,9 @@ extern "C" { #if defined(__linux__) #include "cef_string.h" +// Window handle. +#define cef_window_handle_t void* + // Class representing window information. typedef struct _cef_window_info_t { @@ -55,8 +58,6 @@ typedef struct _cef_print_info_t double m_Scale; } cef_print_info_t; -// Window handle. -#define cef_window_handle_t void* #endif // defined(__linux__) #ifdef __cplusplus diff --git a/include/cef_types_mac.h b/include/cef_types_mac.h index b3655ea7c..bae3209a4 100644 --- a/include/cef_types_mac.h +++ b/include/cef_types_mac.h @@ -38,6 +38,9 @@ extern "C" { #if defined(__APPLE__) #include "cef_string.h" +// Window handle. +#define cef_window_handle_t void* + // Class representing window information. typedef struct _cef_window_info_t { @@ -47,6 +50,12 @@ typedef struct _cef_window_info_t int m_y; int m_nWidth; int m_nHeight; + + // NSWindow pointer for the parent window. + cef_window_handle_t m_ParentWindow; + + // NSWindow pointer for the new browser window. + cef_window_handle_t m_Window; } cef_window_info_t; // Class representing print context information. @@ -55,8 +64,6 @@ typedef struct _cef_print_info_t double m_Scale; } cef_print_info_t; -// Window handle. -#define cef_window_handle_t void* #endif // defined(__APPLE__) #ifdef __cplusplus diff --git a/include/cef_types_win.h b/include/cef_types_win.h index e7d76cffa..2a050572f 100644 --- a/include/cef_types_win.h +++ b/include/cef_types_win.h @@ -39,6 +39,9 @@ extern "C" { #include #include "cef_string.h" +// Window handle. +#define cef_window_handle_t HWND + // Class representing window information. typedef struct _cef_window_info_t { @@ -50,11 +53,11 @@ typedef struct _cef_window_info_t int m_y; int m_nWidth; int m_nHeight; - HWND m_hWndParent; + cef_window_handle_t m_hWndParent; HMENU m_hMenu; // Handle for the new browser window. - HWND m_hWnd; + cef_window_handle_t m_hWnd; } cef_window_info_t; // Class representing print context information. @@ -65,8 +68,6 @@ typedef struct _cef_print_info_t double m_Scale; } cef_print_info_t; -// Window handle. -#define cef_window_handle_t HWND #endif // _WIN32 #ifdef __cplusplus diff --git a/libcef/browser_impl.h b/libcef/browser_impl.h index 7fc8ba41a..78b5b8005 100644 --- a/libcef/browser_impl.h +++ b/libcef/browser_impl.h @@ -112,7 +112,7 @@ public: BrowserWebViewDelegate* GetWebViewDelegate() const { return delegate_.get(); } - CefWindowHandle GetWebViewWndHandle() const { + gfx::NativeView GetWebViewWndHandle() const { return webviewhost_->view_handle(); } WebKit::WebWidget* GetPopup() const { @@ -124,17 +124,10 @@ public: BrowserWebViewDelegate* GetPopupDelegate() const { return popup_delegate_.get(); } - CefWindowHandle GetPopupWndHandle() const { + gfx::NativeView GetPopupWndHandle() const { return popuphost_->view_handle(); } - CefWindowHandle GetMainWndHandle() const { -#if defined(OS_WIN) - return window_info_.m_hWnd; -#else - return 0; -#endif - } - + gfx::NativeWindow GetMainWndHandle() const; //////////////////////////////////////////////////////////// // ALL UIT_* METHODS MUST ONLY BE CALLED ON THE UI THREAD // diff --git a/libcef/browser_impl_mac.mm b/libcef/browser_impl_mac.mm new file mode 100644 index 000000000..5bec43ac7 --- /dev/null +++ b/libcef/browser_impl_mac.mm @@ -0,0 +1,127 @@ +// Copyright (c) 2010 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 "cef_context.h" +#include "browser_impl.h" + +#import + +#include "base/utf_string_conversions.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebRect.h" +#include "third_party/WebKit/WebKit/chromium/public/WebSize.h" +#include "third_party/WebKit/WebKit/chromium/public/WebView.h" + +using WebKit::WebRect; +using WebKit::WebSize; + +CefWindowHandle CefBrowserImpl::GetWindowHandle() +{ + Lock(); + CefWindowHandle handle = window_info_.m_Window; + Unlock(); + return handle; +} + +gfx::NativeWindow CefBrowserImpl::GetMainWndHandle() const { + return (NSWindow*)window_info_.m_Window; +} + +void CefBrowserImpl::UIT_CreateBrowser(const std::wstring& url) +{ + REQUIRE_UIT(); + + // Create the new browser window + // TODO(port): Add implementation. + + // Add a reference that will be released on WM_DESTROY. + AddRef(); + + // Add the new browser to the list maintained by the context + _Context->AddBrowser(this); + + // Create the webview host object + webviewhost_.reset( + WebViewHost::Create([GetMainWndHandle() contentView], delegate_.get(), + NULL, *_Context->web_preferences())); + delegate_->RegisterDragDrop(); + + // Size the web view window to the browser window + // TODO(port): Add implementation. + + if(handler_.get()) { + // Notify the handler that we're done creating the new window + handler_->HandleAfterCreated(this); + } + + if(url.size() > 0) { + CefRefPtr frame = GetMainFrame(); + frame->AddRef(); + UIT_LoadURL(frame, url.c_str()); + } +} + +void CefBrowserImpl::UIT_SetFocus(WebWidgetHost* host, bool enable) +{ + REQUIRE_UIT(); + if (!host) + return; + + // TODO(port): Add implementation. +} + +WebKit::WebWidget* CefBrowserImpl::UIT_CreatePopupWidget() +{ + REQUIRE_UIT(); + + DCHECK(!popuphost_); + popuphost_ = WebWidgetHost::Create(NULL, popup_delegate_.get()); + + // TODO(port): Show window. + + return popuphost_->webwidget(); +} + +void CefBrowserImpl::UIT_ClosePopupWidget() +{ + REQUIRE_UIT(); + + // TODO(port): Close window. + popuphost_ = NULL; +} + +bool CefBrowserImpl::UIT_ViewDocumentString(WebKit::WebFrame *frame) +{ + REQUIRE_UIT(); + + // TODO(port): Add implementation. + NOTIMPLEMENTED(); + return false; +} + +void CefBrowserImpl::UIT_PrintPage(int page_number, int total_pages, + const gfx::Size& canvas_size, + WebKit::WebFrame* frame) { + REQUIRE_UIT(); + + // TODO(port): Add implementation. + NOTIMPLEMENTED(); +} + +void CefBrowserImpl::UIT_PrintPages(WebKit::WebFrame* frame) { + REQUIRE_UIT(); + + // TODO(port): Add implementation. + NOTIMPLEMENTED(); +} + +int CefBrowserImpl::UIT_GetPagesCount(WebKit::WebFrame* frame) +{ + REQUIRE_UIT(); + + // TODO(port): Add implementation. + NOTIMPLEMENTED(); + return 0; +} diff --git a/libcef/browser_impl_win.cc b/libcef/browser_impl_win.cc index 96141b026..fed4bfad6 100644 --- a/libcef/browser_impl_win.cc +++ b/libcef/browser_impl_win.cc @@ -104,6 +104,10 @@ CefWindowHandle CefBrowserImpl::GetWindowHandle() return handle; } +gfx::NativeWindow CefBrowserImpl::GetMainWndHandle() const { + return window_info_.m_hWnd; +} + void CefBrowserImpl::UIT_CreateBrowser(const std::wstring& url) { REQUIRE_UIT(); diff --git a/libcef/browser_webkit_glue.cc b/libcef/browser_webkit_glue.cc index e302a6901..8fa78cf8e 100644 --- a/libcef/browser_webkit_glue.cc +++ b/libcef/browser_webkit_glue.cc @@ -43,10 +43,6 @@ void AppendToLog(const char* file, int line, const char* msg) { logging::LogMessage(file, line).stream() << msg; } -base::StringPiece GetDataResource(int resource_id) { - return NetResourceProvider(resource_id); -} - bool GetApplicationDirectory(FilePath* path) { return PathService::Get(base::DIR_EXE, path); } @@ -154,8 +150,8 @@ bool IsContentDispositionAttachment(const std::string& cd_header, WTF::String name_str = WebCore::filenameFromHTTPContentDisposition(cd_str); if (!name_str.isEmpty()) { - file_name = WideToUTF8( - std::wstring(name_str.characters(), name_str.length())); + WTF::CString cstr(name_str.utf8()); + file_name = std::string(cstr.data(), cstr.length()); } return true; } diff --git a/libcef/browser_webkit_glue_mac.mm b/libcef/browser_webkit_glue_mac.mm new file mode 100644 index 000000000..a480a19e0 --- /dev/null +++ b/libcef/browser_webkit_glue_mac.mm @@ -0,0 +1,126 @@ +// Copyright (c) 2010 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 "base/compiler_specific.h" + +#include "third_party/webkit/webcore/config.h" + +#include "browser_webkit_glue.h" + +#undef LOG +#include "base/data_pack.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/mac_util.h" +#include "base/path_service.h" +#include "grit/webkit_resources.h" +#include "webkit/glue/webkit_glue.h" +#include "webkit/glue/plugins/plugin_list.h" + +namespace webkit_glue { + +// Data pack resource. This is a pointer to the mmapped resources file. +static base::DataPack* g_resource_data_pack = NULL; + +// Helper method for getting the path to the CEF resources directory. +FilePath GetResourcesFilePath() { + FilePath path; + // We need to know if we're bundled or not to know which path to use. + if (mac_util::AmIBundled()) { + PathService::Get(base::DIR_EXE, &path); + path = path.Append(FilePath::kParentDirectory); + return path.AppendASCII("Resources"); + } else { + PathService::Get(base::DIR_SOURCE_ROOT, &path); + path = path.AppendASCII("src"); + path = path.AppendASCII("cef"); + return path.AppendASCII("resources"); + } +} + +string16 GetLocalizedString(int message_id) { + base::StringPiece res; + if (!g_resource_data_pack->GetStringPiece(message_id, &res)) { + LOG(FATAL) << "failed to load webkit string with id " << message_id; + } + + return string16(reinterpret_cast(res.data()), + res.length() / 2); +} + + +base::StringPiece NetResourceProvider(int key) { + base::StringPiece res; + g_resource_data_pack->GetStringPiece(key, &res); + return res; +} + +base::StringPiece GetDataResource(int resource_id) { + switch (resource_id) { + case IDR_BROKENIMAGE: { + // Use webkit's broken image icon (16x16) + static std::string broken_image_data; + if (broken_image_data.empty()) { + FilePath path = GetResourcesFilePath(); + // In order to match WebKit's colors for the missing image, we have to + // use a PNG. The GIF doesn't have the color range needed to correctly + // match the TIFF they use in Safari. + path = path.AppendASCII("missingImage.png"); + bool success = file_util::ReadFileToString(path, &broken_image_data); + if (!success) { + LOG(FATAL) << "Failed reading: " << path.value(); + } + } + return broken_image_data; + } + case IDR_TEXTAREA_RESIZER: { + // Use webkit's text area resizer image. + static std::string resize_corner_data; + if (resize_corner_data.empty()) { + FilePath path = GetResourcesFilePath(); + path = path.AppendASCII("textAreaResizeCorner.png"); + bool success = file_util::ReadFileToString(path, &resize_corner_data); + if (!success) { + LOG(FATAL) << "Failed reading: " << path.value(); + } + } + return resize_corner_data; + } + + case IDR_SEARCH_CANCEL: + case IDR_SEARCH_CANCEL_PRESSED: + case IDR_SEARCH_MAGNIFIER: + case IDR_SEARCH_MAGNIFIER_RESULTS: + case IDR_MEDIA_PAUSE_BUTTON: + case IDR_MEDIA_PLAY_BUTTON: + case IDR_MEDIA_PLAY_BUTTON_DISABLED: + case IDR_MEDIA_SOUND_FULL_BUTTON: + case IDR_MEDIA_SOUND_NONE_BUTTON: + case IDR_MEDIA_SOUND_DISABLED: + case IDR_MEDIA_SLIDER_THUMB: + case IDR_MEDIA_VOLUME_SLIDER_THUMB: + case IDR_INPUT_SPEECH: + case IDR_INPUT_SPEECH_RECORDING: + case IDR_INPUT_SPEECH_WAITING: + return NetResourceProvider(resource_id); + + default: + break; + } + + return base::StringPiece(); +} + +void GetPlugins(bool refresh, std::vector* plugins) { + NPAPI::PluginList::Singleton()->GetPlugins(refresh, plugins); +} + +void DidLoadPlugin(const std::string& filename) { +} + +void DidUnloadPlugin(const std::string& filename) { +} + +} // namespace webkit_glue diff --git a/libcef/browser_webkit_glue_win.cc b/libcef/browser_webkit_glue_win.cc index f51f07823..bcdeb9c6b 100644 --- a/libcef/browser_webkit_glue_win.cc +++ b/libcef/browser_webkit_glue_win.cc @@ -66,6 +66,10 @@ base::StringPiece NetResourceProvider(int key) { return GetRawDataResource(hModule, key); } +base::StringPiece GetDataResource(int resource_id) { + return NetResourceProvider(resource_id); +} + void GetPlugins(bool refresh, std::vector* plugins) { NPAPI::PluginList::Singleton()->GetPlugins(refresh, plugins); } @@ -303,4 +307,4 @@ BOOL SaveBitmapToFile(HBITMAP hBmp, HDC hDC, LPCTSTR file, LPBYTE lpBits) return ret; } -} // namespace webkit_glue +} // namespace webkit_glue \ No newline at end of file diff --git a/libcef/browser_webview_delegate.h b/libcef/browser_webview_delegate.h index ff1d6f41d..65ccd7005 100644 --- a/libcef/browser_webview_delegate.h +++ b/libcef/browser_webview_delegate.h @@ -26,6 +26,9 @@ #include "third_party/WebKit/WebKit/chromium/public/WebFileSystem.h" #include "third_party/WebKit/WebKit/chromium/public/WebFrameClient.h" #include "third_party/WebKit/WebKit/chromium/public/WebRect.h" +#if defined(OS_MACOSX) +#include "third_party/WebKit/WebKit/chromium/public/WebPopupMenuInfo.h" +#endif #include "third_party/WebKit/WebKit/chromium/public/WebViewClient.h" #include "webkit/glue/webcursor.h" #include "webkit/glue/plugins/webplugin_page_delegate.h" @@ -314,7 +317,12 @@ class BrowserWebViewDelegate : public WebKit::WebViewClient, // cursor. GdkCursorType cursor_type_; #endif - + +#if defined(OS_MACOSX) + scoped_ptr popup_menu_info_; + WebKit::WebRect popup_bounds_; +#endif + // true if we want to enable smart insert/delete. bool smart_insert_delete_enabled_; diff --git a/libcef/browser_webview_delegate_mac.mm b/libcef/browser_webview_delegate_mac.mm new file mode 100644 index 000000000..67dc5f40b --- /dev/null +++ b/libcef/browser_webview_delegate_mac.mm @@ -0,0 +1,244 @@ +// Copyright (c) 2008 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 "browser_webview_delegate.h" +#include "browser_impl.h" + +#import + +#include "base/sys_string_conversions.h" +#include "base/utf_string_conversions.h" +#include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h" +#include "third_party/WebKit/WebKit/chromium/public/WebPopupMenu.h" +#include "third_party/WebKit/WebKit/chromium/public/WebView.h" +#include "webkit/glue/webcursor.h" +#include "webkit/glue/plugins/plugin_list.h" +#include "webkit/glue/plugins/webplugin_delegate_impl.h" +#include "webkit/glue/webmenurunner_mac.h" + +using WebKit::WebCursorInfo; +using WebKit::WebNavigationPolicy; +using WebKit::WebPopupMenu; +using WebKit::WebPopupMenuInfo; +using WebKit::WebRect; +using WebKit::WebWidget; + +// WebViewClient -------------------------------------------------------------- + +WebWidget* BrowserWebViewDelegate::createPopupMenu( + const WebPopupMenuInfo& info) { + WebWidget* webwidget = browser_->UIT_CreatePopupWidget(); + popup_menu_info_.reset(new WebPopupMenuInfo(info)); + return webwidget; +} + +void BrowserWebViewDelegate::showContextMenu( + WebKit::WebFrame* frame, const WebKit::WebContextMenuData& data) { + NOTIMPLEMENTED(); +} + +// WebWidgetClient ------------------------------------------------------------ + +void BrowserWebViewDelegate::show(WebNavigationPolicy policy) { + if (!popup_menu_info_.get()) + return; + if (this != browser_->GetPopupDelegate()) + return; + // Display a HTML select menu. + + std::vector 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 = browser_->GetWebViewWndHandle(); + 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 menu_runner; + menu_runner.reset([[WebMenuRunner alloc] initWithItems:items + fontSize:font_size + rightAligned:right_aligned]); + + [menu_runner runMenuInView:browser_->GetWebViewWndHandle() + 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 = browser_->GetPopupHost(); + int window_num = [browser_->GetMainWndHandle() windowNumber]; + NSEvent* event = + webkit_glue::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 BrowserWebViewDelegate::closeWidgetSoon() { + if (this == browser_->GetWebViewDelegate()) { + NSWindow *win = browser_->GetMainWndHandle(); + [win performSelector:@selector(performClose:) withObject:nil afterDelay:0]; + } else if (this == browser_->GetPopupDelegate()) { + browser_->UIT_ClosePopupWidget(); + } +} + +void BrowserWebViewDelegate::didChangeCursor(const WebCursorInfo& cursor_info) { + NSCursor* ns_cursor = WebCursor(cursor_info).GetCursor(); + [ns_cursor set]; +} + +WebRect BrowserWebViewDelegate::windowRect() { + if (WebWidgetHost* host = GetWidgetHost()) { + NSView *view = host->view_handle(); + NSRect rect = [view frame]; + return gfx::Rect(NSRectToCGRect(rect)); + } + return WebRect(); +} + +void BrowserWebViewDelegate::setWindowRect(const WebRect& rect) { + if (this == browser_->GetWebViewDelegate()) { + // TODO(port): Set the window rectangle. + } else if (this == browser_->GetPopupDelegate()) { + popup_bounds_ = rect; // The initial position of the popup. + } +} + +WebRect BrowserWebViewDelegate::rootWindowRect() { + 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 BrowserWebViewDelegate::windowResizerRect() { + NSRect resize_rect = NSMakeRect(0, 0, 0, 0); + WebWidgetHost* host = GetWidgetHost(); + if (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 BrowserWebViewDelegate::runModal() { + NOTIMPLEMENTED(); +} + +// WebPluginPageDelegate ------------------------------------------------------ + +webkit_glue::WebPluginDelegate* BrowserWebViewDelegate::CreatePluginDelegate( + const FilePath& path, + const std::string& mime_type) { + WebWidgetHost *host = GetWidgetHost(); + if (!host) + return NULL; + + gfx::PluginWindowHandle containing_view = NULL; + return WebPluginDelegateImpl::Create(path, mime_type, containing_view); +} + +void BrowserWebViewDelegate::CreatedPluginWindow( + gfx::PluginWindowHandle handle) { +} + +void BrowserWebViewDelegate::WillDestroyPluginWindow( + gfx::PluginWindowHandle handle) { +} + +void BrowserWebViewDelegate::DidMovePlugin( + const webkit_glue::WebPluginGeometry& move) { + // TODO(port): add me once plugins work. +} + +// Protected methods ---------------------------------------------------------- + +void BrowserWebViewDelegate::ShowJavaScriptAlert( + WebKit::WebFrame* webframe, const std::wstring& message) { + NSString *text = + [NSString stringWithUTF8String:WideToUTF8(message).c_str()]; + NSAlert *alert = [NSAlert alertWithMessageText:@"JavaScript Alert" + defaultButton:@"OK" + alternateButton:nil + otherButton:nil + informativeTextWithFormat:text]; + [alert runModal]; +} + +bool BrowserWebViewDelegate::ShowJavaScriptConfirm( + WebKit::WebFrame* webframe, const std::wstring& message) { + NOTIMPLEMENTED(); + return false; +} + +bool BrowserWebViewDelegate::ShowJavaScriptPrompt( + WebKit::WebFrame* webframe, const std::wstring& message, + const std::wstring& default_value, std::wstring* result) { + NOTIMPLEMENTED(); + return false; +} + +// Called to show the file chooser dialog. +bool BrowserWebViewDelegate::ShowFileChooser(std::vector& file_names, + const bool multi_select, + const WebKit::WebString& title, + const FilePath& default_file) { + NOTIMPLEMENTED(); + return false; +} + +// Private methods ------------------------------------------------------------ +/* +void BrowserWebViewDelegate::SetPageTitle(const std::wstring& title) { + [[browser_->GetWebViewHost()->view_handle() window] + setTitle:[NSString stringWithUTF8String:WideToUTF8(title).c_str()]]; +} + +void BrowserWebViewDelegate::SetAddressBarURL(const GURL& url) { + const char* frameURL = url.spec().c_str(); + NSString *address = [NSString stringWithUTF8String:frameURL]; + [browser_->GetEditWnd() setStringValue:address]; +} +*/ diff --git a/libcef/browser_webview_mac.h b/libcef/browser_webview_mac.h new file mode 100644 index 000000000..cfb9e0689 --- /dev/null +++ b/libcef/browser_webview_mac.h @@ -0,0 +1,45 @@ +// Copyright (c) 2008 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. + +#import + +class CefBrowserImpl; + +// A view to wrap the WebCore view and help it live in a Cocoa world. The +// (rough) equivalent of Apple's WebView. + +@interface BrowserWebView : NSView { + @private + CefBrowserImpl *browser_; // weak + NSTrackingArea *trackingArea_; +} + +- (IBAction)goBack:(id)sender; +- (IBAction)goForward:(id)sender; +- (IBAction)reload:(id)sender; +- (IBAction)stopLoading:(id)sender; +- (IBAction)takeURLStringValueFrom:(NSTextField *)sender; + +- (void)mouseDown:(NSEvent *)theEvent; +- (void)rightMouseDown:(NSEvent *)theEvent; +- (void)otherMouseDown:(NSEvent *)theEvent; +- (void)mouseUp:(NSEvent *)theEvent; +- (void)rightMouseUp:(NSEvent *)theEvent; +- (void)otherMouseUp:(NSEvent *)theEvent; +- (void)mouseMoved:(NSEvent *)theEvent; +- (void)mouseDragged:(NSEvent *)theEvent; +- (void)scrollWheel:(NSEvent *)theEvent; +- (void)rightMouseDragged:(NSEvent *)theEvent; +- (void)otherMouseDragged:(NSEvent *)theEvent; +- (void)mouseEntered:(NSEvent *)theEvent; +- (void)mouseExited:(NSEvent *)theEvent; +- (void)keyDown:(NSEvent *)theEvent; +- (void)keyUp:(NSEvent *)theEvent; +- (BOOL)isOpaque; +- (void)setFrame:(NSRect)frameRect; +- (void)setIsActive:(BOOL)active; + +@property (nonatomic, assign) CefBrowserImpl *browser; + +@end diff --git a/libcef/browser_webview_mac.mm b/libcef/browser_webview_mac.mm new file mode 100644 index 000000000..d3393f2f9 --- /dev/null +++ b/libcef/browser_webview_mac.mm @@ -0,0 +1,212 @@ +// Copyright (c) 2008 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. + +#import "browser_webview_mac.h" + +#import + +#include "browser_impl.h" +#include "webwidget_host.h" + +#include "base/scoped_ptr.h" +#include "base/utf_string_conversions.h" +#include "gfx/rect.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebView.h" + +@implementation BrowserWebView + +@synthesize browser = browser_; + +- (id)initWithFrame:(NSRect)frame { + self = [super initWithFrame:frame]; + if (self) { + trackingArea_ = + [[NSTrackingArea alloc] initWithRect:frame + options:NSTrackingMouseMoved | + NSTrackingActiveInActiveApp | + NSTrackingInVisibleRect + owner:self + userInfo:nil]; + [self addTrackingArea:trackingArea_]; + } + return self; +} + +- (void) dealloc { + [self removeTrackingArea:trackingArea_]; + [trackingArea_ release]; + + [super dealloc]; +} + +- (void)drawRect:(NSRect)rect { + CGContextRef context = + reinterpret_cast([[NSGraphicsContext currentContext] + graphicsPort]); + + // start by filling the rect with magenta, so that we can see what's drawn + CGContextSetRGBFillColor (context, 1, 0, 1, 1); + CGContextFillRect(context, NSRectToCGRect(rect)); + + if (browser_ && browser_->GetWebView()) { + gfx::Rect client_rect(NSRectToCGRect(rect)); + // flip from cocoa coordinates + client_rect.set_y([self frame].size.height - + client_rect.height() - client_rect.y()); + + browser_->GetWebViewHost()->UpdatePaintRect(client_rect); + browser_->GetWebViewHost()->Paint(); + } +} + +- (IBAction)goBack:(id)sender { + if (browser_) + browser_->UIT_GoBackOrForward(-1); +} + +- (IBAction)goForward:(id)sender { + if (browser_) + browser_->UIT_GoBackOrForward(1); +} + +- (IBAction)reload:(id)sender { + if (browser_) + browser_->UIT_Reload(false); +} + +- (IBAction)stopLoading:(id)sender { + if (browser_ && browser_->GetWebView()) + browser_->GetWebView()->mainFrame()->stopLoading(); +} + +- (IBAction)takeURLStringValueFrom:(NSTextField *)sender { + NSString *url = [sender stringValue]; + + // if it doesn't already have a prefix, add http. If we can't parse it, + // just don't bother rather than making things worse. + NSURL* tempUrl = [NSURL URLWithString:url]; + if (tempUrl && ![tempUrl scheme]) + url = [@"http://" stringByAppendingString:url]; + browser_->LoadURL(browser_->GetMainFrame(), UTF8ToWide([url UTF8String])); +} + +- (void)mouseDown:(NSEvent *)theEvent { + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->MouseEvent(theEvent); +} + +- (void)rightMouseDown:(NSEvent *)theEvent { + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->MouseEvent(theEvent); +} + +- (void)otherMouseDown:(NSEvent *)theEvent { + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->MouseEvent(theEvent); +} + +- (void)mouseUp:(NSEvent *)theEvent { + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->MouseEvent(theEvent); +} + +- (void)rightMouseUp:(NSEvent *)theEvent { + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->MouseEvent(theEvent); +} + +- (void)otherMouseUp:(NSEvent *)theEvent { + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->MouseEvent(theEvent); +} + +- (void)mouseMoved:(NSEvent *)theEvent { + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->MouseEvent(theEvent); +} + +- (void)mouseDragged:(NSEvent *)theEvent { + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->MouseEvent(theEvent); +} + +- (void)scrollWheel:(NSEvent *)theEvent { + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->WheelEvent(theEvent); +} + +- (void)rightMouseDragged:(NSEvent *)theEvent { + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->MouseEvent(theEvent); +} + +- (void)otherMouseDragged:(NSEvent *)theEvent { + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->MouseEvent(theEvent); +} + +- (void)mouseEntered:(NSEvent *)theEvent { + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->MouseEvent(theEvent); +} + +- (void)mouseExited:(NSEvent *)theEvent { + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->MouseEvent(theEvent); +} + +- (void)keyDown:(NSEvent *)theEvent { + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->KeyEvent(theEvent); +} + +- (void)keyUp:(NSEvent *)theEvent { + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->KeyEvent(theEvent); +} + +- (BOOL)isOpaque { + return YES; +} + +- (BOOL)canBecomeKeyView { + return browser_ && browser_->GetWebView(); +} + +- (BOOL)acceptsFirstResponder { + return browser_ && browser_->GetWebView(); +} + +- (BOOL)becomeFirstResponder { + if (browser_ && browser_->GetWebView()) { + browser_->GetWebViewHost()->SetFocus(YES); + return YES; + } + + return NO; +} + +- (BOOL)resignFirstResponder { + if (browser_ && browser_->GetWebView()) { + browser_->GetWebViewHost()->SetFocus(NO); + return YES; + } + + return NO; +} + +- (void)setIsActive:(BOOL)active { + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->SetIsActive(active ? true : false); +} + +- (void)setFrame:(NSRect)frameRect { + [super setFrame:frameRect]; + if (browser_ && browser_->GetWebView()) + browser_->GetWebViewHost()->Resize(gfx::Rect(NSRectToCGRect(frameRect))); + [self setNeedsDisplay:YES]; +} + +@end diff --git a/libcef/webview_host_mac.mm b/libcef/webview_host_mac.mm new file mode 100644 index 000000000..5ebd64ff9 --- /dev/null +++ b/libcef/webview_host_mac.mm @@ -0,0 +1,56 @@ +// Copyright (c) 2008 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. + +#import + +#include "webview_host.h" +#include "browser_webview_delegate.h" +#include "browser_webview_mac.h" + +#include "gfx/rect.h" +#include "gfx/size.h" +#include "skia/ext/platform_canvas.h" +#include "third_party/WebKit/WebKit/chromium/public/WebSize.h" +#include "third_party/WebKit/WebKit/chromium/public/WebView.h" +#include "webkit/glue/webpreferences.h" + +using WebKit::WebDevToolsAgentClient; +using WebKit::WebSize; +using WebKit::WebView; + +// static +WebViewHost* WebViewHost::Create(NSView* parent_view, + BrowserWebViewDelegate* delegate, + WebDevToolsAgentClient* dev_tools_client, + const WebPreferences& prefs) { + WebViewHost* host = new WebViewHost(); + + NSRect content_rect = [parent_view frame]; + // bump down the top of the view so that it doesn't overlap the buttons + // and URL field. 32 is an ad hoc constant. + // TODO(awalker): replace explicit view layout with a little nib file + // and use that for view geometry. + content_rect.size.height -= 32; + host->view_ = [[BrowserWebView alloc] initWithFrame:content_rect]; + // make the height and width track the window size. + [host->view_ setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; + [parent_view addSubview:host->view_]; + [host->view_ release]; + + host->webwidget_ = WebView::create(delegate, dev_tools_client); + prefs.Apply(host->webview()); + host->webview()->initializeMainFrame(delegate); + host->webwidget_->resize(WebSize(content_rect.size.width, + content_rect.size.height)); + + return host; +} + +WebView* WebViewHost::webview() const { + return static_cast(webwidget_); +} + +void WebViewHost::SetIsActive(bool active) { + webview()->setIsActive(active); +} diff --git a/libcef/webwidget_host.h b/libcef/webwidget_host.h index 72a83953f..989eb5f3b 100644 --- a/libcef/webwidget_host.h +++ b/libcef/webwidget_host.h @@ -11,6 +11,7 @@ #include "gfx/rect.h" #include "skia/ext/platform_canvas.h" #include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" +#include namespace gfx { class Size; diff --git a/libcef/webwidget_host_mac.mm b/libcef/webwidget_host_mac.mm new file mode 100644 index 000000000..d9b81df1a --- /dev/null +++ b/libcef/webwidget_host_mac.mm @@ -0,0 +1,283 @@ +// Copyright (c) 2008-2009 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. + +#import + +#include "webwidget_host.h" + +#include "base/logging.h" +#include "gfx/rect.h" +#include "gfx/size.h" +#include "skia/ext/platform_canvas.h" +#include "third_party/WebKit/WebKit/chromium/public/mac/WebInputEventFactory.h" +#include "third_party/WebKit/WebKit/chromium/public/mac/WebScreenInfoFactory.h" +#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" +#include "third_party/WebKit/WebKit/chromium/public/WebPopupMenu.h" +#include "third_party/WebKit/WebKit/chromium/public/WebScreenInfo.h" +#include "third_party/WebKit/WebKit/chromium/public/WebSize.h" +#include "webkit/glue/webkit_glue.h" + +using WebKit::WebInputEvent; +using WebKit::WebInputEventFactory; +using WebKit::WebKeyboardEvent; +using WebKit::WebMouseEvent; +using WebKit::WebMouseWheelEvent; +using WebKit::WebPopupMenu; +using WebKit::WebScreenInfo; +using WebKit::WebScreenInfoFactory; +using WebKit::WebSize; +using WebKit::WebWidgetClient; + +/*static*/ +WebWidgetHost* WebWidgetHost::Create(NSView* parent_view, + WebWidgetClient* client) { + WebWidgetHost* host = new WebWidgetHost(); + + NSRect content_rect = [parent_view frame]; + content_rect.origin.y += 64; + content_rect.size.height -= 64; + host->view_ = [[NSView alloc] initWithFrame:content_rect]; + [parent_view addSubview:host->view_]; + + // win_util::SetWindowUserData(host->hwnd_, host); + + host->webwidget_ = WebPopupMenu::create(client); + host->webwidget_->resize(WebSize(content_rect.size.width, + content_rect.size.height)); + return host; +} + +/*static*/ +void WebWidgetHost::HandleEvent(NSView* view, NSEvent* event) { + /* TODO(port): rig up a way to get to the host */ + WebWidgetHost* host = NULL; + if (host) { + switch ([event type]) { + case NSLeftMouseDown: + case NSLeftMouseUp: + case NSRightMouseDown: + case NSRightMouseUp: + case NSOtherMouseDown: + case NSOtherMouseUp: + case NSMouseEntered: + case NSMouseExited: + host->MouseEvent(event); + break; + + case NSScrollWheel: + host->WheelEvent(event); + break; + + case NSKeyDown: + case NSKeyUp: + host->KeyEvent(event); + break; + + case NSAppKitDefined: + switch ([event subtype]) { + case NSApplicationActivatedEventType: + host->SetFocus(true); + break; + case NSApplicationDeactivatedEventType: + host->SetFocus(false); + break; + } + break; + } + } +} + +void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) { +#ifndef NDEBUG + DLOG_IF(WARNING, painting_) << "unexpected invalidation while painting"; +#endif + + // If this invalidate overlaps with a pending scroll, then we have to + // downgrade to invalidating the scroll rect. + if (damaged_rect.Intersects(scroll_rect_)) { + paint_rect_ = paint_rect_.Union(scroll_rect_); + ResetScrollRect(); + } + paint_rect_ = paint_rect_.Union(damaged_rect); + + NSRect r = NSRectFromCGRect(damaged_rect.ToCGRect()); + // flip to cocoa coordinates + r.origin.y = [view_ frame].size.height - r.size.height - r.origin.y; + [view_ setNeedsDisplayInRect:r]; +} + +void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { + DCHECK(dx || dy); + + // If we already have a pending scroll operation or if this scroll operation + // intersects the existing paint region, then just failover to invalidating. + if (!scroll_rect_.IsEmpty() || paint_rect_.Intersects(clip_rect)) { + paint_rect_ = paint_rect_.Union(scroll_rect_); + ResetScrollRect(); + paint_rect_ = paint_rect_.Union(clip_rect); + } + + // We will perform scrolling lazily, when requested to actually paint. + scroll_rect_ = clip_rect; + scroll_dx_ = dx; + scroll_dy_ = dy; + + NSRect r = NSRectFromCGRect(clip_rect.ToCGRect()); + // flip to cocoa coordinates + r.origin.y = [view_ frame].size.height - r.size.height - r.origin.y; + [view_ setNeedsDisplayInRect:r]; +} + +void WebWidgetHost::ScheduleComposite() { + if (!webwidget_) + return; + WebSize size = webwidget_->size(); + NSRect r = NSMakeRect(0, 0, size.width, size.height); + [view_ setNeedsDisplayInRect:r]; +} + +// void WebWidgetHost::SetCursor(HCURSOR cursor) { +// } + +void WebWidgetHost::DiscardBackingStore() { + canvas_.reset(); +} + +WebWidgetHost::WebWidgetHost() + : view_(NULL), + webwidget_(NULL), + scroll_dx_(0), + scroll_dy_(0) { + set_painting(false); +} + +WebWidgetHost::~WebWidgetHost() { + // win_util::SetWindowUserData(hwnd_, 0); + + webwidget_->close(); +} + +void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) { + paint_rect_ = paint_rect_.Union(rect); +} + +void WebWidgetHost::Paint() { + gfx::Rect client_rect(NSRectToCGRect([view_ frame])); + NSGraphicsContext* view_context = [NSGraphicsContext currentContext]; + CGContextRef context = static_cast([view_context graphicsPort]); + + // Allocate a canvas if necessary + if (!canvas_.get()) { + ResetScrollRect(); + paint_rect_ = client_rect; + canvas_.reset(new skia::PlatformCanvas( + paint_rect_.width(), paint_rect_.height(), true)); + } + + // make sure webkit draws into our bitmap, not the window + CGContextRef bitmap_context = + canvas_->getTopPlatformDevice().GetBitmapContext(); + [NSGraphicsContext setCurrentContext: + [NSGraphicsContext graphicsContextWithGraphicsPort:bitmap_context + flipped:YES]]; + + // This may result in more invalidation + webwidget_->layout(); + + // Scroll the canvas if necessary + scroll_rect_ = client_rect.Intersect(scroll_rect_); + if (!scroll_rect_.IsEmpty()) { + // add to invalidate rect, since there's no equivalent of ScrollDC. + paint_rect_ = paint_rect_.Union(scroll_rect_); + } + ResetScrollRect(); + + // Paint the canvas if necessary. Allow painting to generate extra rects the + // first time we call it. This is necessary because some WebCore rendering + // objects update their layout only when painted. + for (int i = 0; i < 2; ++i) { + paint_rect_ = client_rect.Intersect(paint_rect_); + if (!paint_rect_.IsEmpty()) { + gfx::Rect rect(paint_rect_); + paint_rect_ = gfx::Rect(); + +// DLOG_IF(WARNING, i == 1) << "painting caused additional invalidations"; + PaintRect(rect); + } + } + DCHECK(paint_rect_.IsEmpty()); + + // set the context back to our window + [NSGraphicsContext setCurrentContext: view_context]; + + // Paint to the screen + if ([view_ lockFocusIfCanDraw]) { + int bitmap_height = CGBitmapContextGetHeight(bitmap_context); + int bitmap_width = CGBitmapContextGetWidth(bitmap_context); + CGRect bitmap_rect = { { 0, 0 }, + { bitmap_width, bitmap_height } }; + canvas_->getTopPlatformDevice().DrawToContext( + context, 0, client_rect.height() - bitmap_height, &bitmap_rect); + + [view_ unlockFocus]; + } +} + +void WebWidgetHost::SetTooltipText(const std::wstring& tooltip_text) { + NOTIMPLEMENTED(); +} + +WebScreenInfo WebWidgetHost::GetScreenInfo() { + return WebScreenInfoFactory::screenInfo(view_); +} + +void WebWidgetHost::Resize(const gfx::Rect& rect) { + // Force an entire re-paint. TODO(darin): Maybe reuse this memory buffer. + DiscardBackingStore(); + webwidget_->resize(WebSize(rect.width(), rect.height())); +} + +void WebWidgetHost::MouseEvent(NSEvent *event) { + const WebMouseEvent& web_event = WebInputEventFactory::mouseEvent( + event, view_); + webwidget_->handleInputEvent(web_event); +} + +void WebWidgetHost::WheelEvent(NSEvent *event) { + webwidget_->handleInputEvent( + WebInputEventFactory::mouseWheelEvent(event, view_)); +} + +void WebWidgetHost::KeyEvent(NSEvent *event) { + WebKeyboardEvent keyboard_event(WebInputEventFactory::keyboardEvent(event)); + webwidget_->handleInputEvent(keyboard_event); + if ([event type] == NSKeyDown) { + // Send a Char event here to emulate the keyboard events. + // TODO(hbono): Bug 20852 implement the + // NSTextInput protocol and remove this code. + keyboard_event.type = WebInputEvent::Char; + webwidget_->handleInputEvent(keyboard_event); + } +} + +void WebWidgetHost::SetFocus(bool enable) { + webwidget_->setFocus(enable); +} + +void WebWidgetHost::ResetScrollRect() { + scroll_rect_ = gfx::Rect(); + scroll_dx_ = 0; + scroll_dy_ = 0; +} + +void WebWidgetHost::PaintRect(const gfx::Rect& rect) { +#ifndef NDEBUG + DCHECK(!painting_); +#endif + DCHECK(canvas_.get()); + + set_painting(true); + webwidget_->paint(webkit_glue::ToWebCanvas(canvas_.get()), rect); + set_painting(false); +}