diff --git a/cef.gyp b/cef.gyp index f91630bf0..47c0ba4ec 100644 --- a/cef.gyp +++ b/cef.gyp @@ -183,6 +183,7 @@ [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', { 'dependencies': [ 'gtk', + 'gtkglext', 'libcef', ], 'link_settings': { @@ -397,6 +398,8 @@ 'tests/cefclient/client_app.h', 'tests/cefclient/client_switches.cpp', 'tests/cefclient/client_switches.h', + 'tests/cefclient/resource_util.h', + 'tests/cefclient/res/osr_test.html', 'tests/unittests/browser_info_map_unittest.cc', 'tests/unittests/command_line_unittest.cc', 'tests/unittests/cookie_unittest.cc', @@ -409,6 +412,7 @@ 'tests/unittests/life_span_unittest.cc', 'tests/unittests/message_router_unittest.cc', 'tests/unittests/navigation_unittest.cc', + 'tests/unittests/os_rendering_unittest.cc', 'tests/unittests/process_message_unittest.cc', 'tests/unittests/request_context_unittest.cc', 'tests/unittests/request_handler_unittest.cc', @@ -438,6 +442,7 @@ 'tests/unittests/zip_reader_unittest.cc', ], 'mac_bundle_resources': [ + 'tests/cefclient/res/osr_test.html', 'tests/unittests/mac/unittests.icns', 'tests/unittests/mac/English.lproj/InfoPlist.strings', 'tests/unittests/mac/English.lproj/MainMenu.xib', @@ -467,6 +472,10 @@ 'cef_sandbox', 'libcef', ], + 'sources': [ + 'tests/cefclient/cefclient.rc', + 'tests/cefclient/resource_util_win.cpp', + ], 'msvs_settings': { 'VCManifestTool': { 'AdditionalManifestFiles': [ @@ -553,6 +562,10 @@ ], }, 'sources': [ + 'tests/cefclient/resource_util_mac.mm', + 'tests/cefclient/resource_util_posix.cpp', + 'tests/unittests/os_rendering_unittest_mac.h', + 'tests/unittests/os_rendering_unittest_mac.mm', 'tests/unittests/run_all_unittests_mac.mm', ], }], @@ -560,6 +573,18 @@ 'dependencies': [ 'libcef', ], + 'sources': [ + 'tests/cefclient/resource_util_linux.cpp', + 'tests/cefclient/resource_util_posix.cpp', + ], + 'copies': [ + { + 'destination': '<(PRODUCT_DIR)/files', + 'files': [ + 'tests/cefclient/res/osr_test.html', + ], + }, + ], }], ], }, @@ -901,6 +926,8 @@ 'libcef/browser/printing/print_view_manager_base.h', 'libcef/browser/process_util_impl.cc', 'libcef/browser/proxy_stubs.cc', + 'libcef/browser/render_widget_host_view_osr.cc', + 'libcef/browser/render_widget_host_view_osr.h', 'libcef/browser/resource_dispatcher_host_delegate.cc', 'libcef/browser/resource_dispatcher_host_delegate.h', 'libcef/browser/resource_request_job.cc', @@ -931,6 +958,8 @@ 'libcef/browser/url_request_interceptor.h', 'libcef/browser/url_request_user_data.cc', 'libcef/browser/url_request_user_data.h', + 'libcef/browser/web_contents_view_osr.cc', + 'libcef/browser/web_contents_view_osr.h', 'libcef/browser/web_plugin_impl.cc', 'libcef/browser/web_plugin_impl.h', 'libcef/browser/xml_reader_impl.cc', @@ -1073,6 +1102,7 @@ 'libcef/browser/javascript_dialog_win.cc', 'libcef/browser/menu_creator_runner_win.cc', 'libcef/browser/menu_creator_runner_win.h', + 'libcef/browser/render_widget_host_view_osr_win.cc', # Include sources for printing. '<(DEPTH)/chrome/renderer/printing/print_web_view_helper_win.cc', ], @@ -1085,6 +1115,9 @@ 'libcef/browser/javascript_dialog_mac.mm', 'libcef/browser/menu_creator_runner_mac.h', 'libcef/browser/menu_creator_runner_mac.mm', + 'libcef/browser/render_widget_host_view_osr_mac.mm', + 'libcef/browser/text_input_client_osr_mac.mm', + 'libcef/browser/text_input_client_osr_mac.h', # Include sources for printing. '<(DEPTH)/chrome/renderer/printing/print_web_view_helper_mac.mm', # Include sources for CoreAnimation support. @@ -1100,6 +1133,7 @@ 'libcef/browser/javascript_dialog_linux.cc', 'libcef/browser/menu_creator_runner_linux.cc', 'libcef/browser/menu_creator_runner_linux.h', + 'libcef/browser/render_widget_host_view_osr_linux.cc', 'libcef/browser/window_x11.cc', 'libcef/browser/window_x11.h', #Include sources for printing. @@ -1632,6 +1666,27 @@ ], }, }, + { + 'target_name': 'gtkglext', + 'type': 'none', + 'variables': { + # gtkglext is required by the cefclient OSR example. + 'gtk_packages': 'gtkglext-1.0', + }, + 'direct_dependent_settings': { + 'cflags': [ + ' drag_data, + const CefMouseEvent& event, + DragOperationsMask allowed_ops) =0; + + /// + // Call this method each time the mouse is moved across the web view during + // a drag operation (after calling DragTargetDragEnter and before calling + // DragTargetDragLeave/DragTargetDrop). + // This method is only used when window rendering is disabled. + /// + /*--cef()--*/ + virtual void DragTargetDragOver(const CefMouseEvent& event, + DragOperationsMask allowed_ops) =0; + + /// + // Call this method when the user drags the mouse out of the web view (after + // calling DragTargetDragEnter). + // This method is only used when window rendering is disabled. + /// + /*--cef()--*/ + virtual void DragTargetDragLeave() =0; + + /// + // Call this method when the user completes the drag operation by dropping + // the object onto the web view (after calling DragTargetDragEnter). + // The object being dropped is |drag_data|, given as an argument to + // the previous DragTargetDragEnter call. + // This method is only used when window rendering is disabled. + /// + /*--cef()--*/ + virtual void DragTargetDrop(const CefMouseEvent& event) =0; + + /// + // Call this method when the drag operation started by a + // CefRenderHandler::StartDragging call has ended either in a drop or + // by being cancelled. |x| and |y| are mouse coordinates relative to the + // upper-left corner of the view. If the web view is both the drag source + // and the drag target then all DragTarget* methods should be called before + // DragSource* mthods. + // This method is only used when window rendering is disabled. + /// + /*--cef()--*/ + virtual void DragSourceEndedAt(int x, int y, DragOperationsMask op) =0; + + /// + // Call this method when the drag operation started by a + // CefRenderHandler::StartDragging call has completed. This method may be + // called immediately without first calling DragSourceEndedAt to cancel a + // drag operation. If the web view is both the drag source and the drag + // target then all DragTarget* methods should be called before DragSource* + // mthods. + // This method is only used when window rendering is disabled. + /// + /*--cef()--*/ + virtual void DragSourceSystemDragEnded() =0; }; #endif // CEF_INCLUDE_CEF_BROWSER_H_ diff --git a/include/cef_client.h b/include/cef_client.h index f70a9b276..d413e0e64 100644 --- a/include/cef_client.h +++ b/include/cef_client.h @@ -51,6 +51,7 @@ #include "include/cef_life_span_handler.h" #include "include/cef_load_handler.h" #include "include/cef_process_message.h" +#include "include/cef_render_handler.h" #include "include/cef_request_handler.h" /// @@ -152,6 +153,14 @@ class CefClient : public virtual CefBase { return NULL; } + /// + // Return the handler for off-screen rendering events. + /// + /*--cef()--*/ + virtual CefRefPtr GetRenderHandler() { + return NULL; + } + /// // Return the handler for browser request events. /// diff --git a/include/cef_drag_data.h b/include/cef_drag_data.h index 58bcc3ed4..8f8094b44 100644 --- a/include/cef_drag_data.h +++ b/include/cef_drag_data.h @@ -39,6 +39,7 @@ #pragma once #include "include/cef_base.h" +#include "include/cef_stream.h" #include /// @@ -48,6 +49,24 @@ /*--cef(source=library)--*/ class CefDragData : public virtual CefBase { public: + /// + // Create a new CefDragData object. + /// + /*--cef()--*/ + static CefRefPtr Create(); + + /// + // Returns a copy of the current object. + /// + /*--cef()--*/ + virtual CefRefPtr Clone() =0; + + /// + // Returns true if this object is read-only. + /// + /*--cef()--*/ + virtual bool IsReadOnly() =0; + /// // Returns true if the drag data is a link. /// @@ -109,12 +128,71 @@ class CefDragData : public virtual CefBase { /*--cef()--*/ virtual CefString GetFileName() =0; + /// + // Write the contents of the file being dragged out of the web view into + // |writer|. Returns the number of bytes sent to |writer|. If |writer| is + // NULL this method will return the size of the file contents in bytes. + // Call GetFileName() to get a suggested name for the file. + /// + /*--cef(optional_param=writer)--*/ + virtual size_t GetFileContents(CefRefPtr writer) =0; + /// // Retrieve the list of file names that are being dragged into the browser // window. /// /*--cef()--*/ virtual bool GetFileNames(std::vector& names) =0; + + /// + // Set the link URL that is being dragged. + /// + /*--cef(optional_param=url)--*/ + virtual void SetLinkURL(const CefString& url) =0; + + /// + // Set the title associated with the link being dragged. + /// + /*--cef(optional_param=title)--*/ + virtual void SetLinkTitle(const CefString& title) =0; + + /// + // Set the metadata associated with the link being dragged. + /// + /*--cef(optional_param=data)--*/ + virtual void SetLinkMetadata(const CefString& data) =0; + + /// + // Set the plain text fragment that is being dragged. + /// + /*--cef(optional_param=text)--*/ + virtual void SetFragmentText(const CefString& text) =0; + + /// + // Set the text/html fragment that is being dragged. + /// + /*--cef(optional_param=html)--*/ + virtual void SetFragmentHtml(const CefString& html) =0; + + /// + // Set the base URL that the fragment came from. + /// + /*--cef(optional_param=base_url)--*/ + virtual void SetFragmentBaseURL(const CefString& base_url) =0; + + /// + // Reset the file contents. You should do this before calling + // CefBrowserHost::DragTargetDragEnter as the web view does not allow us to + // drag in this kind of data. + /// + /*--cef()--*/ + virtual void ResetFileContents() =0; + + /// + // Add a file that is being dragged into the webview. + /// + /*--cef(optional_param=display_name)--*/ + virtual void AddFile(const CefString& path, const CefString& display_name) =0; }; #endif // CEF_INCLUDE_CEF_DRAG_DATA_H_ diff --git a/include/cef_render_handler.h b/include/cef_render_handler.h new file mode 100644 index 000000000..aa4157f8d --- /dev/null +++ b/include/cef_render_handler.h @@ -0,0 +1,170 @@ +// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the name Chromium Embedded +// Framework nor the names of its contributors may be used to endorse +// or promote products derived from this software without specific prior +// written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER OR 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. +// +// --------------------------------------------------------------------------- +// +// The contents of this file must follow a specific format in order to +// support the CEF translator tool. See the translator.README.txt file in the +// tools directory for more information. +// + +#ifndef CEF_INCLUDE_CEF_RENDER_HANDLER_H_ +#define CEF_INCLUDE_CEF_RENDER_HANDLER_H_ +#pragma once + +#include "include/cef_base.h" +#include "include/cef_browser.h" +#include "include/cef_drag_data.h" +#include + +/// +// Implement this interface to handle events when window rendering is disabled. +// The methods of this class will be called on the UI thread. +/// +/*--cef(source=client)--*/ +class CefRenderHandler : public virtual CefBase { + public: + typedef cef_drag_operations_mask_t DragOperation; + typedef cef_drag_operations_mask_t DragOperationsMask; + typedef cef_paint_element_type_t PaintElementType; + typedef std::vector RectList; + + /// + // Called to retrieve the root window rectangle in screen coordinates. Return + // true if the rectangle was provided. + /// + /*--cef()--*/ + virtual bool GetRootScreenRect(CefRefPtr browser, + CefRect& rect) { return false; } + + /// + // Called to retrieve the view rectangle which is relative to screen + // coordinates. Return true if the rectangle was provided. + /// + /*--cef()--*/ + virtual bool GetViewRect(CefRefPtr browser, CefRect& rect) =0; + + /// + // Called to retrieve the translation from view coordinates to actual screen + // coordinates. Return true if the screen coordinates were provided. + /// + /*--cef()--*/ + virtual bool GetScreenPoint(CefRefPtr browser, + int viewX, + int viewY, + int& screenX, + int& screenY) { return false; } + + /// + // Called to allow the client to fill in the CefScreenInfo object with + // appropriate values. Return true if the |screen_info| structure has been + // modified. + // + // If the screen info rectangle is left empty the rectangle from GetViewRect + // will be used. If the rectangle is still empty or invalid popups may not be + // drawn correctly. + /// + /*--cef()--*/ + virtual bool GetScreenInfo(CefRefPtr browser, + CefScreenInfo& screen_info) { return false; } + + /// + // Called when the browser wants to show or hide the popup widget. The popup + // should be shown if |show| is true and hidden if |show| is false. + /// + /*--cef()--*/ + virtual void OnPopupShow(CefRefPtr browser, + bool show) {} + + /// + // Called when the browser wants to move or resize the popup widget. |rect| + // contains the new location and size. + /// + /*--cef()--*/ + virtual void OnPopupSize(CefRefPtr browser, + const CefRect& rect) {} + + /// + // Called when an element should be painted. |type| indicates whether the + // element is the view or the popup widget. |buffer| contains the pixel data + // for the whole image. |dirtyRects| contains the set of rectangles that need + // to be repainted. On Windows |buffer| will be |width|*|height|*4 bytes + // in size and represents a BGRA image with an upper-left origin. + /// + /*--cef()--*/ + virtual void OnPaint(CefRefPtr browser, + PaintElementType type, + const RectList& dirtyRects, + const void* buffer, + int width, int height) =0; + + /// + // Called when the browser window's cursor has changed. + /// + /*--cef()--*/ + virtual void OnCursorChange(CefRefPtr browser, + CefCursorHandle cursor) {} + + /// + // Called when the user starts dragging content in the web view. Contextual + // information about the dragged content is supplied by |drag_data|. + // OS APIs that run a system message loop may be used within the + // StartDragging call. + // + // Return false to abort the drag operation. Don't call any of + // CefBrowserHost::DragSource*Ended* methods after returning false. + // + // Return true to handle the drag operation. Call + // CefBrowserHost::DragSourceEndedAt and DragSourceSystemDragEnded either + // synchronously or asynchronously to inform the web view that the drag + // operation has ended. + /// + /*--cef()--*/ + virtual bool StartDragging(CefRefPtr browser, + CefRefPtr drag_data, + DragOperationsMask allowed_ops, + int x, int y) { return false; } + + /// + // Called when the web view wants to update the mouse cursor during a + // drag & drop operation. |operation| describes the allowed operation + // (none, move, copy, link). + /// + /*--cef()--*/ + virtual void UpdateDragCursor(CefRefPtr browser, + DragOperation operation) {} + + /// + // Called when the scroll offset has changed. + /// + /*--cef()--*/ + virtual void OnScrollOffsetChanged(CefRefPtr browser) {} +}; + +#endif // CEF_INCLUDE_CEF_RENDER_HANDLER_H_ diff --git a/include/internal/cef_linux.h b/include/internal/cef_linux.h index 405e2a198..f0a443306 100644 --- a/include/internal/cef_linux.h +++ b/include/internal/cef_linux.h @@ -72,6 +72,7 @@ class CefCriticalSection { #define CefCursorHandle cef_cursor_handle_t #define CefEventHandle cef_event_handle_t #define CefWindowHandle cef_window_handle_t +#define CefTextInputContext cef_text_input_context_t struct CefMainArgsTraits { typedef cef_main_args_t struct_type; @@ -113,6 +114,8 @@ struct CefWindowInfoTraits { target->width = src->width; target->height = src->height; target->parent_window = src->parent_window; + target->windowless_rendering_enabled = src->windowless_rendering_enabled; + target->transparent_painting_enabled = src->transparent_painting_enabled; target->window = src->window; } }; @@ -137,6 +140,24 @@ class CefWindowInfo : public CefStructBase { width = windowRect.width; height = windowRect.height; } + + /// + // Create the browser using windowless (off-screen) rendering. No window + // will be created for the browser and all rendering will occur via the + // CefRenderHandler interface. The |parent| value will be used to identify + // monitor info and to act as the parent window for dialogs, context menus, + // etc. If |parent| is not provided then the main screen monitor will be used + // and some functionality that requires a parent window may not function + // correctly. If |transparent| is true a transparent background color will be + // used (RGBA=0x00000000). If |transparent| is false the background will be + // white and opaque. In order to create windowless browsers the + // CefSettings.windowless_rendering_enabled value must be set to true. + /// + void SetAsWindowless(CefWindowHandle parent, bool transparent) { + windowless_rendering_enabled = true; + parent_window = parent; + transparent_painting_enabled = transparent; + } }; #endif // OS_LINUX diff --git a/include/internal/cef_mac.h b/include/internal/cef_mac.h index 4d61f85c5..2e4bcbc07 100644 --- a/include/internal/cef_mac.h +++ b/include/internal/cef_mac.h @@ -72,6 +72,7 @@ class CefCriticalSection { #define CefCursorHandle cef_cursor_handle_t #define CefEventHandle cef_event_handle_t #define CefWindowHandle cef_window_handle_t +#define CefTextInputContext cef_text_input_context_t struct CefMainArgsTraits { typedef cef_main_args_t struct_type; @@ -119,6 +120,8 @@ struct CefWindowInfoTraits { target->height = src->height; target->hidden = src->hidden; target->parent_view = src->parent_view; + target->windowless_rendering_enabled = src->windowless_rendering_enabled; + target->transparent_painting_enabled = src->transparent_painting_enabled; target->view = src->view; } }; @@ -144,6 +147,24 @@ class CefWindowInfo : public CefStructBase { this->height = height; hidden = false; } + + /// + // Create the browser using windowless (off-screen) rendering. No view + // will be created for the browser and all rendering will occur via the + // CefRenderHandler interface. The |parent| value will be used to identify + // monitor info and to act as the parent view for dialogs, context menus, + // etc. If |parent| is not provided then the main screen monitor will be used + // and some functionality that requires a parent view may not function + // correctly. If |transparent| is true a transparent background color will be + // used (RGBA=0x00000000). If |transparent| is false the background will be + // white and opaque. In order to create windowless browsers the + // CefSettings.windowless_rendering_enabled value must be set to true. + /// + void SetAsWindowless(CefWindowHandle parent, bool transparent) { + windowless_rendering_enabled = true; + parent_view = parent; + transparent_painting_enabled = transparent; + } }; #endif // OS_MACOSX diff --git a/include/internal/cef_types.h b/include/internal/cef_types.h index 9b065112c..c6159b03d 100644 --- a/include/internal/cef_types.h +++ b/include/internal/cef_types.h @@ -223,6 +223,13 @@ typedef struct _cef_settings_t { /// int multi_threaded_message_loop; + /// + // Set to true (1) to enable windowless (off-screen) rendering support. Do not + // enable this value if the application does not use windowless rendering as + // it may reduce rendering performance on some systems. + /// + int windowless_rendering_enabled; + /// // Set to true (1) to disable configuration of browser process features using // standard CEF and Chromium command-line arguments. Configuration can still @@ -393,6 +400,14 @@ typedef struct _cef_browser_settings_t { /// size_t size; + /// + // The maximum rate in frames per second (fps) that CefRenderHandler::OnPaint + // will be called for a windowless browser. The actual fps may be lower if + // the browser cannot generate frames at the requested rate. The minimum + // value is 1 and the maximum value is 60 (default 30). + /// + int windowless_frame_rate; + // The below values map to WebPreferences settings. /// @@ -1306,6 +1321,14 @@ typedef struct _cef_mouse_event_t { uint32 modifiers; } cef_mouse_event_t; +/// +// Paint element types. +/// +typedef enum { + PET_VIEW = 0, + PET_POPUP, +} cef_paint_element_type_t; + /// // Supported event bit flags. /// diff --git a/include/internal/cef_types_linux.h b/include/internal/cef_types_linux.h index 5127f3c76..190f3d6bb 100644 --- a/include/internal/cef_types_linux.h +++ b/include/internal/cef_types_linux.h @@ -60,6 +60,7 @@ extern "C" { // thread-safe and must only be accessed on the browser process UI thread. /// CEF_EXPORT XDisplay* cef_get_xdisplay(); +#define cef_text_input_context_t void* /// // Structure representing CefExecuteProcess arguments. @@ -83,6 +84,26 @@ typedef struct _cef_window_info_t { /// cef_window_handle_t parent_window; + /// + // Set to true (1) to create the browser using windowless (off-screen) + // rendering. No window will be created for the browser and all rendering will + // occur via the CefRenderHandler interface. The |parent_window| value will be + // used to identify monitor info and to act as the parent window for dialogs, + // context menus, etc. If |parent_window| is not provided then the main screen + // monitor will be used and some functionality that requires a parent window + // may not function correctly. In order to create windowless browsers the + // CefSettings.windowless_rendering_enabled value must be set to true. + /// + int windowless_rendering_enabled; + + /// + // Set to true (1) to enable transparent painting in combination with + // windowless rendering. When this value is true a transparent background + // color will be used (RGBA=0x00000000). When this value is false the + // background will be white and opaque. + /// + int transparent_painting_enabled; + /// // Pointer for the new browser window. Only used with windowed rendering. /// diff --git a/include/internal/cef_types_mac.h b/include/internal/cef_types_mac.h index 580172231..69c64fdb3 100644 --- a/include/internal/cef_types_mac.h +++ b/include/internal/cef_types_mac.h @@ -43,18 +43,22 @@ @class NSCursor; @class NSEvent; @class NSView; +@class NSTextInputContext; #else class NSCursor; class NSEvent; struct NSView; +class NSTextInputContext; #endif #define cef_cursor_handle_t NSCursor* #define cef_event_handle_t NSEvent* #define cef_window_handle_t NSView* +#define cef_text_input_context_t NSTextInputContext* #else #define cef_cursor_handle_t void* #define cef_event_handle_t void* #define cef_window_handle_t void* +#define cef_text_input_context_t void* #endif #define kNullCursorHandle NULL @@ -93,6 +97,26 @@ typedef struct _cef_window_info_t { /// cef_window_handle_t parent_view; + /// + // Set to true (1) to create the browser using windowless (off-screen) + // rendering. No view will be created for the browser and all rendering will + // occur via the CefRenderHandler interface. The |parent_view| value will be + // used to identify monitor info and to act as the parent view for dialogs, + // context menus, etc. If |parent_view| is not provided then the main screen + // monitor will be used and some functionality that requires a parent view + // may not function correctly. In order to create windowless browsers the + // CefSettings.windowless_rendering_enabled value must be set to true. + /// + int windowless_rendering_enabled; + + /// + // Set to true (1) to enable transparent painting in combination with + // windowless rendering. When this value is true a transparent background + // color will be used (RGBA=0x00000000). When this value is false the + // background will be white and opaque. + /// + int transparent_painting_enabled; + /// // NSView pointer for the new browser view. Only used with windowed rendering. /// diff --git a/include/internal/cef_types_win.h b/include/internal/cef_types_win.h index c4e020268..708dd58ea 100644 --- a/include/internal/cef_types_win.h +++ b/include/internal/cef_types_win.h @@ -42,6 +42,7 @@ #define cef_cursor_handle_t HCURSOR #define cef_event_handle_t MSG* #define cef_window_handle_t HWND +#define cef_text_input_context_t void* #define kNullCursorHandle NULL #define kNullEventHandle NULL @@ -73,6 +74,26 @@ typedef struct _cef_window_info_t { cef_window_handle_t parent_window; HMENU menu; + /// + // Set to true (1) to create the browser using windowless (off-screen) + // rendering. No window will be created for the browser and all rendering will + // occur via the CefRenderHandler interface. The |parent_window| value will be + // used to identify monitor info and to act as the parent window for dialogs, + // context menus, etc. If |parent_window| is not provided then the main screen + // monitor will be used and some functionality that requires a parent window + // may not function correctly. In order to create windowless browsers the + // CefSettings.windowless_rendering_enabled value must be set to true. + /// + int windowless_rendering_enabled; + + /// + // Set to true (1) to enable transparent painting in combination with + // windowless rendering. When this value is true a transparent background + // color will be used (RGBA=0x00000000). When this value is false the + // background will be white and opaque. + /// + int transparent_painting_enabled; + /// // Handle for the new browser window. Only used with windowed rendering. /// diff --git a/include/internal/cef_types_wrappers.h b/include/internal/cef_types_wrappers.h index 49b43f8bf..d37e19269 100644 --- a/include/internal/cef_types_wrappers.h +++ b/include/internal/cef_types_wrappers.h @@ -349,6 +349,7 @@ struct CefSettingsTraits { src->browser_subprocess_path.length, &target->browser_subprocess_path, copy); target->multi_threaded_message_loop = src->multi_threaded_message_loop; + target->windowless_rendering_enabled = src->windowless_rendering_enabled; target->command_line_args_disabled = src->command_line_args_disabled; cef_string_set(src->cache_path.str, src->cache_path.length, @@ -405,6 +406,8 @@ struct CefBrowserSettingsTraits { static inline void set(const struct_type* src, struct_type* target, bool copy) { + target->windowless_frame_rate = src->windowless_frame_rate; + cef_string_set(src->standard_font_family.str, src->standard_font_family.length, &target->standard_font_family, copy); cef_string_set(src->fixed_font_family.str, src->fixed_font_family.length, diff --git a/include/internal/cef_win.h b/include/internal/cef_win.h index 857ae7b64..4346f2b64 100644 --- a/include/internal/cef_win.h +++ b/include/internal/cef_win.h @@ -71,6 +71,7 @@ class CefCriticalSection { #define CefCursorHandle cef_cursor_handle_t #define CefEventHandle cef_event_handle_t #define CefWindowHandle cef_window_handle_t +#define CefTextInputContext cef_text_input_context_t struct CefMainArgsTraits { typedef cef_main_args_t struct_type; @@ -118,6 +119,8 @@ struct CefWindowInfoTraits { target->height = src->height; target->parent_window = src->parent_window; target->menu = src->menu; + target->transparent_painting_enabled = src->transparent_painting_enabled; + target->windowless_rendering_enabled = src->windowless_rendering_enabled; target->window = src->window; } }; @@ -160,6 +163,24 @@ class CefWindowInfo : public CefStructBase { cef_string_copy(windowName.c_str(), windowName.length(), &window_name); } + + /// + // Create the browser using windowless (off-screen) rendering. No window + // will be created for the browser and all rendering will occur via the + // CefRenderHandler interface. The |parent| value will be used to identify + // monitor info and to act as the parent window for dialogs, context menus, + // etc. If |parent| is not provided then the main screen monitor will be used + // and some functionality that requires a parent window may not function + // correctly. If |transparent| is true a transparent background color will be + // used (RGBA=0x00000000). If |transparent| is false the background will be + // white and opaque. In order to create windowless browsers the + // CefSettings.windowless_rendering_enabled value must be set to true. + /// + void SetAsWindowless(CefWindowHandle parent, bool transparent) { + windowless_rendering_enabled = TRUE; + parent_window = parent; + transparent_painting_enabled = transparent; + } }; #endif // OS_WIN diff --git a/libcef/browser/browser_host_impl.cc b/libcef/browser/browser_host_impl.cc index 6800a5340..20c36686a 100644 --- a/libcef/browser/browser_host_impl.cc +++ b/libcef/browser/browser_host_impl.cc @@ -19,8 +19,10 @@ #include "libcef/browser/media_capture_devices_dispatcher.h" #include "libcef/browser/navigate_params.h" #include "libcef/browser/printing/print_view_manager.h" +#include "libcef/browser/render_widget_host_view_osr.h" #include "libcef/browser/request_context_impl.h" #include "libcef/browser/scheme_handler.h" +#include "libcef/browser/web_contents_view_osr.h" #include "libcef/browser/thread_util.h" #include "libcef/common/cef_messages.h" #include "libcef/common/cef_switches.h" @@ -33,6 +35,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h" +#include "content/browser/gpu/compositor_util.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/common/view_messages.h" #include "content/public/browser/download_manager.h" @@ -284,6 +287,18 @@ bool CefBrowserHost::CreateBrowser( return false; } + // Verify windowless rendering requirements. + if (windowInfo.windowless_rendering_enabled) { + if (!client->GetRenderHandler().get()) { + NOTREACHED() << "CefRenderHandler implementation is required"; + return false; + } + if (!content::IsDelegatedRendererEnabled()) { + NOTREACHED() << "Delegated renderer must be enabled"; + return false; + } + } + // Create the browser on the UI thread. CreateBrowserHelper* helper = new CreateBrowserHelper(windowInfo, client, url, settings, @@ -337,8 +352,22 @@ CefRefPtr CefBrowserHostImpl::Create( CefWindowHandle opener, bool is_popup, CefRefPtr request_context) { + // Verify windowless rendering requirements. + if (windowInfo.windowless_rendering_enabled) { + if (!client->GetRenderHandler().get()) { + NOTREACHED() << "CefRenderHandler implementation is required"; + return NULL; + } + if (!content::IsDelegatedRendererEnabled()) { + NOTREACHED() << "Delegated renderer must be enabled"; + return NULL; + } + } + scoped_refptr info = CefContentBrowserClient::Get()->CreateBrowserInfo(is_popup); + info->set_windowless(windowInfo.windowless_rendering_enabled ? true : false); + CefRefPtr browser = CefBrowserHostImpl::CreateInternal(windowInfo, settings, client, NULL, info, opener, request_context); @@ -377,15 +406,24 @@ CefRefPtr CefBrowserHostImpl::CreateInternal( content::WebContents::CreateParams create_params( browser_context); + + if (window_info.windowless_rendering_enabled) { + // Use the OSR view instead of the default view. + CefWebContentsViewOSR* view_or = new CefWebContentsViewOSR( + web_contents, + CefContentBrowserClient::Get()->GetWebContentsViewDelegate( + web_contents)); + create_params.view = view_or; + create_params.delegate_view = view_or; + } web_contents = content::WebContents::Create(create_params); } CefRefPtr browser = new CefBrowserHostImpl(window_info, settings, client, web_contents, browser_info, opener); - if (!browser->PlatformCreateWindow()) { + if (!browser->IsWindowless() && !browser->PlatformCreateWindow()) return NULL; - } #if defined(OS_LINUX) || defined(OS_ANDROID) content::RendererPreferences* prefs = web_contents->GetMutableRendererPrefs(); @@ -606,7 +644,8 @@ void CefBrowserHostImpl::CloseBrowser(bool force_close) { if (CEF_CURRENTLY_ON_UIT()) { // Exit early if a close attempt is already pending and this method is // called again from somewhere other than WindowDestroyed(). - if (destruction_state_ >= DESTRUCTION_STATE_PENDING && !window_destroyed_) { + if (destruction_state_ >= DESTRUCTION_STATE_PENDING && + (IsWindowless() || !window_destroyed_)) { if (force_close && destruction_state_ == DESTRUCTION_STATE_PENDING) { // Upgrade the destruction state. destruction_state_ = DESTRUCTION_STATE_ACCEPTED; @@ -856,6 +895,101 @@ bool CefBrowserHostImpl::IsMouseCursorChangeDisabled() { return mouse_cursor_change_disabled_; } +bool CefBrowserHostImpl::IsWindowRenderingDisabled() { + return IsWindowless(); +} + +void CefBrowserHostImpl::WasResized() { + if (!IsWindowless()) { + NOTREACHED() << "Window rendering is not disabled"; + return; + } + + if (!CEF_CURRENTLY_ON_UIT()) { + CEF_POST_TASK(CEF_UIT, base::Bind(&CefBrowserHostImpl::WasResized, this)); + return; + } + + if (!web_contents()) + return; + + CefRenderWidgetHostViewOSR* view = + static_cast( + web_contents()->GetRenderViewHost()->GetView()); + if (view) + view->WasResized(); +} + +void CefBrowserHostImpl::WasHidden(bool hidden) { + if (!IsWindowless()) { + NOTREACHED() << "Window rendering is not disabled"; + return; + } + + if (!CEF_CURRENTLY_ON_UIT()) { + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefBrowserHost::WasHidden, this, hidden)); + return; + } + + if (!web_contents()) + return; + + CefRenderWidgetHostViewOSR* view = + static_cast( + web_contents()->GetRenderViewHost()->GetView()); + if (view) { + if (hidden) + view->WasHidden(); + else + view->WasShown(); + } +} + +void CefBrowserHostImpl::NotifyScreenInfoChanged() { + if (!CEF_CURRENTLY_ON_UIT()) { + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefBrowserHostImpl::NotifyScreenInfoChanged, this)); + return; + } + + if (!IsWindowless()) { + NOTREACHED() << "Window rendering is not disabled"; + return; + } + + if (!web_contents()) + return; + + CefRenderWidgetHostViewOSR* view = + static_cast( + web_contents()->GetRenderViewHost()->GetView()); + if (view) + view->OnScreenInfoChanged(); +} + +void CefBrowserHostImpl::Invalidate(PaintElementType type) { + if (!IsWindowless()) { + NOTREACHED() << "Window rendering is not disabled"; + return; + } + + if (!CEF_CURRENTLY_ON_UIT()) { + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefBrowserHostImpl::Invalidate, this, type)); + return; + } + + if (!web_contents()) + return; + + CefRenderWidgetHostViewOSR* view = + static_cast( + web_contents()->GetRenderViewHost()->GetView()); + if (view) + view->Invalidate(type); +} + void CefBrowserHostImpl::SendKeyEvent(const CefKeyEvent& event) { if (!CEF_CURRENTLY_ON_UIT()) { CEF_POST_TASK(CEF_UIT, @@ -866,9 +1000,20 @@ void CefBrowserHostImpl::SendKeyEvent(const CefKeyEvent& event) { content::NativeWebKeyboardEvent web_event; PlatformTranslateKeyEvent(web_event, event); - content::RenderWidgetHost* widget = web_contents()->GetRenderViewHost(); - if (widget) - widget->ForwardKeyboardEvent(web_event); + if (!IsWindowless()) { + content::RenderWidgetHost* widget = web_contents()->GetRenderViewHost(); + if (widget) + widget->ForwardKeyboardEvent(web_event); + } else { + if (!web_contents()) + return; + + CefRenderWidgetHostViewOSR* view = + static_cast( + web_contents()->GetRenderViewHost()->GetView()); + if (view) + view->SendKeyEvent(web_event); + } } void CefBrowserHostImpl::SendMouseClickEvent(const CefMouseEvent& event, @@ -913,9 +1058,20 @@ void CefBrowserHostImpl::SendMouseWheelEvent(const CefMouseEvent& event, blink::WebMouseWheelEvent web_event; PlatformTranslateWheelEvent(web_event, event, deltaX, deltaY); - content::RenderWidgetHost* widget = web_contents()->GetRenderViewHost(); - if (widget) - widget->ForwardWheelEvent(web_event); + if (!IsWindowless()) { + content::RenderWidgetHost* widget = web_contents()->GetRenderViewHost(); + if (widget) + widget->ForwardWheelEvent(web_event); + } else { + if (!web_contents()) + return; + + CefRenderWidgetHostViewOSR* view = + static_cast( + web_contents()->GetRenderViewHost()->GetView()); + if (view) + view->SendMouseWheelEvent(web_event); + } } int CefBrowserHostImpl::TranslateModifiers(uint32 cef_modifiers) { @@ -949,9 +1105,20 @@ int CefBrowserHostImpl::TranslateModifiers(uint32 cef_modifiers) { } void CefBrowserHostImpl::SendMouseEvent(const blink::WebMouseEvent& event) { - content::RenderWidgetHost* widget = web_contents()->GetRenderViewHost(); - if (widget) - widget->ForwardMouseEvent(event); + if (!IsWindowless()) { + content::RenderWidgetHost* widget = web_contents()->GetRenderViewHost(); + if (widget) + widget->ForwardMouseEvent(event); + } else { + if (!web_contents()) + return; + + CefRenderWidgetHostViewOSR* view = + static_cast( + web_contents()->GetRenderViewHost()->GetView()); + if (view) + view->SendMouseEvent(event); + } } void CefBrowserHostImpl::SendFocusEvent(bool setFocus) { @@ -961,19 +1128,17 @@ void CefBrowserHostImpl::SendFocusEvent(bool setFocus) { return; } - if (!web_contents()) - return; - - content::RenderWidgetHostImpl* widget = - content::RenderWidgetHostImpl::From(web_contents()->GetRenderViewHost()); - if (!widget) - return; - if (setFocus) { - widget->GotFocus(); - widget->SetActive(true); + if (!IsWindowless()) { + SetFocus(setFocus); } else { - widget->SetActive(false); - widget->Blur(); + if (!web_contents()) + return; + + CefRenderWidgetHostViewOSR* view = + static_cast( + web_contents()->GetRenderViewHost()->GetView()); + if (view) + view->SendFocusEvent(setFocus); } } @@ -989,9 +1154,8 @@ void CefBrowserHostImpl::SendCaptureLostEvent() { content::RenderWidgetHostImpl* widget = content::RenderWidgetHostImpl::From(web_contents()->GetRenderViewHost()); - if (!widget) - return; - widget->LostCapture(); + if (widget) + widget->LostCapture(); } // CefBrowser methods. @@ -1180,6 +1344,14 @@ bool CefBrowserHostImpl::SendProcessMessage( // CefBrowserHostImpl public methods. // ----------------------------------------------------------------------------- +bool CefBrowserHostImpl::IsWindowless() const { + return window_info_.windowless_rendering_enabled ? true : false; +} + +bool CefBrowserHostImpl::IsTransparent() const { + return window_info_.transparent_painting_enabled ? true : false; +} + void CefBrowserHostImpl::WindowDestroyed() { CEF_REQUIRE_UIT(); DCHECK(!window_destroyed_); @@ -1234,6 +1406,16 @@ gfx::NativeView CefBrowserHostImpl::GetContentView() const { #endif } +void CefBrowserHostImpl::CancelContextMenu() { +#if defined(OS_LINUX) && defined(USE_AURA) + CEF_REQUIRE_UIT(); + // Special case for dismissing views-based context menus on Linux Aura + // when using windowless rendering. + if (IsWindowless() && menu_creator_) + menu_creator_->CancelContextMenu(); +#endif +} + content::WebContents* CefBrowserHostImpl::GetWebContents() const { CEF_REQUIRE_UIT(); return web_contents_.get(); @@ -1533,6 +1715,208 @@ void CefBrowserHostImpl::RunFileChooser( callback)); } +#if !defined(OS_MACOSX) +CefTextInputContext CefBrowserHostImpl::GetNSTextInputContext() { + NOTREACHED(); + return NULL; +} + +void CefBrowserHostImpl::HandleKeyEventBeforeTextInputClient( + CefEventHandle keyEvent) { + NOTREACHED(); +} + +void CefBrowserHostImpl::HandleKeyEventAfterTextInputClient( + CefEventHandle keyEvent) { + NOTREACHED(); +} +#endif // !defined(OS_MACOSX) + +void CefBrowserHostImpl::DragTargetDragEnter(CefRefPtr drag_data, + const CefMouseEvent& event, + CefBrowserHost::DragOperationsMask allowed_ops) { + if (!CEF_CURRENTLY_ON_UIT()) { + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefBrowserHostImpl::DragTargetDragEnter, this, drag_data, + event, allowed_ops)); + return; + } + + if (!drag_data.get()) { + NOTREACHED(); + return; + } + + if (!IsWindowless()) { + NOTREACHED() << "Window rendering is not disabled"; + return; + } + + content::RenderViewHost* rvh = + web_contents() ? web_contents()->GetRenderViewHost() : NULL; + if (!rvh) + return; + + int screenX, screenY; + + if (!client_->GetRenderHandler()->GetScreenPoint( + this, event.x, event.y, screenX, screenY)) { + screenX = event.x; + screenY = event.y; + } + + CefDragDataImpl* data_impl = static_cast(drag_data.get()); + CefDragDataImpl::AutoLock lock_scope(data_impl); + const content::DropData& drop_data = data_impl->drop_data(); + gfx::Point client_pt(event.x, event.y); + gfx::Point screen_pt(screenX, screenY); + blink::WebDragOperationsMask ops = + static_cast(allowed_ops); + int modifiers = CefBrowserHostImpl::TranslateModifiers(event.modifiers); + + rvh->DragTargetDragEnter(drop_data, client_pt, screen_pt, ops, modifiers); +} + +void CefBrowserHostImpl::DragTargetDragOver(const CefMouseEvent& event, + CefBrowserHost::DragOperationsMask allowed_ops) { + if (!CEF_CURRENTLY_ON_UIT()) { + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefBrowserHostImpl::DragTargetDragOver, this, event, + allowed_ops)); + return; + } + + if (!IsWindowless()) { + NOTREACHED() << "Window rendering is not disabled"; + return; + } + + content::RenderViewHost* rvh = + web_contents() ? web_contents()->GetRenderViewHost() : NULL; + if (!rvh) + return; + + int screenX, screenY; + + if (!client_->GetRenderHandler()->GetScreenPoint( + this, event.x, event.y, screenX, screenY)) { + screenX = event.x; + screenY = event.y; + } + + gfx::Point client_pt(event.x, event.y); + gfx::Point screen_pt(screenX, screenY); + blink::WebDragOperationsMask ops = + static_cast(allowed_ops); + int modifiers = CefBrowserHostImpl::TranslateModifiers(event.modifiers); + + rvh->DragTargetDragOver(client_pt, screen_pt, ops, modifiers); +} + +void CefBrowserHostImpl::DragTargetDragLeave() { + if (!CEF_CURRENTLY_ON_UIT()) { + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefBrowserHostImpl::DragTargetDragLeave, this)); + return; + } + + if (!IsWindowless()) { + NOTREACHED() << "Window rendering is not disabled"; + return; + } + + content::RenderViewHost* rvh = + web_contents() ? web_contents()->GetRenderViewHost() : NULL; + if (!rvh) + return; + + rvh->DragTargetDragLeave(); +} + +void CefBrowserHostImpl::DragTargetDrop(const CefMouseEvent& event) { + if (!CEF_CURRENTLY_ON_UIT()) { + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefBrowserHostImpl::DragTargetDrop, this, event)); + return; + } + + if (!IsWindowless()) { + NOTREACHED() << "Window rendering is not disabled"; + return; + } + + content::RenderViewHost* rvh = + web_contents() ? web_contents()->GetRenderViewHost() : NULL; + if (!rvh) + return; + + int screenX, screenY; + + if (!client_->GetRenderHandler()->GetScreenPoint( + this, event.x, event.y, screenX, screenY)) { + screenX = event.x; + screenY = event.y; + } + + gfx::Point client_pt(event.x, event.y); + gfx::Point screen_pt(screenX, screenY); + int modifiers = CefBrowserHostImpl::TranslateModifiers(event.modifiers); + + rvh->DragTargetDrop(client_pt, screen_pt, modifiers); +} + +void CefBrowserHostImpl::DragSourceSystemDragEnded() { + if (!CEF_CURRENTLY_ON_UIT()) { + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefBrowserHostImpl::DragSourceSystemDragEnded, this)); + return; + } + + if (!IsWindowless()) { + NOTREACHED() << "Window rendering is not disabled"; + return; + } + + content::RenderViewHost* rvh = + web_contents() ? web_contents()->GetRenderViewHost() : NULL; + if (!rvh) + return; + + rvh->DragSourceSystemDragEnded(); +} + +void CefBrowserHostImpl::DragSourceEndedAt( + int x, int y, CefBrowserHost::DragOperationsMask op) { + if (!CEF_CURRENTLY_ON_UIT()) { + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefBrowserHostImpl::DragSourceEndedAt, this, x, y, op)); + return; + } + + if (!IsWindowless()) { + NOTREACHED() << "Window rendering is not disabled"; + return; + } + + content::RenderViewHost* rvh = + web_contents() ? web_contents()->GetRenderViewHost() : NULL; + if (!rvh) + return; + + int screenX, screenY; + + if (!client_->GetRenderHandler()->GetScreenPoint( + this, x, y, screenX, screenY)) { + screenX = x; + screenY = y; + } + + blink::WebDragOperation drag_op = static_cast(op); + + rvh->DragSourceEndedAt(x, y, screenX, screenY, drag_op); +} + + // content::WebContentsDelegate methods. // ----------------------------------------------------------------------------- @@ -1579,7 +1963,7 @@ void CefBrowserHostImpl::CloseContents(content::WebContents* source) { // If this method is called in response to something other than // WindowDestroyed() ask the user if the browser should close. - if (client_.get() && !window_destroyed_) { + if (client_.get() && (IsWindowless() || !window_destroyed_)) { CefRefPtr handler = client_->GetLifeSpanHandler(); if (handler.get()) { @@ -1591,7 +1975,7 @@ void CefBrowserHostImpl::CloseContents(content::WebContents* source) { if (destruction_state_ != DESTRUCTION_STATE_ACCEPTED) destruction_state_ = DESTRUCTION_STATE_ACCEPTED; - if (!window_destroyed_) { + if (!IsWindowless() && !window_destroyed_) { // A window exists so try to close it using the platform method. Will // result in a call to WindowDestroyed() if/when the window is destroyed // via the platform window destruction mechanism. @@ -1603,8 +1987,10 @@ void CefBrowserHostImpl::CloseContents(content::WebContents* source) { // No window exists. Destroy the browser immediately. DestroyBrowser(); - // Release the reference added in PlatformCreateWindow(). - Release(); + if (!IsWindowless()) { + // Release the reference added in PlatformCreateWindow(). + Release(); + } } } else if (destruction_state_ != DESTRUCTION_STATE_NONE) { destruction_state_ = DESTRUCTION_STATE_NONE; @@ -1722,15 +2108,47 @@ bool CefBrowserHostImpl::CanDragEnter( blink::WebDragOperationsMask mask) { CefRefPtr handler = client_->GetDragHandler(); if (handler.get()) { - CefRefPtr drag_data(new CefDragDataImpl(data)); - if (handler->OnDragEnter(this, drag_data, - static_cast(mask))) { + CefRefPtr drag_data(new CefDragDataImpl(data)); + drag_data->SetReadOnly(true); + if (handler->OnDragEnter( + this, + drag_data.get(), + static_cast(mask))) { return false; } } return true; } +bool CefBrowserHostImpl::ShouldCreateWebContents( + content::WebContents* web_contents, + int route_id, + WindowContainerType window_container_type, + const base::string16& frame_name, + const GURL& target_url, + const std::string& partition_id, + content::SessionStorageNamespace* session_storage_namespace, + content::WebContentsView** view, + content::RenderViewHostDelegateView** delegate_view) { + // In cases where the navigation will occur in a new render process the + // |route_id| value will be MSG_ROUTING_NONE here (because the existing + // renderer will not be able to communicate with the new renderer) and + // OpenURLFromTab will be called after WebContentsCreated. + base::AutoLock lock_scope(pending_popup_info_lock_); + DCHECK(pending_popup_info_.get()); + if (pending_popup_info_->window_info.windowless_rendering_enabled) { + // Use the OSR view instead of the default view. + CefWebContentsViewOSR* view_or = new CefWebContentsViewOSR( + web_contents, + CefContentBrowserClient::Get()->GetWebContentsViewDelegate( + web_contents)); + *view = view_or; + *delegate_view = view_or; + } + + return true; +} + void CefBrowserHostImpl::WebContentsCreated( content::WebContents* source_contents, int opener_render_frame_id, @@ -1827,7 +2245,7 @@ void CefBrowserHostImpl::RequestMediaAccessPermission( // Based on chrome/browser/media/media_stream_devices_controller.cc bool microphone_requested = (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE); - bool webcam_requested = + bool webcam_requested = (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE); if (microphone_requested || webcam_requested) { switch (request.request_type) { @@ -1870,8 +2288,9 @@ void CefBrowserHostImpl::RenderFrameCreated( void CefBrowserHostImpl::RenderFrameDeleted( content::RenderFrameHost* render_frame_host) { - browser_info_->remove_render_frame_id(render_frame_host->GetProcess()->GetID(), - render_frame_host->GetRoutingID()); + browser_info_->remove_render_frame_id( + render_frame_host->GetProcess()->GetID(), + render_frame_host->GetRoutingID()); } void CefBrowserHostImpl::RenderViewCreated( @@ -2208,6 +2627,14 @@ CefBrowserHostImpl::CefBrowserHostImpl( // Make sure RenderViewCreated is called at least one time. RenderViewCreated(web_contents->GetRenderViewHost()); + + if (IsWindowless()) { + CefRenderWidgetHostViewOSR* view = + static_cast( + web_contents->GetRenderViewHost()->GetView()); + if (view) + view->set_browser_impl(this); + } } CefRefPtr CefBrowserHostImpl::GetOrCreateFrame( @@ -2291,7 +2718,7 @@ void CefBrowserHostImpl::DetachAllFrames() { void CefBrowserHostImpl::SetFocusedFrame(int64 frame_id) { CefRefPtr unfocused_frame; CefRefPtr focused_frame; - + { base::AutoLock lock_scope(state_lock_); diff --git a/libcef/browser/browser_host_impl.h b/libcef/browser/browser_host_impl.h index 82b5c9941..3ef44e313 100644 --- a/libcef/browser/browser_host_impl.h +++ b/libcef/browser/browser_host_impl.h @@ -35,6 +35,10 @@ #include "ui/base/cursor/cursor.h" #endif +#if defined(USE_X11) +#include "ui/base/x/x11_util.h" +#endif + namespace content { struct NativeWebKeyboardEvent; } @@ -152,6 +156,11 @@ class CefBrowserHostImpl : public CefBrowserHost, virtual void CloseDevTools() OVERRIDE; virtual void SetMouseCursorChangeDisabled(bool disabled) OVERRIDE; virtual bool IsMouseCursorChangeDisabled() OVERRIDE; + virtual bool IsWindowRenderingDisabled() OVERRIDE; + virtual void WasResized() OVERRIDE; + virtual void WasHidden(bool hidden) OVERRIDE; + virtual void NotifyScreenInfoChanged() OVERRIDE; + virtual void Invalidate(PaintElementType type) OVERRIDE; virtual void SendKeyEvent(const CefKeyEvent& event) OVERRIDE; virtual void SendMouseClickEvent(const CefMouseEvent& event, MouseButtonType type, @@ -162,6 +171,20 @@ class CefBrowserHostImpl : public CefBrowserHost, int deltaX, int deltaY) OVERRIDE; virtual void SendFocusEvent(bool setFocus) OVERRIDE; virtual void SendCaptureLostEvent() OVERRIDE; + virtual CefTextInputContext GetNSTextInputContext() OVERRIDE; + virtual void HandleKeyEventBeforeTextInputClient(CefEventHandle keyEvent) + OVERRIDE; + virtual void HandleKeyEventAfterTextInputClient(CefEventHandle keyEvent) + OVERRIDE; + virtual void DragTargetDragEnter(CefRefPtr drag_data, + const CefMouseEvent& event, + DragOperationsMask allowed_ops); + virtual void DragTargetDragOver(const CefMouseEvent& event, + DragOperationsMask allowed_ops); + virtual void DragTargetDragLeave(); + virtual void DragTargetDrop(const CefMouseEvent& event); + virtual void DragSourceSystemDragEnded(); + virtual void DragSourceEndedAt(int x, int y, DragOperationsMask op); // CefBrowser methods. virtual CefRefPtr GetHost() OVERRIDE; @@ -188,6 +211,11 @@ class CefBrowserHostImpl : public CefBrowserHost, CefProcessId target_process, CefRefPtr message) OVERRIDE; + // Returns true if windowless rendering is enabled. + bool IsWindowless() const; + // Returns true if transparent painting is enabled. + bool IsTransparent() const; + // Called when the OS window hosting the browser is destroyed. void WindowDestroyed(); @@ -195,6 +223,9 @@ class CefBrowserHostImpl : public CefBrowserHost, // native browser window is not longer processing messages. void DestroyBrowser(); + // Cancel display of the context menu, if any. + void CancelContextMenu(); + // Returns the native view for the WebContents. gfx::NativeView GetContentView() const; @@ -340,6 +371,16 @@ class CefBrowserHostImpl : public CefBrowserHost, content::WebContents* source, const content::DropData& data, blink::WebDragOperationsMask operations_allowed) OVERRIDE; + virtual bool ShouldCreateWebContents( + content::WebContents* web_contents, + int route_id, + WindowContainerType window_container_type, + const base::string16& frame_name, + const GURL& target_url, + const std::string& partition_id, + content::SessionStorageNamespace* session_storage_namespace, + content::WebContentsView** view, + content::RenderViewHostDelegateView** delegate_view) OVERRIDE; virtual void WebContentsCreated(content::WebContents* source_contents, int opener_render_frame_id, const base::string16& frame_name, @@ -608,6 +649,7 @@ class CefBrowserHostImpl : public CefBrowserHost, #endif // defined(USE_AURA) #if defined(USE_X11) CefWindowX11* window_x11_; + scoped_ptr invisible_cursor_; #endif // defined(USE_X11) IMPLEMENT_REFCOUNTING(CefBrowserHostImpl); diff --git a/libcef/browser/browser_host_impl_linux.cc b/libcef/browser/browser_host_impl_linux.cc index 87bd8fa02..f3135ab19 100644 --- a/libcef/browser/browser_host_impl_linux.cc +++ b/libcef/browser/browser_host_impl_linux.cc @@ -6,6 +6,7 @@ #include "libcef/browser/browser_host_impl.h" #include +#include #include "libcef/browser/context.h" #include "libcef/browser/window_delegate_view.h" @@ -29,8 +30,120 @@ long GetSystemUptime() { return 0; } +// Based on ui/base/cursor/cursor_loader_x11.cc. + +using blink::WebCursorInfo; + +int ToCursorID(WebCursorInfo::Type type) { + switch (type) { + case WebCursorInfo::TypePointer: + return XC_left_ptr; + case WebCursorInfo::TypeCross: + return XC_crosshair; + case WebCursorInfo::TypeHand: + return XC_hand2; + case WebCursorInfo::TypeIBeam: + return XC_xterm; + case WebCursorInfo::TypeWait: + return XC_watch; + case WebCursorInfo::TypeHelp: + return XC_question_arrow; + case WebCursorInfo::TypeEastResize: + return XC_right_side; + case WebCursorInfo::TypeNorthResize: + return XC_top_side; + case WebCursorInfo::TypeNorthEastResize: + return XC_top_right_corner; + case WebCursorInfo::TypeNorthWestResize: + return XC_top_left_corner; + case WebCursorInfo::TypeSouthResize: + return XC_bottom_side; + case WebCursorInfo::TypeSouthEastResize: + return XC_bottom_right_corner; + case WebCursorInfo::TypeSouthWestResize: + return XC_bottom_left_corner; + case WebCursorInfo::TypeWestResize: + return XC_left_side; + case WebCursorInfo::TypeNorthSouthResize: + return XC_sb_v_double_arrow; + case WebCursorInfo::TypeEastWestResize: + return XC_sb_h_double_arrow; + case WebCursorInfo::TypeNorthEastSouthWestResize: + return XC_left_ptr; + case WebCursorInfo::TypeNorthWestSouthEastResize: + return XC_left_ptr; + case WebCursorInfo::TypeColumnResize: + return XC_sb_h_double_arrow; + case WebCursorInfo::TypeRowResize: + return XC_sb_v_double_arrow; + case WebCursorInfo::TypeMiddlePanning: + return XC_fleur; + case WebCursorInfo::TypeEastPanning: + return XC_sb_right_arrow; + case WebCursorInfo::TypeNorthPanning: + return XC_sb_up_arrow; + case WebCursorInfo::TypeNorthEastPanning: + return XC_top_right_corner; + case WebCursorInfo::TypeNorthWestPanning: + return XC_top_left_corner; + case WebCursorInfo::TypeSouthPanning: + return XC_sb_down_arrow; + case WebCursorInfo::TypeSouthEastPanning: + return XC_bottom_right_corner; + case WebCursorInfo::TypeSouthWestPanning: + return XC_bottom_left_corner; + case WebCursorInfo::TypeWestPanning: + return XC_sb_left_arrow; + case WebCursorInfo::TypeMove: + return XC_fleur; + case WebCursorInfo::TypeVerticalText: + return XC_left_ptr; + case WebCursorInfo::TypeCell: + return XC_left_ptr; + case WebCursorInfo::TypeContextMenu: + return XC_left_ptr; + case WebCursorInfo::TypeAlias: + return XC_left_ptr; + case WebCursorInfo::TypeProgress: + return XC_left_ptr; + case WebCursorInfo::TypeNoDrop: + return XC_left_ptr; + case WebCursorInfo::TypeCopy: + return XC_left_ptr; + case WebCursorInfo::TypeNotAllowed: + return XC_left_ptr; + case WebCursorInfo::TypeZoomIn: + return XC_left_ptr; + case WebCursorInfo::TypeZoomOut: + return XC_left_ptr; + case WebCursorInfo::TypeGrab: + return XC_left_ptr; + case WebCursorInfo::TypeGrabbing: + return XC_left_ptr; + case WebCursorInfo::TypeCustom: + case WebCursorInfo::TypeNone: + break; + } + NOTREACHED(); + return 0; +} + } // namespace +ui::PlatformCursor CefBrowserHostImpl::GetPlatformCursor( + blink::WebCursorInfo::Type type) { + if (type == WebCursorInfo::TypeNone) { + if (!invisible_cursor_) { + invisible_cursor_.reset( + new ui::XScopedCursor(ui::CreateInvisibleCursor(), + gfx::GetXDisplay())); + } + return invisible_cursor_->get(); + } else { + return ui::GetXCursor(ToCursorID(type)); + } +} + bool CefBrowserHostImpl::PlatformCreateWindow() { DCHECK(!window_x11_); DCHECK(!window_widget_); @@ -119,7 +232,7 @@ void CefBrowserHostImpl::PlatformSetFocus(bool focus) { } CefWindowHandle CefBrowserHostImpl::PlatformGetWindowHandle() { - return window_info_.window; + return IsWindowless() ? window_info_.parent_window : window_info_.window; } bool CefBrowserHostImpl::PlatformViewText(const std::string& text) { @@ -175,7 +288,32 @@ void CefBrowserHostImpl::PlatformHandleExternalProtocol(const GURL& url) { void CefBrowserHostImpl::PlatformTranslateKeyEvent( content::NativeWebKeyboardEvent& result, const CefKeyEvent& key_event) { - NOTIMPLEMENTED(); + result.timeStampSeconds = GetSystemUptime(); + + result.windowsKeyCode = key_event.windows_key_code; + result.nativeKeyCode = key_event.native_key_code; + result.isSystemKey = key_event.is_system_key ? 1 : 0; + switch (key_event.type) { + case KEYEVENT_RAWKEYDOWN: + case KEYEVENT_KEYDOWN: + result.type = blink::WebInputEvent::RawKeyDown; + break; + case KEYEVENT_KEYUP: + result.type = blink::WebInputEvent::KeyUp; + break; + case KEYEVENT_CHAR: + result.type = blink::WebInputEvent::Char; + break; + default: + NOTREACHED(); + } + + result.text[0] = key_event.character; + result.unmodifiedText[0] = key_event.unmodified_character; + + result.setKeyIdentifierFromWindowsKeyCode(); + + result.modifiers |= TranslateModifiers(key_event.modifiers); } void CefBrowserHostImpl::PlatformTranslateClickEvent( @@ -274,7 +412,14 @@ void CefBrowserHostImpl::PlatformTranslateMouseEvent( result.globalX = result.x; result.globalY = result.y; - // TODO(linux): Convert global{X,Y} to screen coordinates. + if (IsWindowless()) { + GetClient()->GetRenderHandler()->GetScreenPoint( + GetBrowser(), + result.x, result.y, + result.globalX, result.globalY); + } else { + // TODO(linux): Convert global{X,Y} to screen coordinates. + } // modifiers result.modifiers |= TranslateModifiers(mouse_event.modifiers); diff --git a/libcef/browser/browser_host_impl_mac.mm b/libcef/browser/browser_host_impl_mac.mm index 346ea88c1..8426a1125 100644 --- a/libcef/browser/browser_host_impl_mac.mm +++ b/libcef/browser/browser_host_impl_mac.mm @@ -8,6 +8,8 @@ #import #import +#include "libcef/browser/render_widget_host_view_osr.h" +#include "libcef/browser/text_input_client_osr_mac.h" #include "libcef/browser/thread_util.h" #include "base/file_util.h" @@ -286,6 +288,59 @@ bool CefBrowserHostImpl::PlatformViewText(const std::string& text) { return false; } +CefTextInputContext CefBrowserHostImpl::GetNSTextInputContext() { + if (!IsWindowless()) { + NOTREACHED() << "Window rendering is not disabled"; + return NULL; + } + + if (!CEF_CURRENTLY_ON_UIT()) { + NOTREACHED() << "Called on invalid thread"; + return NULL; + } + + CefRenderWidgetHostViewOSR* rwhv = static_cast( + GetWebContents()->GetRenderWidgetHostView()); + + return rwhv->GetNSTextInputContext(); +} + +void CefBrowserHostImpl::HandleKeyEventBeforeTextInputClient( + CefEventHandle keyEvent) { + if (!IsWindowless()) { + NOTREACHED() << "Window rendering is not disabled"; + return; + } + + if (!CEF_CURRENTLY_ON_UIT()) { + NOTREACHED() << "Called on invalid thread"; + return; + } + + CefRenderWidgetHostViewOSR* rwhv = static_cast( + GetWebContents()->GetRenderWidgetHostView()); + + rwhv->HandleKeyEventBeforeTextInputClient(keyEvent); +} + +void CefBrowserHostImpl::HandleKeyEventAfterTextInputClient( + CefEventHandle keyEvent) { + if (!IsWindowless()) { + NOTREACHED() << "Window rendering is not disabled"; + return; + } + + if (!CEF_CURRENTLY_ON_UIT()) { + NOTREACHED() << "Called on invalid thread"; + return; + } + + CefRenderWidgetHostViewOSR* rwhv = static_cast( + GetWebContents()->GetRenderWidgetHostView()); + + rwhv->HandleKeyEventAfterTextInputClient(keyEvent); +} + bool CefBrowserHostImpl::PlatformCreateWindow() { base::mac::ScopedNSAutoreleasePool autorelease_pool; @@ -382,7 +437,7 @@ void CefBrowserHostImpl::PlatformSetFocus(bool focus) { web_contents_->GetRenderWidgetHostView()) { view->SetActive(focus); - if (focus) { + if (focus && !IsWindowless()) { // Give keyboard focus to the native view. NSView* view = web_contents_->GetContentNativeView(); DCHECK([view canBecomeKeyView]); @@ -402,7 +457,7 @@ void CefBrowserHostImpl::PlatformSetWindowVisibility(bool visible) { } CefWindowHandle CefBrowserHostImpl::PlatformGetWindowHandle() { - return window_info_.view; + return IsWindowless() ? window_info_.parent_view : window_info_.view; } void CefBrowserHostImpl::PlatformHandleKeyboardEvent( @@ -616,14 +671,21 @@ void CefBrowserHostImpl::PlatformTranslateMouseEvent( result.globalX = result.x; result.globalY = result.y; - NSView* view = window_info_.parent_view; - if (view) { - NSRect bounds = [view bounds]; - NSPoint view_pt = {result.x, bounds.size.height - result.y}; - NSPoint window_pt = [view convertPoint:view_pt toView:nil]; - NSPoint screen_pt = [[view window] convertBaseToScreen:window_pt]; - result.globalX = screen_pt.x; - result.globalY = screen_pt.y; + if (IsWindowless()) { + GetClient()->GetRenderHandler()->GetScreenPoint( + GetBrowser(), + result.x, result.y, + result.globalX, result.globalY); + } else { + NSView* view = window_info_.parent_view; + if (view) { + NSRect bounds = [view bounds]; + NSPoint view_pt = {result.x, bounds.size.height - result.y}; + NSPoint window_pt = [view convertPoint:view_pt toView:nil]; + NSPoint screen_pt = [[view window] convertBaseToScreen:window_pt]; + result.globalX = screen_pt.x; + result.globalY = screen_pt.y; + } } // modifiers diff --git a/libcef/browser/browser_host_impl_win.cc b/libcef/browser/browser_host_impl_win.cc index f299a114e..ee228a486 100644 --- a/libcef/browser/browser_host_impl_win.cc +++ b/libcef/browser/browser_host_impl_win.cc @@ -716,7 +716,7 @@ void CefBrowserHostImpl::PlatformSetFocus(bool focus) { } CefWindowHandle CefBrowserHostImpl::PlatformGetWindowHandle() { - return window_info_.window; + return IsWindowless() ? window_info_.parent_window : window_info_.window; } bool CefBrowserHostImpl::PlatformViewText(const std::string& text) { @@ -922,11 +922,17 @@ void CefBrowserHostImpl::PlatformTranslateMouseEvent( result.globalX = result.x; result.globalY = result.y; - // global position - POINT globalPoint = { result.x, result.y }; - ClientToScreen(GetWindowHandle(), &globalPoint); - result.globalX = globalPoint.x; - result.globalY = globalPoint.y; + if (IsWindowless()) { + GetClient()->GetRenderHandler()->GetScreenPoint( + GetBrowser(), + result.x, result.y, + result.globalX, result.globalY); + } else { + POINT globalPoint = { result.x, result.y }; + ClientToScreen(GetWindowHandle(), &globalPoint); + result.globalX = globalPoint.x; + result.globalY = globalPoint.y; + } // modifiers result.modifiers |= TranslateModifiers(mouse_event.modifiers); diff --git a/libcef/browser/browser_info.cc b/libcef/browser/browser_info.cc index 24f6d552e..6ca13c4cd 100644 --- a/libcef/browser/browser_info.cc +++ b/libcef/browser/browser_info.cc @@ -7,13 +7,18 @@ CefBrowserInfo::CefBrowserInfo(int browser_id, bool is_popup) : browser_id_(browser_id), - is_popup_(is_popup) { + is_popup_(is_popup), + is_windowless_(false) { DCHECK_GT(browser_id, 0); } CefBrowserInfo::~CefBrowserInfo() { } +void CefBrowserInfo::set_windowless(bool windowless) { + is_windowless_ = windowless; +} + void CefBrowserInfo::add_render_view_id( int render_process_id, int render_routing_id) { add_render_id(&render_view_id_set_, render_process_id, render_routing_id); diff --git a/libcef/browser/browser_info.h b/libcef/browser/browser_info.h index 22755c197..b84cbbc25 100644 --- a/libcef/browser/browser_info.h +++ b/libcef/browser/browser_info.h @@ -24,6 +24,9 @@ class CefBrowserInfo : public base::RefCountedThreadSafe { int browser_id() const { return browser_id_; }; bool is_popup() const { return is_popup_; } + bool is_windowless() const { return is_windowless_; } + + void set_windowless(bool windowless); // Adds an ID pair if it doesn't already exist. void add_render_view_id(int render_process_id, int render_routing_id); @@ -55,6 +58,7 @@ class CefBrowserInfo : public base::RefCountedThreadSafe { int browser_id_; bool is_popup_; + bool is_windowless_; base::Lock lock_; diff --git a/libcef/browser/browser_message_filter.cc b/libcef/browser/browser_message_filter.cc index d31272121..1cc3356e8 100644 --- a/libcef/browser/browser_message_filter.cc +++ b/libcef/browser/browser_message_filter.cc @@ -91,6 +91,7 @@ void CefBrowserMessageFilter::OnGetNewBrowserInfo( render_frame_routing_id); params->browser_id = info->browser_id(); params->is_popup = info->is_popup(); + params->is_windowless = info->is_windowless(); } void CefBrowserMessageFilter::OnCreateWindow( diff --git a/libcef/browser/content_browser_client.cc b/libcef/browser/content_browser_client.cc index 34e9c0726..27eb73c69 100644 --- a/libcef/browser/content_browser_client.cc +++ b/libcef/browser/content_browser_client.cc @@ -74,6 +74,8 @@ class CefAccessTokenStore : public content::AccessTokenStore { private: AccessTokenSet access_token_set_; + + DISALLOW_COPY_AND_ASSIGN(CefAccessTokenStore); }; class CefQuotaCallbackImpl : public CefQuotaCallback { @@ -134,6 +136,7 @@ class CefQuotaCallbackImpl : public CefQuotaCallback { content::QuotaPermissionContext::PermissionCallback callback_; IMPLEMENT_REFCOUNTING(CefQuotaCallbackImpl); + DISALLOW_COPY_AND_ASSIGN(CefQuotaCallbackImpl); }; class CefAllowCertificateErrorCallbackImpl @@ -164,6 +167,7 @@ class CefAllowCertificateErrorCallbackImpl base::Callback callback_; IMPLEMENT_REFCOUNTING(CefAllowCertificateErrorCallbackImpl); + DISALLOW_COPY_AND_ASSIGN(CefAllowCertificateErrorCallbackImpl); }; class CefQuotaPermissionContext : public content::QuotaPermissionContext { @@ -214,6 +218,8 @@ class CefQuotaPermissionContext : public content::QuotaPermissionContext { private: virtual ~CefQuotaPermissionContext() { } + + DISALLOW_COPY_AND_ASSIGN(CefQuotaPermissionContext); }; class CefPluginServiceFilter : public content::PluginServiceFilter { @@ -255,6 +261,8 @@ class CefPluginServiceFilter : public content::PluginServiceFilter { const base::FilePath& path) OVERRIDE { return true; } + + DISALLOW_COPY_AND_ASSIGN(CefPluginServiceFilter); }; void TranslatePopupFeatures(const blink::WebWindowFeatures& webKitFeatures, diff --git a/libcef/browser/menu_creator.cc b/libcef/browser/menu_creator.cc index a0b21c68a..fdfe1799a 100644 --- a/libcef/browser/menu_creator.cc +++ b/libcef/browser/menu_creator.cc @@ -103,6 +103,11 @@ bool CefMenuCreator::CreateContextMenu( return runner_->RunContextMenu(this); } +void CefMenuCreator::CancelContextMenu() { + if (IsShowingContextMenu()) + runner_->CancelContextMenu(); +} + bool CefMenuCreator::CreateRunner() { if (!runner_.get()) { // Create the menu runner. diff --git a/libcef/browser/menu_creator.h b/libcef/browser/menu_creator.h index 3ca124102..2955fd439 100644 --- a/libcef/browser/menu_creator.h +++ b/libcef/browser/menu_creator.h @@ -24,6 +24,7 @@ class CefMenuCreator : public CefMenuModelImpl::Delegate { public: virtual ~Runner() {} virtual bool RunContextMenu(CefMenuCreator* manager) =0; + virtual void CancelContextMenu() {} virtual bool FormatLabel(base::string16& label) { return false; } }; @@ -35,6 +36,7 @@ class CefMenuCreator : public CefMenuModelImpl::Delegate { // Create the context menu. bool CreateContextMenu(const content::ContextMenuParams& params); + void CancelContextMenu(); CefBrowserHostImpl* browser() { return browser_; } ui::MenuModel* model() { return model_->model(); } diff --git a/libcef/browser/menu_creator_runner_linux.cc b/libcef/browser/menu_creator_runner_linux.cc index ec51feffd..6505d8789 100644 --- a/libcef/browser/menu_creator_runner_linux.cc +++ b/libcef/browser/menu_creator_runner_linux.cc @@ -24,14 +24,34 @@ CefMenuCreatorRunnerLinux::~CefMenuCreatorRunnerLinux() { bool CefMenuCreatorRunnerLinux::RunContextMenu(CefMenuCreator* manager) { menu_.reset(new views::MenuRunner(manager->model())); - // We can't use aura::Window::GetBoundsInScreen on Linux because it will - // return bounds from DesktopWindowTreeHostX11 which in our case is relative - // to the parent window instead of the root window (screen). - const gfx::Rect& bounds_in_screen = - manager->browser()->window_x11()->GetBoundsInScreen(); - gfx::Point screen_point = - gfx::Point(bounds_in_screen.x() + manager->params().x, - bounds_in_screen.y() + manager->params().y); + gfx::Point screen_point; + + if (manager->browser()->IsWindowless()) { + CefRefPtr client = manager->browser()->GetClient(); + if (!client.get()) + return false; + + CefRefPtr handler = client->GetRenderHandler(); + if (!handler.get()) + return false; + + int screenX = 0, screenY = 0; + if (!handler->GetScreenPoint(manager->browser(), + manager->params().x, manager->params().y, + screenX, screenY)) { + return false; + } + + screen_point = gfx::Point(screenX, screenY); + } else { + // We can't use aura::Window::GetBoundsInScreen on Linux because it will + // return bounds from DesktopWindowTreeHostX11 which in our case is relative + // to the parent window instead of the root window (screen). + const gfx::Rect& bounds_in_screen = + manager->browser()->window_x11()->GetBoundsInScreen(); + screen_point = gfx::Point(bounds_in_screen.x() + manager->params().x, + bounds_in_screen.y() + manager->params().y); + } views::MenuRunner::RunResult result = menu_->RunMenuAt(manager->browser()->window_widget(), @@ -44,6 +64,11 @@ bool CefMenuCreatorRunnerLinux::RunContextMenu(CefMenuCreator* manager) { return true; } +void CefMenuCreatorRunnerLinux::CancelContextMenu() { + if (menu_) + menu_->Cancel(); +} + bool CefMenuCreatorRunnerLinux::FormatLabel(base::string16& label) { // Remove the accelerator indicator (&) from label strings. const char16 replace[] = {L'&', 0}; diff --git a/libcef/browser/menu_creator_runner_linux.h b/libcef/browser/menu_creator_runner_linux.h index 0af6e9112..eb28c5707 100644 --- a/libcef/browser/menu_creator_runner_linux.h +++ b/libcef/browser/menu_creator_runner_linux.h @@ -18,6 +18,7 @@ class CefMenuCreatorRunnerLinux: public CefMenuCreator::Runner { // CefMemoryManager::Runner methods. virtual bool RunContextMenu(CefMenuCreator* manager) OVERRIDE; + virtual void CancelContextMenu() OVERRIDE; virtual bool FormatLabel(base::string16& label) OVERRIDE; private: diff --git a/libcef/browser/menu_creator_runner_mac.mm b/libcef/browser/menu_creator_runner_mac.mm index 28121c3a5..151d80042 100644 --- a/libcef/browser/menu_creator_runner_mac.mm +++ b/libcef/browser/menu_creator_runner_mac.mm @@ -61,9 +61,33 @@ bool CefMenuCreatorRunnerMac::RunContextMenu(CefMenuCreator* manager) { base::mac::ScopedSendingEvent sendingEventScoper; // Show the menu. Blocks until the menu is dismissed. - [NSMenu popUpContextMenu:[menu_controller_ menu] - withEvent:clickEvent - forView:parent_view]; + if (manager->browser()->IsWindowless()) { + // Showing the menu in OSR is pretty much self contained, only using + // the initialized menu_controller_ in this function, and the scoped + // variables in this block. + int screenX = 0, screenY = 0; + CefRefPtr handler = + manager->browser()->GetClient()->GetRenderHandler(); + if (!handler->GetScreenPoint(manager->browser(), + manager->params().x, manager->params().y, + screenX, screenY)) { + return false; + } + + // Don't show the menu unless there is a parent native window to tie it to + if (!manager->browser()->GetWindowHandle()) + return false; + + NSPoint screen_position = + NSPointFromCGPoint(gfx::Point(screenX, screenY).ToCGPoint()); + [[menu_controller_ menu] popUpMenuPositioningItem:nil + atLocation:screen_position + inView:nil]; + } else { + [NSMenu popUpContextMenu:[menu_controller_ menu] + withEvent:clickEvent + forView:parent_view]; + } } return true; diff --git a/libcef/browser/menu_creator_runner_win.cc b/libcef/browser/menu_creator_runner_win.cc index 65c2d51d5..669e23bf7 100644 --- a/libcef/browser/menu_creator_runner_win.cc +++ b/libcef/browser/menu_creator_runner_win.cc @@ -24,10 +24,29 @@ bool CefMenuCreatorRunnerWin::RunContextMenu(CefMenuCreator* manager) { gfx::Point screen_point; - aura::Window* window = manager->browser()->GetContentView(); - const gfx::Rect& bounds_in_screen = window->GetBoundsInScreen(); - screen_point = gfx::Point(bounds_in_screen.x() + manager->params().x, - bounds_in_screen.y() + manager->params().y); + if (manager->browser()->IsWindowless()) { + CefRefPtr client = manager->browser()->GetClient(); + if (!client.get()) + return false; + + CefRefPtr handler = client->GetRenderHandler(); + if (!handler.get()) + return false; + + int screenX = 0, screenY = 0; + if (!handler->GetScreenPoint(manager->browser(), + manager->params().x, manager->params().y, + screenX, screenY)) { + return false; + } + + screen_point = gfx::Point(screenX, screenY); + } else { + aura::Window* window = manager->browser()->GetContentView(); + const gfx::Rect& bounds_in_screen = window->GetBoundsInScreen(); + screen_point = gfx::Point(bounds_in_screen.x() + manager->params().x, + bounds_in_screen.y() + manager->params().y); + } // Show the menu. Blocks until the menu is dismissed. menu_->RunMenuAt(screen_point, views::Menu2::ALIGN_TOPLEFT); diff --git a/libcef/browser/render_widget_host_view_osr.cc b/libcef/browser/render_widget_host_view_osr.cc new file mode 100644 index 000000000..6c08a261b --- /dev/null +++ b/libcef/browser/render_widget_host_view_osr.cc @@ -0,0 +1,1094 @@ +// Copyright (c) 2014 The Chromium Embedded Framework Authors. +// Portions 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 "libcef/browser/render_widget_host_view_osr.h" +#include "libcef/browser/browser_host_impl.h" +#include "libcef/browser/thread_util.h" + +#include "base/callback_helpers.h" +#include "cc/output/copy_output_request.h" +#include "content/browser/compositor/image_transport_factory.h" +#include "content/browser/compositor/resize_lock.h" +#include "content/browser/renderer_host/dip_util.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" +#include "content/common/gpu/client/gl_helper.h" +#include "content/public/browser/context_factory.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_widget_host_view_frame_subscriber.h" +#include "third_party/WebKit/public/platform/WebScreenInfo.h" +#include "ui/gfx/geometry/size_conversions.h" +#include "ui/gfx/image/image_skia_operations.h" + +namespace { + +const float kDefaultScaleFactor = 1.0; + +// The rate at which new calls to OnPaint will be generated. +const int kDefaultFrameRate = 30; +const int kMaximumFrameRate = 60; + +// The maximum number of retry counts if frame capture fails. +const int kFrameRetryLimit = 2; + +// When accelerated compositing is enabled and a widget resize is pending, +// we delay further resizes of the UI. The following constant is the maximum +// length of time that we should delay further UI resizes while waiting for a +// resized frame from a renderer. +const int kResizeLockTimeoutMs = 67; + +static blink::WebScreenInfo webScreenInfoFrom(const CefScreenInfo& src) { + blink::WebScreenInfo webScreenInfo; + webScreenInfo.deviceScaleFactor = src.device_scale_factor; + webScreenInfo.depth = src.depth; + webScreenInfo.depthPerComponent = src.depth_per_component; + webScreenInfo.isMonochrome = src.is_monochrome ? true : false; + webScreenInfo.rect = blink::WebRect(src.rect.x, src.rect.y, + src.rect.width, src.rect.height); + webScreenInfo.availableRect = blink::WebRect(src.available_rect.x, + src.available_rect.y, + src.available_rect.width, + src.available_rect.height); + + return webScreenInfo; +} + +// Root layer passed to the ui::Compositor. +class CefRootLayer : public ui::Layer, public ui::LayerDelegate { + public: + CefRootLayer() + : Layer(ui::LAYER_TEXTURED) { + set_delegate(this); + } + + virtual ~CefRootLayer() { } + + // Overridden from LayerDelegate: + virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE { + } + + virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE { + } + + virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE { + return base::Closure(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(CefRootLayer); +}; + +// Used to prevent further resizes while a resize is pending. +class CefResizeLock : public content::ResizeLock { + public: + CefResizeLock(CefRenderWidgetHostViewOSR* host, + const gfx::Size new_size, + bool defer_compositor_lock, + double timeout) + : ResizeLock(new_size, defer_compositor_lock), + host_(host), + cancelled_(false), + weak_ptr_factory_(this) { + DCHECK(host_); + host_->HoldResize(); + + CEF_POST_DELAYED_TASK( + CEF_UIT, + base::Bind(&CefResizeLock::CancelLock, + weak_ptr_factory_.GetWeakPtr()), + timeout); + } + + virtual ~CefResizeLock() { + CancelLock(); + } + + virtual bool GrabDeferredLock() OVERRIDE { + return ResizeLock::GrabDeferredLock(); + } + + virtual void UnlockCompositor() OVERRIDE { + ResizeLock::UnlockCompositor(); + compositor_lock_ = NULL; + } + + protected: + virtual void LockCompositor() OVERRIDE { + ResizeLock::LockCompositor(); + compositor_lock_ = host_->compositor()->GetCompositorLock(); + } + + void CancelLock() { + if (cancelled_) + return; + cancelled_ = true; + UnlockCompositor(); + host_->ReleaseResize(); + } + + private: + CefRenderWidgetHostViewOSR* host_; + scoped_refptr compositor_lock_; + bool cancelled_; + base::WeakPtrFactory weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(CefResizeLock); +}; + +} // namespace + +CefRenderWidgetHostViewOSR::CefRenderWidgetHostViewOSR( + content::RenderWidgetHost* widget) + : delegated_frame_host_(new content::DelegatedFrameHost(this)), + compositor_widget_(gfx::kNullAcceleratedWidget), + frame_rate_threshold_ms_(1000 / kDefaultFrameRate), + frame_pending_(false), + frame_in_progress_(false), + frame_retry_count_(0), + hold_resize_(false), + pending_resize_(false), + render_widget_host_(content::RenderWidgetHostImpl::From(widget)), + parent_host_view_(NULL), + popup_host_view_(NULL), + is_showing_(false), + is_destroyed_(false), +#if defined(OS_MACOSX) + text_input_context_osr_mac_(NULL), +#endif + weak_ptr_factory_(this) { + DCHECK(render_widget_host_); + render_widget_host_->SetView(this); + + // CefBrowserHostImpl might not be created at this time for popups. + if (render_widget_host_->IsRenderView()) { + browser_impl_ = CefBrowserHostImpl::GetBrowserForHost( + content::RenderViewHost::From(render_widget_host_)); + } + + root_layer_.reset(new CefRootLayer); + + PlatformCreateCompositorWidget(); +#if !defined(OS_MACOSX) + // On OS X the ui::Compositor is created/owned by the platform view. + compositor_.reset( + new ui::Compositor(compositor_widget_, content::GetContextFactory())); +#endif + compositor_->SetRootLayer(root_layer_.get()); + + if (browser_impl_) { + SetFrameRate(); + ResizeRootLayer(); + compositor_->SetScaleAndSize(CurrentDeviceScaleFactor(), + root_layer_->bounds().size()); + } +} + +CefRenderWidgetHostViewOSR::~CefRenderWidgetHostViewOSR() { + delegated_frame_host_.reset(NULL); + compositor_.reset(NULL); + PlatformDestroyCompositorWidget(); + root_layer_.reset(NULL); +} + +void CefRenderWidgetHostViewOSR::InitAsChild(gfx::NativeView parent_view) { +} + +content::RenderWidgetHost* + CefRenderWidgetHostViewOSR::GetRenderWidgetHost() const { + return render_widget_host_; +} + +void CefRenderWidgetHostViewOSR::SetSize(const gfx::Size& size) { +} + +void CefRenderWidgetHostViewOSR::SetBounds(const gfx::Rect& rect) { +} + +gfx::NativeView CefRenderWidgetHostViewOSR::GetNativeView() const { + return gfx::NativeView(); +} + +gfx::NativeViewId CefRenderWidgetHostViewOSR::GetNativeViewId() const { + return gfx::NativeViewId(); +} + +gfx::NativeViewAccessible + CefRenderWidgetHostViewOSR::GetNativeViewAccessible() { + return gfx::NativeViewAccessible(); +} + +ui::TextInputClient* CefRenderWidgetHostViewOSR::GetTextInputClient() { + return NULL; +} + +void CefRenderWidgetHostViewOSR::Focus() { +} + +bool CefRenderWidgetHostViewOSR::HasFocus() const { + return false; +} + +bool CefRenderWidgetHostViewOSR::IsSurfaceAvailableForCopy() const { + return delegated_frame_host_->CanCopyToBitmap(); +} + +void CefRenderWidgetHostViewOSR::Show() { + WasShown(); +} + +void CefRenderWidgetHostViewOSR::Hide() { + WasHidden(); +} + +bool CefRenderWidgetHostViewOSR::IsShowing() { + return is_showing_; +} + +gfx::Rect CefRenderWidgetHostViewOSR::GetViewBounds() const { + if (IsPopupWidget()) + return popup_position_; + + if (!browser_impl_) + return gfx::Rect(); + + CefRect rc; + browser_impl_->GetClient()->GetRenderHandler()->GetViewRect( + browser_impl_.get(), rc); + return gfx::Rect(rc.x, rc.y, rc.width, rc.height); +} + +void CefRenderWidgetHostViewOSR::SetBackgroundOpaque(bool opaque) { + content::RenderWidgetHostViewBase::SetBackgroundOpaque(opaque); + if (render_widget_host_) + render_widget_host_->SetBackgroundOpaque(opaque); +} + +bool CefRenderWidgetHostViewOSR::LockMouse() { + return false; +} + +void CefRenderWidgetHostViewOSR::UnlockMouse() { +} + +void CefRenderWidgetHostViewOSR::OnSwapCompositorFrame( + uint32 output_surface_id, + scoped_ptr frame) { + TRACE_EVENT0("libcef", "CefRenderWidgetHostViewOSR::OnSwapCompositorFrame"); + if (frame->delegated_frame_data) { + delegated_frame_host_->SwapDelegatedFrame( + output_surface_id, + frame->delegated_frame_data.Pass(), + frame->metadata.device_scale_factor, + frame->metadata.latency_info); + + GenerateFrame(true); + return; + } + + if (frame->software_frame_data) { + DLOG(ERROR) << "Unable to use software frame in CEF windowless rendering"; + if (render_widget_host_) + render_widget_host_->GetProcess()->ReceivedBadMessage(); + return; + } +} + +void CefRenderWidgetHostViewOSR::InitAsPopup( + content::RenderWidgetHostView* parent_host_view, + const gfx::Rect& pos) { + parent_host_view_ = static_cast( + parent_host_view); + browser_impl_ = parent_host_view_->browser_impl(); + if (!browser_impl_) + return; + + if (parent_host_view_->popup_host_view_) { + // Cancel the previous popup widget. + parent_host_view_->popup_host_view_->CancelPopupWidget(); + } + + parent_host_view_->set_popup_host_view(this); + browser_impl_->GetClient()->GetRenderHandler()->OnPopupShow( + browser_impl_.get(), true); + + popup_position_ = pos; + + const float scale_factor = CurrentDeviceScaleFactor(); + const gfx::Rect scaled_size = + gfx::ToNearestRect(gfx::ScaleRect(pos, scale_factor)); + + CefRect widget_pos(scaled_size.x(), scaled_size.y(), + scaled_size.width(), scaled_size.height()); + browser_impl_->GetClient()->GetRenderHandler()->OnPopupSize( + browser_impl_.get(), widget_pos); + + SetFrameRate(); + ResizeRootLayer(); + compositor_->SetScaleAndSize(scale_factor, root_layer_->bounds().size()); + + WasShown(); +} + +void CefRenderWidgetHostViewOSR::InitAsFullscreen( + content::RenderWidgetHostView* reference_host_view) { + NOTREACHED() << "Fullscreen widgets are not supported in OSR"; +} + +void CefRenderWidgetHostViewOSR::WasShown() { + if (is_showing_) + return; + + is_showing_ = true; + if (render_widget_host_) + render_widget_host_->WasShown(); + delegated_frame_host_->AddedToWindow(); + delegated_frame_host_->WasShown(); +} + +void CefRenderWidgetHostViewOSR::WasHidden() { + if (!is_showing_) + return; + + if (browser_impl_) + browser_impl_->CancelContextMenu(); + + if (render_widget_host_) + render_widget_host_->WasHidden(); + delegated_frame_host_->WasHidden(); + delegated_frame_host_->RemovingFromWindow(); + is_showing_ = false; +} + +void CefRenderWidgetHostViewOSR::MovePluginWindows( + const std::vector& moves) { +} + +void CefRenderWidgetHostViewOSR::Blur() { +} + +void CefRenderWidgetHostViewOSR::UpdateCursor( + const content::WebCursor& cursor) { + TRACE_EVENT0("libcef", "CefRenderWidgetHostViewOSR::UpdateCursor"); + if (!browser_impl_) + return; + +#if defined(USE_AURA) + content::WebCursor web_cursor = cursor; + + ui::PlatformCursor platform_cursor; + if (web_cursor.IsCustom()) { + // |web_cursor| owns the resulting |platform_cursor|. + platform_cursor = web_cursor.GetPlatformCursor(); + } else { + content::WebCursor::CursorInfo cursor_info; + cursor.GetCursorInfo(&cursor_info); + platform_cursor = browser_impl_->GetPlatformCursor(cursor_info.type); + } + + browser_impl_->GetClient()->GetRenderHandler()->OnCursorChange( + browser_impl_.get(), platform_cursor); +#elif defined(OS_MACOSX) + // |web_cursor| owns the resulting |native_cursor|. + content::WebCursor web_cursor = cursor; + CefCursorHandle native_cursor = web_cursor.GetNativeCursor(); + browser_impl_->GetClient()->GetRenderHandler()->OnCursorChange( + browser_impl_.get(), native_cursor); +#else + // TODO(port): Implement this method to work on other platforms as part of + // off-screen rendering support. + NOTREACHED(); +#endif +} + +void CefRenderWidgetHostViewOSR::SetIsLoading(bool is_loading) { +} + +#if !defined(OS_MACOSX) +void CefRenderWidgetHostViewOSR::TextInputTypeChanged( + ui::TextInputType type, + ui::TextInputMode input_mode, + bool can_compose_inline) { +} + +void CefRenderWidgetHostViewOSR::ImeCancelComposition() { +} +#endif // !defined(OS_MACOSX) + +void CefRenderWidgetHostViewOSR::RenderProcessGone( + base::TerminationStatus status, + int error_code) { + // TODO(OSR): Need to also clear WebContentsViewOSR::view_? + render_widget_host_ = NULL; + parent_host_view_ = NULL; + popup_host_view_ = NULL; +} + +void CefRenderWidgetHostViewOSR::Destroy() { + if (!is_destroyed_) { + is_destroyed_ = true; + + if (IsPopupWidget()) { + CancelPopupWidget(); + } else { + if (popup_host_view_) + popup_host_view_->CancelPopupWidget(); + WasHidden(); + } + } + + delete this; +} + +void CefRenderWidgetHostViewOSR::SetTooltipText( + const base::string16& tooltip_text) { + if (!browser_impl_) + return; + + CefString tooltip(tooltip_text); + CefRefPtr handler = + browser_impl_->GetClient()->GetDisplayHandler(); + if (handler.get()) { + handler->OnTooltip(browser_impl_.get(), tooltip); + } +} + +void CefRenderWidgetHostViewOSR::SelectionChanged( + const base::string16& text, + size_t offset, + const gfx::Range& range) { +} + +gfx::Size CefRenderWidgetHostViewOSR::GetRequestedRendererSize() const { + return delegated_frame_host_->GetRequestedRendererSize(); +} + +gfx::Size CefRenderWidgetHostViewOSR::GetPhysicalBackingSize() const { + float scale_factor = const_cast(this)-> + CurrentDeviceScaleFactor(); + return gfx::ToCeiledSize(gfx::ScaleSize(GetRequestedRendererSize(), + scale_factor)); +} + +void CefRenderWidgetHostViewOSR::SelectionBoundsChanged( + const ViewHostMsg_SelectionBounds_Params& params) { +} + +void CefRenderWidgetHostViewOSR::ScrollOffsetChanged() { + if (!browser_impl_) + return; + + browser_impl_->GetClient()->GetRenderHandler()-> + OnScrollOffsetChanged(browser_impl_.get()); +} + +void CefRenderWidgetHostViewOSR::CopyFromCompositingSurface( + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + const base::Callback& callback, + const SkBitmap::Config config) { + delegated_frame_host_->CopyFromCompositingSurface( + src_subrect, dst_size, callback, config); +} + +void CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceToVideoFrame( + const gfx::Rect& src_subrect, + const scoped_refptr& target, + const base::Callback& callback) { + delegated_frame_host_->CopyFromCompositingSurfaceToVideoFrame( + src_subrect, target, callback); +} + +bool CefRenderWidgetHostViewOSR::CanCopyToVideoFrame() const { + return delegated_frame_host_->CanCopyToVideoFrame(); +} + +bool CefRenderWidgetHostViewOSR::CanSubscribeFrame() const { + return delegated_frame_host_->CanSubscribeFrame(); +} + +void CefRenderWidgetHostViewOSR::BeginFrameSubscription( + scoped_ptr subscriber) { + delegated_frame_host_->BeginFrameSubscription(subscriber.Pass()); +} + +void CefRenderWidgetHostViewOSR::EndFrameSubscription() { + delegated_frame_host_->EndFrameSubscription(); +} + +void CefRenderWidgetHostViewOSR::AcceleratedSurfaceInitialized( + int host_id, + int route_id) { +} + +void CefRenderWidgetHostViewOSR::AcceleratedSurfaceBuffersSwapped( + const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params_in_pixel, + int gpu_host_id) { + // Oldschool composited mode is no longer supported. +} + +void CefRenderWidgetHostViewOSR::AcceleratedSurfacePostSubBuffer( + const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params_in_pixel, + int gpu_host_id) { + // Oldschool composited mode is no longer supported. +} + +void CefRenderWidgetHostViewOSR::AcceleratedSurfaceSuspend() { +} + +void CefRenderWidgetHostViewOSR::AcceleratedSurfaceRelease() { +} + +bool CefRenderWidgetHostViewOSR::HasAcceleratedSurface( + const gfx::Size& desired_size) { + // CEF doesn't use GetBackingStore for accelerated pages, so it doesn't + // matter what is returned here as GetBackingStore is the only caller of this + // method. + NOTREACHED(); + return false; +} + +void CefRenderWidgetHostViewOSR::GetScreenInfo(blink::WebScreenInfo* results) { + if (!browser_impl_) + return; + + CefScreenInfo screen_info( + kDefaultScaleFactor, 0, 0, false, CefRect(), CefRect()); + + CefRefPtr handler = + browser_impl_->client()->GetRenderHandler(); + if (!handler->GetScreenInfo(browser_impl_.get(), screen_info) || + screen_info.rect.width == 0 || + screen_info.rect.height == 0 || + screen_info.available_rect.width == 0 || + screen_info.available_rect.height == 0) { + // If a screen rectangle was not provided, try using the view rectangle + // instead. Otherwise, popup views may be drawn incorrectly, or not at all. + CefRect screenRect; + if (!handler->GetViewRect(browser_impl_.get(), screenRect)) { + NOTREACHED(); + screenRect = CefRect(); + } + + if (screen_info.rect.width == 0 && screen_info.rect.height == 0) + screen_info.rect = screenRect; + + if (screen_info.available_rect.width == 0 && + screen_info.available_rect.height == 0) + screen_info.available_rect = screenRect; + } + + *results = webScreenInfoFrom(screen_info); +} + +gfx::Rect CefRenderWidgetHostViewOSR::GetBoundsInRootWindow() { + if (!browser_impl_) + return gfx::Rect(); + + CefRect rc; + if (browser_impl_->GetClient()->GetRenderHandler()->GetRootScreenRect( + browser_impl_.get(), rc)) { + return gfx::Rect(rc.x, rc.y, rc.width, rc.height); + } + return gfx::Rect(); +} + +gfx::GLSurfaceHandle CefRenderWidgetHostViewOSR::GetCompositingSurface() { + return content::ImageTransportFactory::GetInstance()-> + GetSharedSurfaceHandle(); +} + +void CefRenderWidgetHostViewOSR::SetScrollOffsetPinning( + bool is_pinned_to_left, + bool is_pinned_to_right) { +} + +#if !defined(OS_MACOSX) && defined(USE_AURA) +void CefRenderWidgetHostViewOSR::ImeCompositionRangeChanged( + const gfx::Range& range, + const std::vector& character_bounds) { +} +#endif + +ui::Compositor* CefRenderWidgetHostViewOSR::GetCompositor() const { + return compositor_.get(); +} + +ui::Layer* CefRenderWidgetHostViewOSR::GetLayer() { + return root_layer_.get(); +} + +content::RenderWidgetHostImpl* CefRenderWidgetHostViewOSR::GetHost() { + return render_widget_host_; +} + +void CefRenderWidgetHostViewOSR::SchedulePaintInRect( + const gfx::Rect& damage_rect_in_dip) { + root_layer_->SchedulePaint(damage_rect_in_dip); +} + +void CefRenderWidgetHostViewOSR::DelegatedCompositorDidSwapBuffers() { +} + +void CefRenderWidgetHostViewOSR::DelegatedCompositorAbortedSwapBuffers() { +} + +bool CefRenderWidgetHostViewOSR::IsVisible() { + return IsShowing(); +} + +scoped_ptr CefRenderWidgetHostViewOSR::CreateResizeLock( + bool defer_compositor_lock) { + const gfx::Size& desired_size = root_layer_->bounds().size(); + return scoped_ptr(new CefResizeLock( + this, + desired_size, + defer_compositor_lock, + kResizeLockTimeoutMs)); +} + +gfx::Size CefRenderWidgetHostViewOSR::DesiredFrameSize() { + return root_layer_->bounds().size(); +} + +float CefRenderWidgetHostViewOSR::CurrentDeviceScaleFactor() { + if (!browser_impl_) + return kDefaultScaleFactor; + + CefScreenInfo screen_info( + kDefaultScaleFactor, 0, 0, false, CefRect(), CefRect()); + if (!browser_impl_->GetClient()->GetRenderHandler()->GetScreenInfo( + browser_impl_.get(), screen_info)) { + // Use the default + return kDefaultScaleFactor; + } + + return screen_info.device_scale_factor; +} + +gfx::Size CefRenderWidgetHostViewOSR::ConvertViewSizeToPixel( + const gfx::Size& size) { + return content::ConvertViewSizeToPixel(this, size); +} + +content::DelegatedFrameHost* + CefRenderWidgetHostViewOSR::GetDelegatedFrameHost() const { + return delegated_frame_host_.get(); +} + +bool CefRenderWidgetHostViewOSR::InstallTransparency() { + if (browser_impl_ && browser_impl_->IsTransparent()) { + SetBackgroundOpaque(false); + return true; + } + return false; +} + +void CefRenderWidgetHostViewOSR::WasResized() { + if (hold_resize_) { + if (!pending_resize_) + pending_resize_ = true; + return; + } + + ResizeRootLayer(); + if (render_widget_host_) + render_widget_host_->WasResized(); + delegated_frame_host_->WasResized(); +} + +void CefRenderWidgetHostViewOSR::OnScreenInfoChanged() { + TRACE_EVENT0("libcef", "CefRenderWidgetHostViewOSR::OnScreenInfoChanged"); + if (!render_widget_host_) + return; + + // TODO(OSR): Update the backing store. + + render_widget_host_->NotifyScreenInfoChanged(); + // We might want to change the cursor scale factor here as well - see the + // cache for the current_cursor_, as passed by UpdateCursor from the renderer + // in the rwhv_aura (current_cursor_.SetScaleFactor) +} + +void CefRenderWidgetHostViewOSR::Invalidate( + CefBrowserHost::PaintElementType type) { + TRACE_EVENT1("libcef", "CefRenderWidgetHostViewOSR::Invalidate", "type", + type); + if (!IsPopupWidget() && type == PET_POPUP) { + if (popup_host_view_) + popup_host_view_->Invalidate(type); + return; + } + + GenerateFrame(true); +} + +void CefRenderWidgetHostViewOSR::SendKeyEvent( + const content::NativeWebKeyboardEvent& event) { + TRACE_EVENT0("libcef", "CefRenderWidgetHostViewOSR::SendKeyEvent"); + if (!render_widget_host_) + return; + render_widget_host_->ForwardKeyboardEvent(event); +} + +void CefRenderWidgetHostViewOSR::SendMouseEvent( + const blink::WebMouseEvent& event) { + TRACE_EVENT0("libcef", "CefRenderWidgetHostViewOSR::SendMouseEvent"); + if (!IsPopupWidget()) { + if (browser_impl_ && event.type == blink::WebMouseEvent::MouseDown) + browser_impl_->CancelContextMenu(); + + if (popup_host_view_ && + popup_host_view_->popup_position_.Contains(event.x, event.y)) { + blink::WebMouseEvent popup_event(event); + popup_event.x -= popup_host_view_->popup_position_.x(); + popup_event.y -= popup_host_view_->popup_position_.y(); + popup_event.windowX = popup_event.x; + popup_event.windowY = popup_event.y; + + popup_host_view_->SendMouseEvent(popup_event); + return; + } + } + if (!render_widget_host_) + return; + render_widget_host_->ForwardMouseEvent(event); +} + +void CefRenderWidgetHostViewOSR::SendMouseWheelEvent( + const blink::WebMouseWheelEvent& event) { + TRACE_EVENT0("libcef", "CefRenderWidgetHostViewOSR::SendMouseWheelEvent"); + if (!IsPopupWidget()) { + if (browser_impl_) + browser_impl_->CancelContextMenu(); + + if (popup_host_view_) { + if (popup_host_view_->popup_position_.Contains(event.x, event.y)) { + blink::WebMouseWheelEvent popup_event(event); + popup_event.x -= popup_host_view_->popup_position_.x(); + popup_event.y -= popup_host_view_->popup_position_.y(); + popup_event.windowX = popup_event.x; + popup_event.windowY = popup_event.y; + popup_host_view_->SendMouseWheelEvent(popup_event); + return; + } else { + // Scrolling outside of the popup widget so destroy it. + // Execute asynchronously to avoid deleting the widget from inside some + // other callback. + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefRenderWidgetHostViewOSR::CancelPopupWidget, + popup_host_view_->weak_ptr_factory_.GetWeakPtr())); + } + } + } + if (!render_widget_host_) + return; + render_widget_host_->ForwardWheelEvent(event); +} + +void CefRenderWidgetHostViewOSR::SendFocusEvent(bool focus) { + if (!render_widget_host_) + return; + + content::RenderWidgetHostImpl* widget = + content::RenderWidgetHostImpl::From(render_widget_host_); + if (focus) { + widget->GotFocus(); + widget->SetActive(true); + } else { + if (browser_impl_) + browser_impl_->CancelContextMenu(); + + widget->SetActive(false); + widget->Blur(); + } +} + +void CefRenderWidgetHostViewOSR::HoldResize() { + if (!hold_resize_) + hold_resize_ = true; +} + +void CefRenderWidgetHostViewOSR::ReleaseResize() { + if (!hold_resize_) + return; + + hold_resize_ = false; + if (pending_resize_) { + pending_resize_ = false; + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefRenderWidgetHostViewOSR::WasResized, + weak_ptr_factory_.GetWeakPtr())); + } +} + +void CefRenderWidgetHostViewOSR::SetFrameRate() { + if (!browser_impl_) + return; + int frame_rate = browser_impl_->settings().windowless_frame_rate; + if (frame_rate < 1) + frame_rate = kDefaultFrameRate; + else if (frame_rate > kMaximumFrameRate) + frame_rate = kMaximumFrameRate; + frame_rate_threshold_ms_ = 1000 / frame_rate; +} + +void CefRenderWidgetHostViewOSR::ResizeRootLayer() { + gfx::Size size; + if (!IsPopupWidget()) + size = GetViewBounds().size(); + else + size = popup_position_.size(); + root_layer_->SetBounds(gfx::Rect(0, 0, size.width(), size.height())); +} + +void CefRenderWidgetHostViewOSR::GenerateFrame(bool force_frame) { + if (force_frame && !frame_pending_) + frame_pending_ = true; + + // No frame needs to be generated at this time. + if (!frame_pending_) + return; + + // Don't attempt to generate a frame while one is currently in-progress. + if (frame_in_progress_) + return; + frame_in_progress_ = true; + + // Don't exceed the frame rate threshold. + const int64 frame_rate_delta = + (base::TimeTicks::Now() - frame_start_time_).InMilliseconds(); + if (frame_rate_delta < frame_rate_threshold_ms_) { + // Generate the frame after the necessary time has passed. + CEF_POST_DELAYED_TASK(CEF_UIT, + base::Bind(&CefRenderWidgetHostViewOSR::InternalGenerateFrame, + weak_ptr_factory_.GetWeakPtr()), + frame_rate_threshold_ms_ - frame_rate_delta); + return; + } + + InternalGenerateFrame(); +} + +void CefRenderWidgetHostViewOSR::InternalGenerateFrame() { + frame_pending_ = false; + frame_start_time_ = base::TimeTicks::Now(); + + // The below code is similar in functionality to + // DelegatedFrameHost::CopyFromCompositingSurface but we reuse the same + // SkBitmap in the GPU codepath and avoid scaling where possible. + scoped_ptr request = + cc::CopyOutputRequest::CreateRequest(base::Bind( + &CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceHasResult, + weak_ptr_factory_.GetWeakPtr())); + + const gfx::Rect& src_subrect_in_pixel = + content::ConvertRectToPixel(CurrentDeviceScaleFactor(), + root_layer_->bounds()); + request->set_area(src_subrect_in_pixel); + RequestCopyOfOutput(request.Pass()); +} + +void CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceHasResult( + scoped_ptr result) { + if (result->IsEmpty() || result->size().IsEmpty()) { + OnFrameCaptureFailure(); + return; + } + + if (result->HasTexture()) { + PrepareTextureCopyOutputResult(result.Pass()); + return; + } + + DCHECK(result->HasBitmap()); + PrepareBitmapCopyOutputResult(result.Pass()); +} + +void CefRenderWidgetHostViewOSR::PrepareTextureCopyOutputResult( + scoped_ptr result) { + DCHECK(result->HasTexture()); + base::ScopedClosureRunner scoped_callback_runner( + base::Bind(&CefRenderWidgetHostViewOSR::OnFrameCaptureFailure, + weak_ptr_factory_.GetWeakPtr())); + + const gfx::Size& result_size = result->size(); + SkIRect bitmap_size; + if (bitmap_) + bitmap_->getBounds(&bitmap_size); + + if (!bitmap_ || + bitmap_size.width() != result_size.width() || + bitmap_size.height() != result_size.height()) { + // Create a new bitmap if the size has changed. + bitmap_.reset(new SkBitmap); + bitmap_->setConfig(SkBitmap::kARGB_8888_Config, + result_size.width(), + result_size.height(), + 0, + kOpaque_SkAlphaType); + if (!bitmap_->allocPixels()) + return; + } + + content::ImageTransportFactory* factory = + content::ImageTransportFactory::GetInstance(); + content::GLHelper* gl_helper = factory->GetGLHelper(); + if (!gl_helper) + return; + + scoped_ptr bitmap_pixels_lock( + new SkAutoLockPixels(*bitmap_)); + uint8* pixels = static_cast(bitmap_->getPixels()); + + cc::TextureMailbox texture_mailbox; + scoped_ptr release_callback; + result->TakeTexture(&texture_mailbox, &release_callback); + DCHECK(texture_mailbox.IsTexture()); + if (!texture_mailbox.IsTexture()) + return; + + ignore_result(scoped_callback_runner.Release()); + + gl_helper->CropScaleReadbackAndCleanMailbox( + texture_mailbox.mailbox(), + texture_mailbox.sync_point(), + result_size, + gfx::Rect(result_size), + result_size, + pixels, + SkBitmap::kARGB_8888_Config, + base::Bind( + &CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceFinishedProxy, + weak_ptr_factory_.GetWeakPtr(), + base::Passed(&release_callback), + base::Passed(&bitmap_), + base::Passed(&bitmap_pixels_lock)), + content::GLHelper::SCALER_QUALITY_FAST); +} + +// static +void CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceFinishedProxy( + base::WeakPtr view, + scoped_ptr release_callback, + scoped_ptr bitmap, + scoped_ptr bitmap_pixels_lock, + bool result) { + // This method may be called after the view has been deleted. + uint32 sync_point = 0; + if (result) { + content::GLHelper* gl_helper = + content::ImageTransportFactory::GetInstance()->GetGLHelper(); + sync_point = gl_helper->InsertSyncPoint(); + } + bool lost_resource = sync_point == 0; + release_callback->Run(sync_point, lost_resource); + + if (view) { + view->CopyFromCompositingSurfaceFinished( + bitmap.Pass(), bitmap_pixels_lock.Pass(), result); + } else { + bitmap_pixels_lock.reset(); + bitmap.reset(); + } +} + +void CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceFinished( + scoped_ptr bitmap, + scoped_ptr bitmap_pixels_lock, + bool result) { + // Restore ownership of the bitmap to the view. + DCHECK(!bitmap_); + bitmap_ = bitmap.Pass(); + + if (result) { + OnFrameCaptureSuccess(*bitmap_, bitmap_pixels_lock.Pass()); + } else { + bitmap_pixels_lock.reset(); + OnFrameCaptureFailure(); + } +} + +void CefRenderWidgetHostViewOSR::PrepareBitmapCopyOutputResult( + scoped_ptr result) { + DCHECK(result->HasBitmap()); + scoped_ptr source = result->TakeBitmap(); + DCHECK(source); + if (source) { + scoped_ptr bitmap_pixels_lock( + new SkAutoLockPixels(*source)); + OnFrameCaptureSuccess(*source, bitmap_pixels_lock.Pass()); + } else { + OnFrameCaptureFailure(); + } +} + +void CefRenderWidgetHostViewOSR::OnFrameCaptureFailure() { + const bool force_frame = (++frame_retry_count_ <= kFrameRetryLimit); + OnFrameCaptureCompletion(force_frame); +} + +void CefRenderWidgetHostViewOSR::OnFrameCaptureSuccess( + const SkBitmap& bitmap, + scoped_ptr bitmap_pixels_lock) { + SkRect bounds; + bitmap.getBounds(&bounds); + + CefRenderHandler::RectList rcList; + rcList.push_back(CefRect(0, 0, bounds.width(), bounds.height())); + + browser_impl_->GetClient()->GetRenderHandler()->OnPaint( + browser_impl_.get(), + IsPopupWidget() ? PET_POPUP : PET_VIEW, + rcList, + bitmap.getPixels(), + bounds.width(), + bounds.height()); + + bitmap_pixels_lock.reset(); + + // Reset the frame retry count on successful frame generation. + if (frame_retry_count_ > 0) + frame_retry_count_ = 0; + + OnFrameCaptureCompletion(false); +} + +void CefRenderWidgetHostViewOSR::OnFrameCaptureCompletion(bool force_frame) { + frame_in_progress_ = false; + + if (frame_pending_) { + // Another frame was requested while the current frame was in-progress. + // Generate the pending frame now. + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefRenderWidgetHostViewOSR::GenerateFrame, + weak_ptr_factory_.GetWeakPtr(), force_frame)); + } +} + +void CefRenderWidgetHostViewOSR::CancelPopupWidget() { + DCHECK(IsPopupWidget()); + + if (render_widget_host_) + render_widget_host_->LostCapture(); + + WasHidden(); + + if (browser_impl_) { + browser_impl_->GetClient()->GetRenderHandler()->OnPopupShow( + browser_impl_.get(), false); + browser_impl_ = NULL; + } + + if (parent_host_view_) { + parent_host_view_->set_popup_host_view(NULL); + parent_host_view_ = NULL; + } + + if (render_widget_host_ && !is_destroyed_) { + is_destroyed_ = true; + // Results in a call to Destroy(). + render_widget_host_->Shutdown(); + } +} + diff --git a/libcef/browser/render_widget_host_view_osr.h b/libcef/browser/render_widget_host_view_osr.h new file mode 100644 index 000000000..236270bc7 --- /dev/null +++ b/libcef/browser/render_widget_host_view_osr.h @@ -0,0 +1,341 @@ +// Copyright (c) 2014 The Chromium Embedded Framework Authors. +// Portions 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. + +#ifndef CEF_LIBCEF_BROWSER_RENDER_WIDGET_HOST_VIEW_OSR_H_ +#define CEF_LIBCEF_BROWSER_RENDER_WIDGET_HOST_VIEW_OSR_H_ +#pragma once + +#include + +#include "include/cef_base.h" +#include "include/cef_browser.h" + +#include "base/memory/weak_ptr.h" +#include "content/browser/compositor/delegated_frame_host.h" +#include "content/browser/renderer_host/render_widget_host_view_base.h" +#include "ui/compositor/compositor.h" + +#if defined(OS_WIN) +#include "ui/gfx/win/window_impl.h" +#endif + +namespace content { +class RenderWidgetHost; +class RenderWidgetHostImpl; +class BackingStore; +} + +class CefBrowserHostImpl; +class CefWebContentsViewOSR; + +#if defined(OS_MACOSX) +#ifdef __OBJC__ +@class NSWindow; +#else +class NSWindow; +#endif +#endif + +#if defined(USE_X11) +class CefWindowX11; +#endif + +/////////////////////////////////////////////////////////////////////////////// +// CefRenderWidgetHostViewOSR +// +// An object representing the "View" of a rendered web page. This object is +// responsible for sending paint events to the the CefRenderHandler +// when window rendering is disabled. It is the implementation of the +// RenderWidgetHostView that the cross-platform RenderWidgetHost object uses +// to display the data. +// +// Comment excerpted from render_widget_host.h: +// +// "The lifetime of the RenderWidgetHostView is tied to the render process. +// If the render process dies, the RenderWidgetHostView goes away and all +// references to it must become NULL." +// +// RenderWidgetHostView class hierarchy described in render_widget_host_view.h. +/////////////////////////////////////////////////////////////////////////////// + +class CefRenderWidgetHostViewOSR + : public content::RenderWidgetHostViewBase, + public content::DelegatedFrameHostClient { + public: + explicit CefRenderWidgetHostViewOSR(content::RenderWidgetHost* widget); + virtual ~CefRenderWidgetHostViewOSR(); + + // RenderWidgetHostView implementation. + virtual void InitAsChild(gfx::NativeView parent_view) OVERRIDE; + virtual content::RenderWidgetHost* GetRenderWidgetHost() const OVERRIDE; + virtual void SetSize(const gfx::Size& size) OVERRIDE; + virtual void SetBounds(const gfx::Rect& rect) OVERRIDE; + virtual gfx::NativeView GetNativeView() const OVERRIDE; + virtual gfx::NativeViewId GetNativeViewId() const OVERRIDE; + virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE; + virtual ui::TextInputClient* GetTextInputClient() OVERRIDE; + virtual void Focus() OVERRIDE; + virtual bool HasFocus() const OVERRIDE; + virtual bool IsSurfaceAvailableForCopy() const OVERRIDE; + virtual void Show() OVERRIDE; + virtual void Hide() OVERRIDE; + virtual bool IsShowing() OVERRIDE; + virtual gfx::Rect GetViewBounds() const OVERRIDE; + virtual void SetBackgroundOpaque(bool opaque) OVERRIDE; + virtual bool LockMouse() OVERRIDE; + virtual void UnlockMouse() OVERRIDE; + +#if defined(OS_MACOSX) + virtual void SetActive(bool active) OVERRIDE; + virtual void SetTakesFocusOnlyOnMouseDown(bool flag) OVERRIDE; + virtual void SetWindowVisibility(bool visible) OVERRIDE; + virtual void WindowFrameChanged() OVERRIDE; + virtual void ShowDefinitionForSelection() OVERRIDE; + virtual bool SupportsSpeech() const OVERRIDE; + virtual void SpeakSelection() OVERRIDE; + virtual bool IsSpeaking() const OVERRIDE; + virtual void StopSpeaking() OVERRIDE; +#endif // defined(OS_MACOSX) + + // RenderWidgetHostViewBase implementation. + virtual void OnSwapCompositorFrame( + uint32 output_surface_id, + scoped_ptr frame) OVERRIDE; + virtual void InitAsPopup(content::RenderWidgetHostView* parent_host_view, + const gfx::Rect& pos) OVERRIDE; + virtual void InitAsFullscreen( + content::RenderWidgetHostView* reference_host_view) OVERRIDE; + virtual void WasShown() OVERRIDE; + virtual void WasHidden() OVERRIDE; + virtual void MovePluginWindows( + const std::vector& moves) OVERRIDE; + virtual void Blur() OVERRIDE; + virtual void UpdateCursor(const content::WebCursor& cursor) OVERRIDE; + virtual void SetIsLoading(bool is_loading) OVERRIDE; + virtual void TextInputTypeChanged(ui::TextInputType type, + ui::TextInputMode input_mode, + bool can_compose_inline) OVERRIDE; + virtual void ImeCancelComposition() OVERRIDE; + virtual void RenderProcessGone(base::TerminationStatus status, + int error_code) OVERRIDE; + virtual void Destroy() OVERRIDE; + virtual void SetTooltipText(const base::string16& tooltip_text) OVERRIDE; + virtual void SelectionChanged(const base::string16& text, + size_t offset, + const gfx::Range& range) OVERRIDE; + virtual gfx::Size GetRequestedRendererSize() const OVERRIDE; + virtual gfx::Size GetPhysicalBackingSize() const OVERRIDE; + virtual void SelectionBoundsChanged( + const ViewHostMsg_SelectionBounds_Params& params) OVERRIDE; + virtual void ScrollOffsetChanged() OVERRIDE; + virtual void CopyFromCompositingSurface( + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + const base::Callback& callback, + const SkBitmap::Config config) OVERRIDE; + virtual void CopyFromCompositingSurfaceToVideoFrame( + const gfx::Rect& src_subrect, + const scoped_refptr& target, + const base::Callback& callback) OVERRIDE; + virtual bool CanCopyToVideoFrame() const OVERRIDE; + virtual bool CanSubscribeFrame() const OVERRIDE; + virtual void BeginFrameSubscription( + scoped_ptr subscriber) + OVERRIDE; + virtual void EndFrameSubscription() OVERRIDE; + virtual void AcceleratedSurfaceInitialized(int host_id, + int route_id) OVERRIDE; + virtual void AcceleratedSurfaceBuffersSwapped( + const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params_in_pixel, + int gpu_host_id) OVERRIDE; + virtual void AcceleratedSurfacePostSubBuffer( + const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params_in_pixel, + int gpu_host_id) OVERRIDE; + virtual void AcceleratedSurfaceSuspend() OVERRIDE; + virtual void AcceleratedSurfaceRelease() OVERRIDE; + virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) OVERRIDE; + virtual void GetScreenInfo(blink::WebScreenInfo* results) OVERRIDE; + virtual gfx::Rect GetBoundsInRootWindow() OVERRIDE; + virtual gfx::GLSurfaceHandle GetCompositingSurface() OVERRIDE; + virtual void SetScrollOffsetPinning( + bool is_pinned_to_left, + bool is_pinned_to_right) OVERRIDE; + +#if defined(OS_MACOSX) + virtual bool PostProcessEventForPluginIme( + const content::NativeWebKeyboardEvent& event) OVERRIDE; +#endif + +#if defined(OS_MACOSX) || defined(USE_AURA) + virtual void ImeCompositionRangeChanged( + const gfx::Range& range, + const std::vector& character_bounds) OVERRIDE; +#endif + +#if defined(OS_WIN) + virtual void SetParentNativeViewAccessible( + gfx::NativeViewAccessible accessible_parent) OVERRIDE; + virtual gfx::NativeViewId GetParentForWindowlessPlugin() const OVERRIDE; +#endif + + // DelegatedFrameHost implementation. + virtual ui::Compositor* GetCompositor() const OVERRIDE; + virtual ui::Layer* GetLayer() OVERRIDE; + virtual content::RenderWidgetHostImpl* GetHost() OVERRIDE; + virtual void SchedulePaintInRect( + const gfx::Rect& damage_rect_in_dip) OVERRIDE; + virtual void DelegatedCompositorDidSwapBuffers() OVERRIDE; + virtual void DelegatedCompositorAbortedSwapBuffers() OVERRIDE; + virtual bool IsVisible() OVERRIDE; + virtual scoped_ptr CreateResizeLock( + bool defer_compositor_lock) OVERRIDE; + virtual gfx::Size DesiredFrameSize() OVERRIDE; + virtual float CurrentDeviceScaleFactor() OVERRIDE; + virtual gfx::Size ConvertViewSizeToPixel(const gfx::Size& size) OVERRIDE; + virtual content::DelegatedFrameHost* GetDelegatedFrameHost() const OVERRIDE; + + bool InstallTransparency(); + + void WasResized(); + void OnScreenInfoChanged(); + void Invalidate(CefBrowserHost::PaintElementType type); + void SendKeyEvent(const content::NativeWebKeyboardEvent& event); + void SendMouseEvent(const blink::WebMouseEvent& event); + void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event); + void SendFocusEvent(bool focus); + + void HoldResize(); + void ReleaseResize(); + + bool IsPopupWidget() const { + return popup_type_ != blink::WebPopupTypeNone; + } + +#if defined(OS_MACOSX) + NSTextInputContext* GetNSTextInputContext(); + void HandleKeyEventBeforeTextInputClient(CefEventHandle keyEvent); + void HandleKeyEventAfterTextInputClient(CefEventHandle keyEvent); + + bool GetCachedFirstRectForCharacterRange(gfx::Range range, gfx::Rect* rect, + gfx::Range* actual_range) const; +#endif // defined(OS_MACOSX) + + CefRefPtr browser_impl() const { return browser_impl_; } + void set_browser_impl(CefRefPtr browser) { + browser_impl_ = browser; + } + + void set_popup_host_view(CefRenderWidgetHostViewOSR* popup_view) { + popup_host_view_ = popup_view; + } + + ui::Compositor* compositor() const { return compositor_.get(); } + content::RenderWidgetHostImpl* render_widget_host() const + { return render_widget_host_; } + + private: + void SetFrameRate(); + void ResizeRootLayer(); + + // Implementation based on RendererOverridesHandler::InnerSwapCompositorFrame + // and DelegatedFrameHost::CopyFromCompositingSurface. + void GenerateFrame(bool force_frame); + void InternalGenerateFrame(); + void CopyFromCompositingSurfaceHasResult( + scoped_ptr result); + void PrepareTextureCopyOutputResult( + scoped_ptr result); + static void CopyFromCompositingSurfaceFinishedProxy( + base::WeakPtr view, + scoped_ptr release_callback, + scoped_ptr bitmap, + scoped_ptr bitmap_pixels_lock, + bool result); + void CopyFromCompositingSurfaceFinished( + scoped_ptr bitmap, + scoped_ptr bitmap_pixels_lock, + bool result); + void PrepareBitmapCopyOutputResult( + scoped_ptr result); + void OnFrameCaptureFailure(); + void OnFrameCaptureSuccess( + const SkBitmap& bitmap, + scoped_ptr bitmap_pixels_lock); + void OnFrameCaptureCompletion(bool force_frame); + + void CancelPopupWidget(); + +#if defined(OS_MACOSX) + // Returns composition character boundary rectangle. The |range| is + // composition based range. Also stores |actual_range| which is corresponding + // to actually used range for returned rectangle. + gfx::Rect GetFirstRectForCompositionRange(const gfx::Range& range, + gfx::Range* actual_range) const; + + // Converts from given whole character range to composition oriented range. If + // the conversion failed, return gfx::Range::InvalidRange. + gfx::Range ConvertCharacterRangeToCompositionRange( + const gfx::Range& request_range) const; + + // Returns true if there is line break in |range| and stores line breaking + // point to |line_breaking_point|. The |line_break_point| is valid only if + // this function returns true. + static bool GetLineBreakIndex(const std::vector& bounds, + const gfx::Range& range, + size_t* line_break_point); + + void DestroyNSTextInputOSR(); +#endif // defined(OS_MACOSX) + + void PlatformCreateCompositorWidget(); + void PlatformDestroyCompositorWidget(); + + scoped_ptr delegated_frame_host_; + scoped_ptr compositor_; + gfx::AcceleratedWidget compositor_widget_; + scoped_ptr root_layer_; + +#if defined(OS_WIN) + scoped_ptr window_; +#elif defined(OS_MACOSX) + NSWindow* window_; +#elif defined(USE_X11) + CefWindowX11* window_; +#endif + + int frame_rate_threshold_ms_; + base::TimeTicks frame_start_time_; + bool frame_pending_; + bool frame_in_progress_; + int frame_retry_count_; + scoped_ptr bitmap_; + + bool hold_resize_; + bool pending_resize_; + + // The associated Model. While |this| is being Destroyed, + // |render_widget_host_| is NULL and the message loop is run one last time + // Message handlers must check for a NULL |render_widget_host_|. + content::RenderWidgetHostImpl* render_widget_host_; + CefRenderWidgetHostViewOSR* parent_host_view_; + CefRenderWidgetHostViewOSR* popup_host_view_; + + CefRefPtr browser_impl_; + + bool is_showing_; + bool is_destroyed_; + gfx::Rect popup_position_; + +#if defined(OS_MACOSX) + NSTextInputContext* text_input_context_osr_mac_; +#endif + + base::WeakPtrFactory weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(CefRenderWidgetHostViewOSR); +}; + +#endif // CEF_LIBCEF_BROWSER_RENDER_WIDGET_HOST_VIEW_OSR_H_ + diff --git a/libcef/browser/render_widget_host_view_osr_linux.cc b/libcef/browser/render_widget_host_view_osr_linux.cc new file mode 100644 index 000000000..26cc247ab --- /dev/null +++ b/libcef/browser/render_widget_host_view_osr_linux.cc @@ -0,0 +1,25 @@ +// Copyright (c) 2014 The Chromium Embedded Framework Authors. +// Portions 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 "libcef/browser/render_widget_host_view_osr.h" + +#include + +#include "libcef/browser/browser_host_impl.h" +#include "libcef/browser/window_x11.h" + +#include "ui/gfx/x/x11_types.h" + +void CefRenderWidgetHostViewOSR::PlatformCreateCompositorWidget() { + // Create a hidden 1x1 window. It will delete itself on close. + window_ = new CefWindowX11(NULL, None, gfx::Rect(0, 0, 1, 1)); + compositor_widget_ = window_->xwindow(); +} + +void CefRenderWidgetHostViewOSR::PlatformDestroyCompositorWidget() { + DCHECK(window_); + window_->Close(); + compositor_widget_ = gfx::kNullAcceleratedWidget; +} diff --git a/libcef/browser/render_widget_host_view_osr_mac.mm b/libcef/browser/render_widget_host_view_osr_mac.mm new file mode 100644 index 000000000..95b1b57ab --- /dev/null +++ b/libcef/browser/render_widget_host_view_osr_mac.mm @@ -0,0 +1,283 @@ +// Copyright (c) 2014 The Chromium Embedded Framework Authors. +// Portions 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 "libcef/browser/render_widget_host_view_osr.h" + +#import + +#include "libcef/browser/browser_host_impl.h" +#include "libcef/browser/text_input_client_osr_mac.h" + +#include "content/browser/compositor/browser_compositor_view_mac.h" + +#if !defined(UNUSED) +#define UNUSED(x) ((void)(x)) /* to avoid warnings */ +#endif + +namespace { + +CefTextInputClientOSRMac* GetInputClientFromContext( + const NSTextInputContext* context) { + if (!context) + return NULL; + return reinterpret_cast([context client]); +} + +} // namespace + +void CefRenderWidgetHostViewOSR::SetActive(bool active) { +} + +void CefRenderWidgetHostViewOSR::SetTakesFocusOnlyOnMouseDown(bool flag) { +} + +void CefRenderWidgetHostViewOSR::SetWindowVisibility(bool visible) { +} + +void CefRenderWidgetHostViewOSR::WindowFrameChanged() { +} + +void CefRenderWidgetHostViewOSR::ShowDefinitionForSelection() { +} + +bool CefRenderWidgetHostViewOSR::SupportsSpeech() const { + return false; +} + +void CefRenderWidgetHostViewOSR::SpeakSelection() { +} + +bool CefRenderWidgetHostViewOSR::IsSpeaking() const { + return false; +} + +void CefRenderWidgetHostViewOSR::StopSpeaking() { +} + +void CefRenderWidgetHostViewOSR::TextInputTypeChanged( + ui::TextInputType type, + ui::TextInputMode mode, + bool can_compose_inline) { + [NSApp updateWindows]; +} + +void CefRenderWidgetHostViewOSR::ImeCancelComposition() { + CefTextInputClientOSRMac* client = GetInputClientFromContext( + text_input_context_osr_mac_); + if (client) + [client cancelComposition]; +} + +bool CefRenderWidgetHostViewOSR::PostProcessEventForPluginIme( + const content::NativeWebKeyboardEvent& event) { + return false; +} + +void CefRenderWidgetHostViewOSR::ImeCompositionRangeChanged( + const gfx::Range& range, + const std::vector& character_bounds) { + CefTextInputClientOSRMac* client = GetInputClientFromContext( + text_input_context_osr_mac_); + if (!client) + return; + + client->markedRange_ = range.ToNSRange(); + client->composition_range_ = range; + client->composition_bounds_ = character_bounds; +} + +CefTextInputContext CefRenderWidgetHostViewOSR::GetNSTextInputContext() { + if (!text_input_context_osr_mac_) { + CefTextInputClientOSRMac* text_input_client_osr_mac = + [[CefTextInputClientOSRMac alloc] initWithRenderWidgetHostViewOSR: + this]; + + text_input_context_osr_mac_ = [[NSTextInputContext alloc] initWithClient: + text_input_client_osr_mac]; + } + + return text_input_context_osr_mac_; +} + +void CefRenderWidgetHostViewOSR::HandleKeyEventBeforeTextInputClient( + CefEventHandle keyEvent) { + CefTextInputClientOSRMac* client = GetInputClientFromContext( + text_input_context_osr_mac_); + if (client) + [client HandleKeyEventBeforeTextInputClient: keyEvent]; +} + +void CefRenderWidgetHostViewOSR::HandleKeyEventAfterTextInputClient( + CefEventHandle keyEvent) { + CefTextInputClientOSRMac* client = GetInputClientFromContext( + text_input_context_osr_mac_); + if (client) + [client HandleKeyEventAfterTextInputClient: keyEvent]; +} + +bool CefRenderWidgetHostViewOSR::GetCachedFirstRectForCharacterRange( + gfx::Range range, gfx::Rect* rect, gfx::Range* actual_range) const { + DCHECK(rect); + CefTextInputClientOSRMac* client = GetInputClientFromContext( + text_input_context_osr_mac_); + + // If requested range is same as caret location, we can just return it. + if (selection_range_.is_empty() && gfx::Range(range) == selection_range_) { + if (actual_range) + *actual_range = range; + *rect = client->caret_rect_; + return true; + } + + const gfx::Range request_range_in_composition = + ConvertCharacterRangeToCompositionRange(gfx::Range(range)); + if (request_range_in_composition == gfx::Range::InvalidRange()) + return false; + + // If firstRectForCharacterRange in WebFrame is failed in renderer, + // ImeCompositionRangeChanged will be sent with empty vector. + if (client->composition_bounds_.empty()) + return false; + + DCHECK_EQ(client->composition_bounds_.size(), + client->composition_range_.length()); + + gfx::Range ui_actual_range; + *rect = GetFirstRectForCompositionRange(request_range_in_composition, + &ui_actual_range); + if (actual_range) { + *actual_range = gfx::Range( + client->composition_range_.start() + ui_actual_range.start(), + client->composition_range_.start() + ui_actual_range.end()).ToNSRange(); + } + return true; +} + +gfx::Rect CefRenderWidgetHostViewOSR::GetFirstRectForCompositionRange( + const gfx::Range& range, gfx::Range* actual_range) const { + CefTextInputClientOSRMac* client = GetInputClientFromContext( + text_input_context_osr_mac_); + + DCHECK(client); + DCHECK(actual_range); + DCHECK(!client->composition_bounds_.empty()); + DCHECK_LE(range.start(), client->composition_bounds_.size()); + DCHECK_LE(range.end(), client->composition_bounds_.size()); + + if (range.is_empty()) { + *actual_range = range; + if (range.start() == client->composition_bounds_.size()) { + return gfx::Rect(client->composition_bounds_[range.start() - 1].right(), + client->composition_bounds_[range.start() - 1].y(), + 0, + client->composition_bounds_[range.start() - 1].height()); + } else { + return gfx::Rect(client->composition_bounds_[range.start()].x(), + client->composition_bounds_[range.start()].y(), + 0, + client->composition_bounds_[range.start()].height()); + } + } + + size_t end_idx; + if (!GetLineBreakIndex(client->composition_bounds_, + range, &end_idx)) { + end_idx = range.end(); + } + *actual_range = gfx::Range(range.start(), end_idx); + gfx::Rect rect = client->composition_bounds_[range.start()]; + for (size_t i = range.start() + 1; i < end_idx; ++i) { + rect.Union(client->composition_bounds_[i]); + } + return rect; +} + +gfx::Range CefRenderWidgetHostViewOSR::ConvertCharacterRangeToCompositionRange( + const gfx::Range& request_range) const { + CefTextInputClientOSRMac* client = GetInputClientFromContext( + text_input_context_osr_mac_); + DCHECK(client); + + if (client->composition_range_.is_empty()) + return gfx::Range::InvalidRange(); + + if (request_range.is_reversed()) + return gfx::Range::InvalidRange(); + + if (request_range.start() < client->composition_range_.start() + || request_range.start() > client->composition_range_.end() + || request_range.end() > client->composition_range_.end()) + return gfx::Range::InvalidRange(); + + return gfx::Range(request_range.start() - client->composition_range_.start(), + request_range.end() - client->composition_range_.start()); +} + +bool CefRenderWidgetHostViewOSR::GetLineBreakIndex( + const std::vector& bounds, + const gfx::Range& range, + size_t* line_break_point) { + DCHECK(line_break_point); + if (range.start() >= bounds.size() || range.is_reversed() || range.is_empty()) + return false; + + // We can't check line breaking completely from only rectangle array. Thus we + // assume the line breaking as the next character's y offset is larger than + // a threshold. Currently the threshold is determined as minimum y offset plus + // 75% of maximum height. + const size_t loop_end_idx = std::min(bounds.size(), range.end()); + int max_height = 0; + int min_y_offset = kint32max; + for (size_t idx = range.start(); idx < loop_end_idx; ++idx) { + max_height = std::max(max_height, bounds[idx].height()); + min_y_offset = std::min(min_y_offset, bounds[idx].y()); + } + int line_break_threshold = min_y_offset + (max_height * 3 / 4); + for (size_t idx = range.start(); idx < loop_end_idx; ++idx) { + if (bounds[idx].y() > line_break_threshold) { + *line_break_point = idx; + return true; + } + } + return false; +} + +void CefRenderWidgetHostViewOSR::DestroyNSTextInputOSR() { + CefTextInputClientOSRMac* client = GetInputClientFromContext( + text_input_context_osr_mac_); + if (client) { + [client release]; + client = NULL; + } + + [text_input_context_osr_mac_ release]; + text_input_context_osr_mac_ = NULL; +} + +void CefRenderWidgetHostViewOSR::PlatformCreateCompositorWidget() { + // Create a borderless non-visible 1x1 window. + window_ = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 1, 1) + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + BrowserCompositorViewMac* view = + [[BrowserCompositorViewMac alloc] initWithSuperview:[window_ contentView] + withClient:NULL]; + compositor_.reset([view compositor]); + DCHECK(compositor_); + compositor_widget_ = view; +} + +void CefRenderWidgetHostViewOSR::PlatformDestroyCompositorWidget() { + DCHECK(window_); + + // Compositor is owned by and will be freed by BrowserCompositorViewMac. + ui::Compositor* compositor = compositor_.release(); + UNUSED(compositor); + + [window_ close]; + window_ = nil; + compositor_widget_ = gfx::kNullAcceleratedWidget; +} diff --git a/libcef/browser/render_widget_host_view_osr_win.cc b/libcef/browser/render_widget_host_view_osr_win.cc new file mode 100644 index 000000000..9d1643b3d --- /dev/null +++ b/libcef/browser/render_widget_host_view_osr_win.cc @@ -0,0 +1,59 @@ +// Copyright (c) 2014 The Chromium Embedded Framework Authors. +// Portions 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 "libcef/browser/render_widget_host_view_osr.h" +#include "libcef/browser/browser_host_impl.h" + +namespace { + +class CefCompositorHostWin : public gfx::WindowImpl { + public: + CefCompositorHostWin() { + // Create a hidden 1x1 borderless window. + set_window_style(WS_POPUP | WS_SYSMENU); + Init(NULL, gfx::Rect(0, 0, 1, 1)); + } + + virtual ~CefCompositorHostWin() { + DestroyWindow(hwnd()); + } + + private: + CR_BEGIN_MSG_MAP_EX(CompositorHostWin) + CR_MSG_WM_PAINT(OnPaint) + CR_END_MSG_MAP() + + void OnPaint(HDC dc) { + ValidateRect(hwnd(), NULL); + } + + DISALLOW_COPY_AND_ASSIGN(CefCompositorHostWin); +}; + +} // namespace + +void CefRenderWidgetHostViewOSR::SetParentNativeViewAccessible( + gfx::NativeViewAccessible accessible_parent) { +} + +gfx::NativeViewId + CefRenderWidgetHostViewOSR::GetParentForWindowlessPlugin() const { + if (browser_impl_.get()) { + return reinterpret_cast( + browser_impl_->GetWindowHandle()); + } + return NULL; +} + +void CefRenderWidgetHostViewOSR::PlatformCreateCompositorWidget() { + DCHECK(!window_); + window_.reset(new CefCompositorHostWin()); + compositor_widget_ = window_->hwnd(); +} + +void CefRenderWidgetHostViewOSR::PlatformDestroyCompositorWidget() { + window_.reset(NULL); + compositor_widget_ = gfx::kNullAcceleratedWidget; +} diff --git a/libcef/browser/text_input_client_osr_mac.h b/libcef/browser/text_input_client_osr_mac.h new file mode 100644 index 000000000..5b10caab1 --- /dev/null +++ b/libcef/browser/text_input_client_osr_mac.h @@ -0,0 +1,89 @@ +// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#ifndef CEF_LIBCEF_BROWSER_TEXT_INPUT_CLIENT_OSR_MAC_H_ +#define CEF_LIBCEF_BROWSER_TEXT_INPUT_CLIENT_OSR_MAC_H_ +#pragma once + +#import +#include + +#include "libcef/browser/render_widget_host_view_osr.h" + +#include "base/mac/scoped_nsobject.h" +#include "base/strings/string16.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" +#include "content/common/edit_command.h" +#include "third_party/WebKit/public/web/WebCompositionUnderline.h" + +// Implementation for the NSTextInputClient protocol used for enabling IME on +// mac when window rendering is disabled. + +@interface CefTextInputClientOSRMac : NSObject { + + @public + // The range of current marked text inside the whole content of the DOM node + // being edited. + NSRange markedRange_; + + // The current composition character range and its bounds. + gfx::Range composition_range_; + std::vector composition_bounds_; + + // The current caret bounds. + gfx::Rect caret_rect_; + + @private + // Represents the input-method attributes supported by this object. + base::scoped_nsobject validAttributesForMarkedText_; + + // Indicates if we are currently handling a key down event. + BOOL handlingKeyDown_; + + // Indicates if there is any marked text. + BOOL hasMarkedText_; + + // Indicates whether there was any marked text prior to handling + // the current key event. + BOOL oldHasMarkedText_; + + // Indicates if unmarkText is called or not when handling a keyboard + // event. + BOOL unmarkTextCalled_; + + // The selected range, cached from a message sent by the renderer. + NSRange selectedRange_; + + // Text to be inserted which was generated by handling a key down event. + base::string16 textToBeInserted_; + + // Marked text which was generated by handling a key down event. + base::string16 markedText_; + + // Underline information of the |markedText_|. + std::vector underlines_; + + // Indicates if doCommandBySelector method receives any edit command when + // handling a key down event. + BOOL hasEditCommands_; + + // Contains edit commands received by the -doCommandBySelector: method when + // handling a key down event, not including inserting commands, eg. insertTab, + // etc. + content::EditCommands editCommands_; + + CefRenderWidgetHostViewOSR* renderWidgetHostView_; +} + +@property(nonatomic, readonly) NSRange selectedRange; +@property(nonatomic) BOOL handlingKeyDown; + +- (id)initWithRenderWidgetHostViewOSR:(CefRenderWidgetHostViewOSR*) rwhv; +- (void)HandleKeyEventBeforeTextInputClient:(NSEvent*)keyEvent; +- (void)HandleKeyEventAfterTextInputClient:(NSEvent*)keyEvent; +- (void)cancelComposition; + +@end + +#endif // CEF_LIBCEF_BROWSER_TEXT_INPUT_CLIENT_OSR_MAC_H_ diff --git a/libcef/browser/text_input_client_osr_mac.mm b/libcef/browser/text_input_client_osr_mac.mm new file mode 100644 index 000000000..179f588ad --- /dev/null +++ b/libcef/browser/text_input_client_osr_mac.mm @@ -0,0 +1,359 @@ +// Copyright (c) 2013 The Chromium Embedded Framework 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 "libcef/browser/text_input_client_osr_mac.h" +#include "libcef/browser/browser_host_impl.h" + +#include "base/strings/sys_string_conversions.h" +#import "content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper.h" +#import "content/browser/renderer_host/text_input_client_mac.h" +#include "content/common/input_messages.h" + +namespace { + +// TODO(suzhe): Upstream this function. +blink::WebColor WebColorFromNSColor(NSColor *color) { + CGFloat r, g, b, a; + [color getRed:&r green:&g blue:&b alpha:&a]; + + return + std::max(0, std::min(static_cast(lroundf(255.0f * a)), 255)) << 24 | + std::max(0, std::min(static_cast(lroundf(255.0f * r)), 255)) << 16 | + std::max(0, std::min(static_cast(lroundf(255.0f * g)), 255)) << 8 | + std::max(0, std::min(static_cast(lroundf(255.0f * b)), 255)); +} + +// Extract underline information from an attributed string. Mostly copied from +// third_party/WebKit/Source/WebKit/mac/WebView/WebHTMLView.mm +void ExtractUnderlines(NSAttributedString* string, + std::vector* underlines) { + int length = [[string string] length]; + int i = 0; + while (i < length) { + NSRange range; + NSDictionary* attrs = [string attributesAtIndex:i + longestEffectiveRange:&range + inRange:NSMakeRange(i, length - i)]; + NSNumber *style = [attrs objectForKey: NSUnderlineStyleAttributeName]; + if (style) { + blink::WebColor color = SK_ColorBLACK; + if (NSColor *colorAttr = + [attrs objectForKey:NSUnderlineColorAttributeName]) { + color = WebColorFromNSColor( + [colorAttr colorUsingColorSpaceName:NSDeviceRGBColorSpace]); + } + underlines->push_back(blink::WebCompositionUnderline( + range.location, NSMaxRange(range), color, [style intValue] > 1)); + } + i = range.location + range.length; + } +} + +} // namespace + +extern "C" { + extern NSString* NSTextInputReplacementRangeAttributeName; +} + +@implementation CefTextInputClientOSRMac + +@synthesize selectedRange = selectedRange_; +@synthesize handlingKeyDown = handlingKeyDown_; + +- (id)initWithRenderWidgetHostViewOSR:(CefRenderWidgetHostViewOSR*)rwhv { + self = [super init]; + renderWidgetHostView_ = rwhv; + + return self; +} + +- (NSArray*)validAttributesForMarkedText { + if (!validAttributesForMarkedText_) { + validAttributesForMarkedText_.reset([[NSArray alloc] initWithObjects: + NSUnderlineStyleAttributeName, + NSUnderlineColorAttributeName, + NSMarkedClauseSegmentAttributeName, + NSTextInputReplacementRangeAttributeName, + nil]); + } + return validAttributesForMarkedText_.get(); +} + +- (NSRange)markedRange { + return hasMarkedText_ ? markedRange_ : NSMakeRange(NSNotFound, 0); +} + +- (BOOL)hasMarkedText { + return hasMarkedText_; +} + +- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange { + BOOL isAttributedString = [aString isKindOfClass:[NSAttributedString class]]; + NSString* im_text = isAttributedString ? [aString string] : aString; + if (handlingKeyDown_) { + textToBeInserted_.append(base::SysNSStringToUTF16(im_text)); + } else { + gfx::Range replacement_range(replacementRange); + + renderWidgetHostView_->render_widget_host()->ImeConfirmComposition( + base::SysNSStringToUTF16(im_text), replacement_range, false); + } + + // Inserting text will delete all marked text automatically. + hasMarkedText_ = NO; +} + +- (void)doCommandBySelector:(SEL)aSelector { + // An input method calls this function to dispatch an editing command to be + // handled by this view. + if (aSelector == @selector(noop:)) + return; + std::string command([content::RenderWidgetHostViewMacEditCommandHelper:: + CommandNameForSelector(aSelector) UTF8String]); + + // If this method is called when handling a key down event, then we need to + // handle the command in the key event handler. Otherwise we can just handle + // it here. + if (handlingKeyDown_) { + hasEditCommands_ = YES; + // We ignore commands that insert characters, because this was causing + // strange behavior (e.g. tab always inserted a tab rather than moving to + // the next field on the page). + if (!StartsWithASCII(command, "insert", false)) + editCommands_.push_back(content::EditCommand(command, "")); + } else { + renderWidgetHostView_->render_widget_host()->Send( + new InputMsg_ExecuteEditCommand( + renderWidgetHostView_->render_widget_host()->GetRoutingID(), + command, "")); + } +} + +- (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelRange + replacementRange:(NSRange)replacementRange { + // An input method updates the composition string. + // We send the given text and range to the renderer so it can update the + // composition node of WebKit. + + BOOL isAttributedString = [aString isKindOfClass:[NSAttributedString class]]; + NSString* im_text = isAttributedString ? [aString string] : aString; + int length = [im_text length]; + + // |markedRange_| will get set on a callback from ImeSetComposition(). + selectedRange_ = newSelRange; + markedText_ = base::SysNSStringToUTF16(im_text); + hasMarkedText_ = (length > 0); + underlines_.clear(); + + if (isAttributedString) { + ExtractUnderlines(aString, &underlines_); + } else { + // Use a thin black underline by default. + underlines_.push_back(blink::WebCompositionUnderline(0, length, + SK_ColorBLACK, false)); + } + + // If we are handling a key down event, then SetComposition() will be + // called in keyEvent: method. + // Input methods of Mac use setMarkedText calls with an empty text to cancel + // an ongoing composition. So, we should check whether or not the given text + // is empty to update the input method state. (Our input method backend can + // automatically cancels an ongoing composition when we send an empty text. + // So, it is OK to send an empty text to the renderer.) + if (!handlingKeyDown_) { + renderWidgetHostView_->render_widget_host()->ImeSetComposition( + markedText_, underlines_, newSelRange.location, + NSMaxRange(newSelRange)); + } +} + +- (void)unmarkText { + // Delete the composition node of the renderer and finish an ongoing + // composition. + // It seems an input method calls the setMarkedText method and set an empty + // text when it cancels an ongoing composition, i.e. I have never seen an + // input method calls this method. + hasMarkedText_ = NO; + markedText_.clear(); + underlines_.clear(); + + // If we are handling a key down event, then ConfirmComposition() will be + // called in keyEvent: method. + if (!handlingKeyDown_) { + renderWidgetHostView_->render_widget_host()->ImeConfirmComposition( + base::string16(), gfx::Range::InvalidRange(), false); + } else { + unmarkTextCalled_ = YES; + } +} + +- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range + actualRange:(NSRangePointer)actualRange { + if (actualRange) + *actualRange = range; + NSAttributedString* str = content::TextInputClientMac::GetInstance()-> + GetAttributedSubstringFromRange( + renderWidgetHostView_->GetRenderWidgetHost(), range); + return str; +} + +- (NSRect)firstViewRectForCharacterRange:(NSRange)theRange + actualRange:(NSRangePointer)actualRange { + NSRect rect; + gfx::Rect gfxRect; + gfx::Range range(theRange); + gfx::Range actual_range; + if (!renderWidgetHostView_->GetCachedFirstRectForCharacterRange(range, + &gfxRect, &actual_range)) { + rect = content::TextInputClientMac::GetInstance()-> + GetFirstRectForRange(renderWidgetHostView_->GetRenderWidgetHost(), + range.ToNSRange()); + + if (actualRange) + *actualRange = range.ToNSRange(); + } else { + rect = NSRectFromCGRect(gfxRect.ToCGRect()); + } + + return rect; +} + +- (NSRect) screenRectFromViewRect:(NSRect)rect { + NSRect screenRect; + + int screenX, screenY; + renderWidgetHostView_->browser_impl()->GetClient()->GetRenderHandler()-> + GetScreenPoint(renderWidgetHostView_->browser_impl()->GetBrowser(), + rect.origin.x, rect.origin.y, screenX, screenY); + screenRect.origin = NSMakePoint(screenX, screenY); + screenRect.size = rect.size; + + return screenRect; +} + +- (NSRect)firstRectForCharacterRange:(NSRange)theRange + actualRange:(NSRangePointer)actualRange { + NSRect rect = [self firstViewRectForCharacterRange:theRange + actualRange:actualRange]; + + // Convert into screen coordinates for return. + rect = [self screenRectFromViewRect:rect]; + + if (rect.origin.y >= rect.size.height) + rect.origin.y -= rect.size.height; + else + rect.origin.y = 0; + + return rect; +} + +- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint { + // |thePoint| is in screen coordinates, but needs to be converted to WebKit + // coordinates (upper left origin). Scroll offsets will be taken care of in + // the renderer. + + CefRect view_rect; + renderWidgetHostView_->browser_impl()->GetClient()->GetRenderHandler()-> + GetViewRect(renderWidgetHostView_->browser_impl()->GetBrowser(), + view_rect); + + thePoint.x -= view_rect.x; + thePoint.y -= view_rect.y; + thePoint.y = view_rect.height - thePoint.y; + + NSUInteger index = content::TextInputClientMac::GetInstance()-> + GetCharacterIndexAtPoint(renderWidgetHostView_->GetRenderWidgetHost(), + gfx::Point(thePoint.x, thePoint.y)); + return index; +} + +- (void)HandleKeyEventBeforeTextInputClient:(NSEvent*)keyEvent { + DCHECK([keyEvent type] == NSKeyDown); + // Don't call this method recursively. + DCHECK(!handlingKeyDown_); + + oldHasMarkedText_ = hasMarkedText_; + handlingKeyDown_ = YES; + + // These variables might be set when handling the keyboard event. + // Clear them here so that we can know whether they have changed afterwards. + textToBeInserted_.clear(); + markedText_.clear(); + underlines_.clear(); + unmarkTextCalled_ = NO; + hasEditCommands_ = NO; + editCommands_.clear(); +} + +- (void)HandleKeyEventAfterTextInputClient:(NSEvent*)keyEvent { + handlingKeyDown_ = NO; + + // Then send keypress and/or composition related events. + // If there was a marked text or the text to be inserted is longer than 1 + // character, then we send the text by calling ConfirmComposition(). + // Otherwise, if the text to be inserted only contains 1 character, then we + // can just send a keypress event which is fabricated by changing the type of + // the keydown event, so that we can retain all necessary informations, such + // as unmodifiedText, etc. And we need to set event.skip_in_browser to true to + // prevent the browser from handling it again. + // Note that, |textToBeInserted_| is a UTF-16 string, but it's fine to only + // handle BMP characters here, as we can always insert non-BMP characters as + // text. + + if (!hasMarkedText_ && !oldHasMarkedText_ && + textToBeInserted_.length() <= 1) { + content::NativeWebKeyboardEvent event(keyEvent); + if (textToBeInserted_.length() == 1) { + event.type = blink::WebInputEvent::Type::Char; + event.text[0] = textToBeInserted_[0]; + event.text[1] = 0; + } + renderWidgetHostView_->SendKeyEvent(event); + } + + BOOL textInserted = NO; + if (textToBeInserted_.length() > + ((hasMarkedText_ || oldHasMarkedText_) ? 0u : 1u)) { + renderWidgetHostView_->render_widget_host()->ImeConfirmComposition( + textToBeInserted_, gfx::Range::InvalidRange(), false); + textToBeInserted_ = YES; + } + + // Updates or cancels the composition. If some text has been inserted, then + // we don't need to cancel the composition explicitly. + if (hasMarkedText_ && markedText_.length()) { + // Sends the updated marked text to the renderer so it can update the + // composition node in WebKit. + // When marked text is available, |selectedRange_| will be the range being + // selected inside the marked text. + renderWidgetHostView_->render_widget_host()->ImeSetComposition( + markedText_, underlines_, selectedRange_.location, + NSMaxRange(selectedRange_)); + } else if (oldHasMarkedText_ && !hasMarkedText_ && !textInserted) { + if (unmarkTextCalled_) { + renderWidgetHostView_->render_widget_host()->ImeConfirmComposition( + base::string16(), gfx::Range::InvalidRange(), false); + } else { + renderWidgetHostView_->render_widget_host()->ImeCancelComposition(); + } + } +} + +- (void)cancelComposition { + if (!hasMarkedText_) + return; + + // Cancel the ongoing composition. [NSInputManager markedTextAbandoned:] + // doesn't call any NSTextInput functions, such as setMarkedText or + // insertText. So, we need to send an IPC message to a renderer so it can + // delete the composition node. + NSInputManager *currentInputManager = [NSInputManager currentInputManager]; + [currentInputManager markedTextAbandoned:self]; + + hasMarkedText_ = NO; + // Should not call [self unmarkText] here, because it'll send unnecessary + // cancel composition IPC message to the renderer. +} + +@end diff --git a/libcef/browser/web_contents_view_osr.cc b/libcef/browser/web_contents_view_osr.cc new file mode 100644 index 000000000..673b112c3 --- /dev/null +++ b/libcef/browser/web_contents_view_osr.cc @@ -0,0 +1,167 @@ +// Copyright (c) 2014 The Chromium Embedded Framework Authors. +// Portions 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 "libcef/browser/web_contents_view_osr.h" +#include "libcef/browser/browser_host_impl.h" +#include "libcef/browser/render_widget_host_view_osr.h" +#include "libcef/common/drag_data_impl.h" + +#include "content/public/browser/render_widget_host.h" + +CefWebContentsViewOSR::CefWebContentsViewOSR( + content::WebContents* web_contents, + content::WebContentsViewDelegate* delegate) + : web_contents_(web_contents), + view_(NULL) { +} + +CefWebContentsViewOSR::~CefWebContentsViewOSR() { +} + +gfx::NativeView CefWebContentsViewOSR::GetNativeView() const { + return gfx::NativeView(); +} + +gfx::NativeView CefWebContentsViewOSR::GetContentNativeView() const { + return gfx::NativeView(); +} + +gfx::NativeWindow CefWebContentsViewOSR::GetTopLevelNativeWindow() const { + return gfx::NativeWindow(); +} + +void CefWebContentsViewOSR::GetContainerBounds(gfx::Rect* out) const { + *out = GetViewBounds(); +} + +void CefWebContentsViewOSR::SizeContents(const gfx::Size& size) { +} + +void CefWebContentsViewOSR::Focus() { +} + +void CefWebContentsViewOSR::SetInitialFocus() { +} + +void CefWebContentsViewOSR::StoreFocus() { +} + +void CefWebContentsViewOSR::RestoreFocus() { +} + +content::DropData* CefWebContentsViewOSR::GetDropData() const { + return NULL; +} + +gfx::Rect CefWebContentsViewOSR::GetViewBounds() const { + return view_ ? view_->GetViewBounds() : gfx::Rect(); +} + +void CefWebContentsViewOSR::CreateView(const gfx::Size& initial_size, + gfx::NativeView context) { +} + +content::RenderWidgetHostViewBase* CefWebContentsViewOSR::CreateViewForWidget( + content::RenderWidgetHost* render_widget_host) { + if (render_widget_host->GetView()) { + return static_cast( + render_widget_host->GetView()); + } + + view_ = new CefRenderWidgetHostViewOSR(render_widget_host); + return view_; +} + +content::RenderWidgetHostViewBase* + CefWebContentsViewOSR::CreateViewForPopupWidget( + content::RenderWidgetHost* render_widget_host) { + return new CefRenderWidgetHostViewOSR(render_widget_host); +} + +void CefWebContentsViewOSR::SetPageTitle(const base::string16& title) { +} + +void CefWebContentsViewOSR::RenderViewCreated(content::RenderViewHost* host) { + if (view_) + view_->InstallTransparency(); +} + +void CefWebContentsViewOSR::RenderViewSwappedIn( + content::RenderViewHost* host) { +} + +void CefWebContentsViewOSR::SetOverscrollControllerEnabled(bool enabled) { +} + +#if defined(OS_MACOSX) +void CefWebContentsViewOSR::SetAllowOverlappingViews(bool overlapping) { +} + +bool CefWebContentsViewOSR::GetAllowOverlappingViews() const { + return false; +} + +void CefWebContentsViewOSR::SetOverlayView( + content::WebContentsView* overlay, + const gfx::Point& offset) { +} +void CefWebContentsViewOSR::RemoveOverlayView() { +} + +bool CefWebContentsViewOSR::IsEventTracking() const { + return false; +} + +void CefWebContentsViewOSR::CloseTabAfterEventTracking() { +} +#endif // defined(OS_MACOSX) + +void CefWebContentsViewOSR::StartDragging( + const content::DropData& drop_data, + blink::WebDragOperationsMask allowed_ops, + const gfx::ImageSkia& image, + const gfx::Vector2d& image_offset, + const content::DragEventSourceInfo& event_info) { + CefRefPtr browser; + CefRefPtr handler; + bool handled = false; + CefRenderWidgetHostViewOSR* view = + static_cast(view_); + if (view) + browser = view->browser_impl(); + if (browser.get()) + handler = browser->GetClient()->GetRenderHandler(); + DCHECK(handler.get()); + if (handler.get()) { + CefRefPtr drag_data(new CefDragDataImpl(drop_data)); + drag_data->SetReadOnly(true); + base::MessageLoop::ScopedNestableTaskAllower allow( + base::MessageLoop::current()); + handled = handler->StartDragging(browser->GetBrowser(), + drag_data.get(), + static_cast(allowed_ops), + event_info.event_location.x(), + event_info.event_location.y()); + } + if (!handled && web_contents_) + web_contents_->SystemDragEnded(); +} + +void CefWebContentsViewOSR::UpdateDragCursor( + blink::WebDragOperation operation) { + CefRefPtr browser; + CefRefPtr handler; + CefRenderWidgetHostViewOSR* view = + static_cast(view_); + if (view) + browser = view->browser_impl(); + if (browser.get()) + handler = browser->GetClient()->GetRenderHandler(); + DCHECK(handler.get()); + if (handler.get()) { + handler->UpdateDragCursor(browser->GetBrowser(), + static_cast(operation)); + } +} diff --git a/libcef/browser/web_contents_view_osr.h b/libcef/browser/web_contents_view_osr.h new file mode 100644 index 000000000..a6f0431af --- /dev/null +++ b/libcef/browser/web_contents_view_osr.h @@ -0,0 +1,76 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2011 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. + +#ifndef CEF_LIBCEF_BROWSER_WEB_CONTENTS_VIEW_OSR_H_ +#define CEF_LIBCEF_BROWSER_WEB_CONTENTS_VIEW_OSR_H_ + +#include "content/browser/renderer_host/render_view_host_delegate_view.h" +#include "content/browser/web_contents/web_contents_view.h" + +namespace content { +class WebContents; +class WebContentsViewDelegate; +} + +class CefRenderWidgetHostViewOSR; + +// An implementation of WebContentsView for off-screen rendering. +class CefWebContentsViewOSR : public content::WebContentsView, + public content::RenderViewHostDelegateView { + public: + CefWebContentsViewOSR(content::WebContents* web_contents, + content::WebContentsViewDelegate* delegate); + virtual ~CefWebContentsViewOSR(); + + // WebContentsView methods. + virtual gfx::NativeView GetNativeView() const OVERRIDE; + virtual gfx::NativeView GetContentNativeView() const OVERRIDE; + virtual gfx::NativeWindow GetTopLevelNativeWindow() const OVERRIDE; + virtual void GetContainerBounds(gfx::Rect* out) const OVERRIDE; + virtual void SizeContents(const gfx::Size& size) OVERRIDE; + virtual void Focus() OVERRIDE; + virtual void SetInitialFocus() OVERRIDE; + virtual void StoreFocus() OVERRIDE; + virtual void RestoreFocus() OVERRIDE; + virtual content::DropData* GetDropData() const OVERRIDE; + virtual gfx::Rect GetViewBounds() const OVERRIDE; + virtual void CreateView(const gfx::Size& initial_size, + gfx::NativeView context) OVERRIDE; + virtual content::RenderWidgetHostViewBase* CreateViewForWidget( + content::RenderWidgetHost* render_widget_host) OVERRIDE; + virtual content::RenderWidgetHostViewBase* CreateViewForPopupWidget( + content::RenderWidgetHost* render_widget_host) OVERRIDE; + virtual void SetPageTitle(const base::string16& title) OVERRIDE; + virtual void RenderViewCreated(content::RenderViewHost* host) OVERRIDE; + virtual void RenderViewSwappedIn(content::RenderViewHost* host) OVERRIDE; + virtual void SetOverscrollControllerEnabled(bool enabled) OVERRIDE; + +#if defined(OS_MACOSX) + virtual void SetAllowOverlappingViews(bool overlapping) OVERRIDE; + virtual bool GetAllowOverlappingViews() const OVERRIDE; + virtual void SetOverlayView(content::WebContentsView* overlay, + const gfx::Point& offset) OVERRIDE; + virtual void RemoveOverlayView() OVERRIDE; + virtual bool IsEventTracking() const OVERRIDE; + virtual void CloseTabAfterEventTracking() OVERRIDE; +#endif + + // RenderViewHostDelegateView methods. + virtual void StartDragging( + const content::DropData& drop_data, + blink::WebDragOperationsMask allowed_ops, + const gfx::ImageSkia& image, + const gfx::Vector2d& image_offset, + const content::DragEventSourceInfo& event_info) OVERRIDE; + virtual void UpdateDragCursor(blink::WebDragOperation operation) OVERRIDE; + + private: + content::WebContents* web_contents_; + CefRenderWidgetHostViewOSR* view_; + + DISALLOW_COPY_AND_ASSIGN(CefWebContentsViewOSR); +}; + +#endif // CEF_LIBCEF_BROWSER_WEB_CONTENTS_VIEW_OSR_H_ diff --git a/libcef/browser/window_x11.cc b/libcef/browser/window_x11.cc index 20ba5523e..cb25d7690 100644 --- a/libcef/browser/window_x11.cc +++ b/libcef/browser/window_x11.cc @@ -173,10 +173,14 @@ void CefWindowX11::Focus() { if (xwindow_ == None || !window_mapped_) return; - ::Window child = FindChild(xdisplay_, xwindow_); - if (child && ui::IsWindowVisible(child)) { - // Give focus to the child DesktopWindowTreeHostX11. - XSetInputFocus(xdisplay_, child, RevertToParent, CurrentTime); + if (browser_) { + ::Window child = FindChild(xdisplay_, xwindow_); + if (child && ui::IsWindowVisible(child)) { + // Give focus to the child DesktopWindowTreeHostX11. + XSetInputFocus(xdisplay_, child, RevertToParent, CurrentTime); + } + } else { + XSetInputFocus(xdisplay_, xwindow_, RevertToParent, CurrentTime); } } @@ -233,13 +237,15 @@ uint32_t CefWindowX11::DispatchEvent(const ui::PlatformEvent& event) { xev->xconfigure.width, xev->xconfigure.height); bounds_ = bounds; - ::Window child = FindChild(xdisplay_, xwindow_); - if (child) { - // Resize the child DesktopWindowTreeHostX11 to match this window. - XWindowChanges changes = {0}; - changes.width = bounds.width(); - changes.height = bounds.height(); - XConfigureWindow(xdisplay_, child, CWHeight | CWWidth, &changes); + if (browser_) { + ::Window child = FindChild(xdisplay_, xwindow_); + if (child) { + // Resize the child DesktopWindowTreeHostX11 to match this window. + XWindowChanges changes = {0}; + changes.width = bounds.width(); + changes.height = bounds.height(); + XConfigureWindow(xdisplay_, child, CWHeight | CWWidth, &changes); + } } break; } @@ -247,7 +253,7 @@ uint32_t CefWindowX11::DispatchEvent(const ui::PlatformEvent& event) { Atom message_type = static_cast(xev->xclient.data.l[0]); if (message_type == atom_cache_.GetAtom("WM_DELETE_WINDOW")) { // We have received a close message from the window manager. - if (browser_->destruction_state() <= + if (browser_ && browser_->destruction_state() <= CefBrowserHostImpl::DESTRUCTION_STATE_PENDING) { if (browser_->destruction_state() == CefBrowserHostImpl::DESTRUCTION_STATE_NONE) { @@ -276,9 +282,11 @@ uint32_t CefWindowX11::DispatchEvent(const ui::PlatformEvent& event) { case DestroyNotify: xwindow_ = None; - // Force the browser to be destroyed and release the reference added - // in PlatformCreateWindow(). - browser_->WindowDestroyed(); + if (browser_) { + // Force the browser to be destroyed and release the reference added + // in PlatformCreateWindow(). + browser_->WindowDestroyed(); + } delete this; break; @@ -311,8 +319,7 @@ uint32_t CefWindowX11::DispatchEvent(const ui::PlatformEvent& event) { void CefWindowX11::ContinueFocus() { if (!focus_pending_) return; - browser_->SetFocus(true); + if (browser_) + browser_->SetFocus(true); focus_pending_ = false; } - - diff --git a/libcef/common/cef_messages.h b/libcef/common/cef_messages.h index 1feaa751f..a7fb14b52 100644 --- a/libcef/common/cef_messages.h +++ b/libcef/common/cef_messages.h @@ -151,6 +151,7 @@ IPC_SYNC_MESSAGE_CONTROL0_1( IPC_STRUCT_BEGIN(CefProcessHostMsg_GetNewBrowserInfo_Params) IPC_STRUCT_MEMBER(int, browser_id) IPC_STRUCT_MEMBER(bool, is_popup) + IPC_STRUCT_MEMBER(bool, is_windowless) IPC_STRUCT_END() // Retrieve information about a newly created browser. diff --git a/libcef/common/drag_data_impl.cc b/libcef/common/drag_data_impl.cc index 8251f5a37..ccb7cb1d6 100644 --- a/libcef/common/drag_data_impl.cc +++ b/libcef/common/drag_data_impl.cc @@ -2,55 +2,127 @@ // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. +#include + +#include "libcef/browser/stream_impl.h" #include "libcef/common/drag_data_impl.h" #include "base/files/file_path.h" +#include "net/base/filename_util.h" +#include "net/base/net_util.h" + +#define CHECK_READONLY_RETURN_VOID() \ + if (read_only_) { \ + NOTREACHED() << "object is read only"; \ + return; \ + } CefDragDataImpl::CefDragDataImpl(const content::DropData& data) - : data_(data) { + : data_(data), + read_only_(false) { +} + +CefDragDataImpl::CefDragDataImpl() + : read_only_(false) { +} + +CefRefPtr CefDragData::Create() { + return new CefDragDataImpl(); +} + +CefRefPtr CefDragDataImpl::Clone() { + CefDragDataImpl* drag_data = NULL; + { + AutoLock lock_scope(this); + drag_data = new CefDragDataImpl(data_); + } + return drag_data; +} + +bool CefDragDataImpl::IsReadOnly() { + AutoLock lock_scope(this); + return read_only_; } bool CefDragDataImpl::IsLink() { + AutoLock lock_scope(this); return (data_.url.is_valid() && data_.file_description_filename.empty()); } bool CefDragDataImpl::IsFragment() { + AutoLock lock_scope(this); return (!data_.url.is_valid() && data_.file_description_filename.empty() && data_.filenames.empty()); } bool CefDragDataImpl::IsFile() { + AutoLock lock_scope(this); return (!data_.file_description_filename.empty() || !data_.filenames.empty()); } CefString CefDragDataImpl::GetLinkURL() { + AutoLock lock_scope(this); return data_.url.spec(); } CefString CefDragDataImpl::GetLinkTitle() { + AutoLock lock_scope(this); return data_.url_title; } CefString CefDragDataImpl::GetLinkMetadata() { + AutoLock lock_scope(this); return data_.download_metadata; } CefString CefDragDataImpl::GetFragmentText() { + AutoLock lock_scope(this); return data_.text.is_null() ? CefString() : CefString(data_.text.string()); } CefString CefDragDataImpl::GetFragmentHtml() { + AutoLock lock_scope(this); return data_.html.is_null() ? CefString() : CefString(data_.html.string()); } CefString CefDragDataImpl::GetFragmentBaseURL() { + AutoLock lock_scope(this); return data_.html_base_url.spec(); } CefString CefDragDataImpl::GetFileName() { - return data_.file_description_filename; + AutoLock lock_scope(this); + if (data_.file_description_filename.empty()) + return CefString(); + + base::FilePath file_name(CefString(data_.file_description_filename)); + // Images without ALT text will only have a file extension so we need to + // synthesize one from the provided extension and URL. + if (file_name.BaseName().RemoveExtension().empty()) { + CefString extension = file_name.Extension(); + // Retrieve the name from the URL. + CefString suggested_file_name = + net::GetSuggestedFilename(data_.url, "", "", "", "", ""); + file_name = base::FilePath(suggested_file_name).ReplaceExtension(extension); + } + return file_name.value(); +} + +size_t CefDragDataImpl::GetFileContents(CefRefPtr writer) { + AutoLock lock_scope(this); + if (data_.file_contents.empty()) + return 0; + + char* data = const_cast(data_.file_contents.c_str()); + size_t size = data_.file_contents.size(); + + if (!writer.get()) + return size; + + return writer->Write(data, 1, size); } bool CefDragDataImpl::GetFileNames(std::vector& names) { + AutoLock lock_scope(this); if (data_.filenames.empty()) return false; @@ -61,3 +133,62 @@ bool CefDragDataImpl::GetFileNames(std::vector& names) { return true; } + +void CefDragDataImpl::SetLinkURL(const CefString& url) { + AutoLock lock_scope(this); + CHECK_READONLY_RETURN_VOID(); + data_.url = GURL(url.ToString()); +} + +void CefDragDataImpl::SetLinkTitle(const CefString& title) { + AutoLock lock_scope(this); + CHECK_READONLY_RETURN_VOID(); + data_.url_title = title.ToString16(); +} + +void CefDragDataImpl::SetLinkMetadata(const CefString& data) { + AutoLock lock_scope(this); + CHECK_READONLY_RETURN_VOID(); + data_.download_metadata = data.ToString16(); +} + +void CefDragDataImpl::SetFragmentText(const CefString& text) { + AutoLock lock_scope(this); + CHECK_READONLY_RETURN_VOID(); + data_.text = base::NullableString16(text.ToString16(), false); +} + +void CefDragDataImpl::SetFragmentHtml(const CefString& fragment) { + AutoLock lock_scope(this); + CHECK_READONLY_RETURN_VOID(); + data_.html = base::NullableString16(fragment.ToString16(), false); +} + +void CefDragDataImpl::SetFragmentBaseURL(const CefString& fragment) { + AutoLock lock_scope(this); + CHECK_READONLY_RETURN_VOID(); + data_.html_base_url = GURL(fragment.ToString()); +} + +void CefDragDataImpl::ResetFileContents() { + AutoLock lock_scope(this); + CHECK_READONLY_RETURN_VOID(); + data_.file_contents.erase(); + data_.file_description_filename.erase(); +} + +void CefDragDataImpl::AddFile(const CefString& path, + const CefString& display_name) { + AutoLock lock_scope(this); + CHECK_READONLY_RETURN_VOID(); + data_.filenames.push_back(ui::FileInfo(base::FilePath(path), + base::FilePath(display_name))); +} + +void CefDragDataImpl::SetReadOnly(bool read_only) { + AutoLock lock_scope(this); + if (read_only_ == read_only) + return; + + read_only_ = read_only; +} diff --git a/libcef/common/drag_data_impl.h b/libcef/common/drag_data_impl.h index 17bbd1493..21717478d 100644 --- a/libcef/common/drag_data_impl.h +++ b/libcef/common/drag_data_impl.h @@ -14,7 +14,10 @@ // Implementation of CefDragData. class CefDragDataImpl : public CefDragData { public: + CefDragDataImpl(); explicit CefDragDataImpl(const content::DropData& data); + virtual CefRefPtr Clone(); + virtual bool IsReadOnly(); virtual bool IsLink(); virtual bool IsFragment(); @@ -26,12 +29,33 @@ class CefDragDataImpl : public CefDragData { virtual CefString GetFragmentHtml(); virtual CefString GetFragmentBaseURL(); virtual CefString GetFileName(); + virtual size_t GetFileContents(CefRefPtr writer); virtual bool GetFileNames(std::vector& names); + virtual void SetLinkURL(const CefString& url); + virtual void SetLinkTitle(const CefString& title); + virtual void SetLinkMetadata(const CefString& data); + virtual void SetFragmentText(const CefString& text); + virtual void SetFragmentHtml(const CefString& fragment); + virtual void SetFragmentBaseURL(const CefString& fragment); + virtual void ResetFileContents(); + virtual void AddFile(const CefString& path, const CefString& display_name); + + // This method is not safe. Use Lock/Unlock to get mutually exclusive access. + const content::DropData& drop_data() { + return data_; + } + + void SetReadOnly(bool read_only); + protected: content::DropData data_; + // True if this object is read-only. + bool read_only_; + IMPLEMENT_REFCOUNTING(CefDragDataImpl); + IMPLEMENT_LOCKING(CefDragDataImpl); }; #endif // CEF_LIBCEF_COMMON_DRAG_DATA_IMPL_H_ diff --git a/libcef/common/main_delegate.cc b/libcef/common/main_delegate.cc index 4c3257121..f3c38f252 100644 --- a/libcef/common/main_delegate.cc +++ b/libcef/common/main_delegate.cc @@ -288,6 +288,13 @@ bool CefMainDelegate::BasicStartupComplete(int* exit_code) { command_line->AppendSwitchASCII(switches::kContextSafetyImplementation, base::IntToString(settings.context_safety_implementation)); } + + if (settings.windowless_rendering_enabled) { +#if defined(OS_MACOSX) + // The delegated renderer is not yet enabled by default on OS X. + command_line->AppendSwitch(switches::kEnableDelegatedRenderer); +#endif + } } if (content_client_.application().get()) { diff --git a/libcef/renderer/browser_impl.cc b/libcef/renderer/browser_impl.cc index c95c60cc8..035365844 100644 --- a/libcef/renderer/browser_impl.cc +++ b/libcef/renderer/browser_impl.cc @@ -268,10 +268,12 @@ bool CefBrowserImpl::SendProcessMessage(CefProcessId target_process, CefBrowserImpl::CefBrowserImpl(content::RenderView* render_view, int browser_id, - bool is_popup) + bool is_popup, + bool is_windowless) : content::RenderViewObserver(render_view), browser_id_(browser_id), is_popup_(is_popup), + is_windowless_(is_windowless), last_focused_frame_id_(webkit_glue::kInvalidFrameId) { response_manager_.reset(new CefResponseManager); } diff --git a/libcef/renderer/browser_impl.h b/libcef/renderer/browser_impl.h index d1fb40e03..fd3c26c55 100644 --- a/libcef/renderer/browser_impl.h +++ b/libcef/renderer/browser_impl.h @@ -75,7 +75,8 @@ class CefBrowserImpl : public CefBrowser, CefBrowserImpl(content::RenderView* render_view, int browser_id, - bool is_popup); + bool is_popup, + bool is_windowless); virtual ~CefBrowserImpl(); void LoadRequest(const CefMsg_LoadRequest_Params& params); @@ -95,6 +96,7 @@ class CefBrowserImpl : public CefBrowser, int browser_id() const { return browser_id_; } bool is_popup() const { return is_popup_; } + bool is_windowless() const { return is_windowless_; } content::RenderView* render_view() const { return content::RenderViewObserver::render_view(); } @@ -137,6 +139,7 @@ class CefBrowserImpl : public CefBrowser, // same browser ID. int browser_id_; bool is_popup_; + bool is_windowless_; // Id of the last frame that had focus. int64 last_focused_frame_id_; diff --git a/libcef/renderer/content_renderer_client.cc b/libcef/renderer/content_renderer_client.cc index b303d5237..d14444ba7 100644 --- a/libcef/renderer/content_renderer_client.cc +++ b/libcef/renderer/content_renderer_client.cc @@ -54,6 +54,7 @@ MSVC_POP_WARNING(); #include "third_party/WebKit/public/platform/WebWorkerRunLoop.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebFrame.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebKit.h" #include "third_party/WebKit/public/web/WebPluginParams.h" #include "third_party/WebKit/public/web/WebPrerendererClient.h" @@ -434,6 +435,90 @@ void CefContentRendererClient::RenderViewCreated( BrowserCreated(render_view, render_view->GetMainRenderFrame()); } +bool CefContentRendererClient::OverrideCreatePlugin( + content::RenderFrame* render_frame, + blink::WebLocalFrame* frame, + const blink::WebPluginParams& params, + blink::WebPlugin** plugin) { + CefRefPtr browser = + CefBrowserImpl::GetBrowserForMainFrame(frame->top()); + if (!browser || !browser->is_windowless()) + return false; + +#if defined(ENABLE_PLUGINS) + if (base::UTF16ToASCII(params.mimeType) == content::kBrowserPluginMimeType) + return false; + + content::RenderFrameImpl* render_frame_impl = + static_cast(render_frame); + + content::WebPluginInfo info; + std::string mime_type; + bool found = false; + render_frame_impl->Send( + new FrameHostMsg_GetPluginInfo( + render_frame_impl->GetRoutingID(), + params.url, + frame->top()->document().url(), + params.mimeType.utf8(), + &found, + &info, + &mime_type)); + if (!found) + return false; + + bool flash = LowerCaseEqualsASCII(mime_type, + "application/x-shockwave-flash"); + bool silverlight = StartsWithASCII(mime_type, + "application/x-silverlight", false); + + if (flash) { + // "wmode" values of "opaque" or "transparent" are allowed. + size_t size = params.attributeNames.size(); + for (size_t i = 0; i < size; ++i) { + std::string name = params.attributeNames[i].utf8(); + if (name == "wmode") { + std::string value = params.attributeValues[i].utf8(); + if (value == "opaque" || value == "transparent") + flash = false; + break; + } + } + } + + if (flash || silverlight) { + // Force Flash and Silverlight plugins to use windowless mode. + blink::WebPluginParams params_to_use = params; + params_to_use.mimeType = blink::WebString::fromUTF8(mime_type); + + size_t size = params.attributeNames.size(); + blink::WebVector new_names(size+1), + new_values(size+1); + + for (size_t i = 0; i < size; ++i) { + new_names[i] = params.attributeNames[i]; + new_values[i] = params.attributeValues[i]; + } + + if (flash) { + new_names[size] = "wmode"; + new_values[size] = "opaque"; + } else if (silverlight) { + new_names[size] = "windowless"; + new_values[size] = "true"; + } + + params_to_use.attributeNames.swap(new_names); + params_to_use.attributeValues.swap(new_values); + + *plugin = render_frame_impl->CreatePlugin(frame, info, params_to_use); + return true; + } +#endif // defined(ENABLE_PLUGINS) + + return false; +} + bool CefContentRendererClient::HandleNavigation( content::RenderFrame* render_frame, content::DocumentState* document_state, @@ -578,8 +663,18 @@ void CefContentRendererClient::BrowserCreated( if (GetBrowserForView(render_view)) return; +#if defined(OS_MACOSX) + // FIXME: It would be better if this API would be a callback from the + // WebKit layer, or if it would be exposed as an WebView instance method; the + // current implementation uses a static variable, and WebKit needs to be + // patched in order to make it work for each WebView instance + render_view->GetWebView()->setUseExternalPopupMenusThisInstance( + !params.is_windowless); +#endif + CefRefPtr browser = - new CefBrowserImpl(render_view, params.browser_id, params.is_popup); + new CefBrowserImpl(render_view, params.browser_id, params.is_popup, + params.is_windowless); browsers_.insert(std::make_pair(render_view, browser)); new CefPrerendererClient(render_view); diff --git a/libcef/renderer/content_renderer_client.h b/libcef/renderer/content_renderer_client.h index 105f1374e..453dc8c52 100644 --- a/libcef/renderer/content_renderer_client.h +++ b/libcef/renderer/content_renderer_client.h @@ -76,6 +76,11 @@ class CefContentRendererClient : public content::ContentRendererClient, virtual void RenderThreadStarted() OVERRIDE; virtual void RenderFrameCreated(content::RenderFrame* render_frame) OVERRIDE; virtual void RenderViewCreated(content::RenderView* render_view) OVERRIDE; + virtual bool OverrideCreatePlugin( + content::RenderFrame* render_frame, + blink::WebLocalFrame* frame, + const blink::WebPluginParams& params, + blink::WebPlugin** plugin) OVERRIDE; virtual bool HandleNavigation(content::RenderFrame* render_frame, content::DocumentState* document_state, int opener_id, diff --git a/libcef_dll/cpptoc/browser_host_cpptoc.cc b/libcef_dll/cpptoc/browser_host_cpptoc.cc index d32a1eb54..2124e40f5 100644 --- a/libcef_dll/cpptoc/browser_host_cpptoc.cc +++ b/libcef_dll/cpptoc/browser_host_cpptoc.cc @@ -12,6 +12,7 @@ #include "libcef_dll/cpptoc/browser_cpptoc.h" #include "libcef_dll/cpptoc/browser_host_cpptoc.h" +#include "libcef_dll/cpptoc/drag_data_cpptoc.h" #include "libcef_dll/cpptoc/request_context_cpptoc.h" #include "libcef_dll/ctocpp/client_ctocpp.h" #include "libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h" @@ -410,6 +411,70 @@ int CEF_CALLBACK browser_host_is_mouse_cursor_change_disabled( return _retval; } +int CEF_CALLBACK browser_host_is_window_rendering_disabled( + struct _cef_browser_host_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + + // Execute + bool _retval = CefBrowserHostCppToC::Get(self)->IsWindowRenderingDisabled(); + + // Return type: bool + return _retval; +} + +void CEF_CALLBACK browser_host_was_resized(struct _cef_browser_host_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefBrowserHostCppToC::Get(self)->WasResized(); +} + +void CEF_CALLBACK browser_host_was_hidden(struct _cef_browser_host_t* self, + int hidden) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefBrowserHostCppToC::Get(self)->WasHidden( + hidden?true:false); +} + +void CEF_CALLBACK browser_host_notify_screen_info_changed( + struct _cef_browser_host_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefBrowserHostCppToC::Get(self)->NotifyScreenInfoChanged(); +} + +void CEF_CALLBACK browser_host_invalidate(struct _cef_browser_host_t* self, + cef_paint_element_type_t type) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefBrowserHostCppToC::Get(self)->Invalidate( + type); +} + void CEF_CALLBACK browser_host_send_key_event(struct _cef_browser_host_t* self, const struct _cef_key_event_t* event) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING @@ -532,6 +597,164 @@ void CEF_CALLBACK browser_host_send_capture_lost_event( CefBrowserHostCppToC::Get(self)->SendCaptureLostEvent(); } +cef_text_input_context_t CEF_CALLBACK browser_host_get_nstext_input_context( + struct _cef_browser_host_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return NULL; + + // Execute + cef_text_input_context_t _retval = CefBrowserHostCppToC::Get( + self)->GetNSTextInputContext(); + + // Return type: simple + return _retval; +} + +void CEF_CALLBACK browser_host_handle_key_event_before_text_input_client( + struct _cef_browser_host_t* self, cef_event_handle_t keyEvent) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefBrowserHostCppToC::Get(self)->HandleKeyEventBeforeTextInputClient( + keyEvent); +} + +void CEF_CALLBACK browser_host_handle_key_event_after_text_input_client( + struct _cef_browser_host_t* self, cef_event_handle_t keyEvent) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefBrowserHostCppToC::Get(self)->HandleKeyEventAfterTextInputClient( + keyEvent); +} + +void CEF_CALLBACK browser_host_drag_target_drag_enter( + struct _cef_browser_host_t* self, struct _cef_drag_data_t* drag_data, + const struct _cef_mouse_event_t* event, + cef_drag_operations_mask_t allowed_ops) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: drag_data; type: refptr_same + DCHECK(drag_data); + if (!drag_data) + return; + // Verify param: event; type: struct_byref_const + DCHECK(event); + if (!event) + return; + + // Translate param: event; type: struct_byref_const + CefMouseEvent eventObj; + if (event) + eventObj.Set(*event, false); + + // Execute + CefBrowserHostCppToC::Get(self)->DragTargetDragEnter( + CefDragDataCppToC::Unwrap(drag_data), + eventObj, + allowed_ops); +} + +void CEF_CALLBACK browser_host_drag_target_drag_over( + struct _cef_browser_host_t* self, const struct _cef_mouse_event_t* event, + cef_drag_operations_mask_t allowed_ops) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: event; type: struct_byref_const + DCHECK(event); + if (!event) + return; + + // Translate param: event; type: struct_byref_const + CefMouseEvent eventObj; + if (event) + eventObj.Set(*event, false); + + // Execute + CefBrowserHostCppToC::Get(self)->DragTargetDragOver( + eventObj, + allowed_ops); +} + +void CEF_CALLBACK browser_host_drag_target_drag_leave( + struct _cef_browser_host_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefBrowserHostCppToC::Get(self)->DragTargetDragLeave(); +} + +void CEF_CALLBACK browser_host_drag_target_drop( + struct _cef_browser_host_t* self, const struct _cef_mouse_event_t* event) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: event; type: struct_byref_const + DCHECK(event); + if (!event) + return; + + // Translate param: event; type: struct_byref_const + CefMouseEvent eventObj; + if (event) + eventObj.Set(*event, false); + + // Execute + CefBrowserHostCppToC::Get(self)->DragTargetDrop( + eventObj); +} + +void CEF_CALLBACK browser_host_drag_source_ended_at( + struct _cef_browser_host_t* self, int x, int y, + cef_drag_operations_mask_t op) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefBrowserHostCppToC::Get(self)->DragSourceEndedAt( + x, + y, + op); +} + +void CEF_CALLBACK browser_host_drag_source_system_drag_ended( + struct _cef_browser_host_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefBrowserHostCppToC::Get(self)->DragSourceSystemDragEnded(); +} + // CONSTRUCTOR - Do not edit by hand. @@ -559,6 +782,13 @@ CefBrowserHostCppToC::CefBrowserHostCppToC(CefBrowserHost* cls) browser_host_set_mouse_cursor_change_disabled; struct_.struct_.is_mouse_cursor_change_disabled = browser_host_is_mouse_cursor_change_disabled; + struct_.struct_.is_window_rendering_disabled = + browser_host_is_window_rendering_disabled; + struct_.struct_.was_resized = browser_host_was_resized; + struct_.struct_.was_hidden = browser_host_was_hidden; + struct_.struct_.notify_screen_info_changed = + browser_host_notify_screen_info_changed; + struct_.struct_.invalidate = browser_host_invalidate; struct_.struct_.send_key_event = browser_host_send_key_event; struct_.struct_.send_mouse_click_event = browser_host_send_mouse_click_event; struct_.struct_.send_mouse_move_event = browser_host_send_mouse_move_event; @@ -566,6 +796,19 @@ CefBrowserHostCppToC::CefBrowserHostCppToC(CefBrowserHost* cls) struct_.struct_.send_focus_event = browser_host_send_focus_event; struct_.struct_.send_capture_lost_event = browser_host_send_capture_lost_event; + struct_.struct_.get_nstext_input_context = + browser_host_get_nstext_input_context; + struct_.struct_.handle_key_event_before_text_input_client = + browser_host_handle_key_event_before_text_input_client; + struct_.struct_.handle_key_event_after_text_input_client = + browser_host_handle_key_event_after_text_input_client; + struct_.struct_.drag_target_drag_enter = browser_host_drag_target_drag_enter; + struct_.struct_.drag_target_drag_over = browser_host_drag_target_drag_over; + struct_.struct_.drag_target_drag_leave = browser_host_drag_target_drag_leave; + struct_.struct_.drag_target_drop = browser_host_drag_target_drop; + struct_.struct_.drag_source_ended_at = browser_host_drag_source_ended_at; + struct_.struct_.drag_source_system_drag_ended = + browser_host_drag_source_system_drag_ended; } #ifndef NDEBUG diff --git a/libcef_dll/cpptoc/client_cpptoc.cc b/libcef_dll/cpptoc/client_cpptoc.cc index 02d4bea05..9b4ac4e50 100644 --- a/libcef_dll/cpptoc/client_cpptoc.cc +++ b/libcef_dll/cpptoc/client_cpptoc.cc @@ -22,6 +22,7 @@ #include "libcef_dll/cpptoc/keyboard_handler_cpptoc.h" #include "libcef_dll/cpptoc/life_span_handler_cpptoc.h" #include "libcef_dll/cpptoc/load_handler_cpptoc.h" +#include "libcef_dll/cpptoc/render_handler_cpptoc.h" #include "libcef_dll/cpptoc/request_handler_cpptoc.h" #include "libcef_dll/ctocpp/browser_ctocpp.h" #include "libcef_dll/ctocpp/process_message_ctocpp.h" @@ -205,6 +206,22 @@ struct _cef_load_handler_t* CEF_CALLBACK client_get_load_handler( return CefLoadHandlerCppToC::Wrap(_retval); } +struct _cef_render_handler_t* CEF_CALLBACK client_get_render_handler( + struct _cef_client_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return NULL; + + // Execute + CefRefPtr _retval = CefClientCppToC::Get( + self)->GetRenderHandler(); + + // Return type: refptr_same + return CefRenderHandlerCppToC::Wrap(_retval); +} + struct _cef_request_handler_t* CEF_CALLBACK client_get_request_handler( struct _cef_client_t* self) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING @@ -264,6 +281,7 @@ CefClientCppToC::CefClientCppToC(CefClient* cls) struct_.struct_.get_keyboard_handler = client_get_keyboard_handler; struct_.struct_.get_life_span_handler = client_get_life_span_handler; struct_.struct_.get_load_handler = client_get_load_handler; + struct_.struct_.get_render_handler = client_get_render_handler; struct_.struct_.get_request_handler = client_get_request_handler; struct_.struct_.on_process_message_received = client_on_process_message_received; diff --git a/libcef_dll/cpptoc/drag_data_cpptoc.cc b/libcef_dll/cpptoc/drag_data_cpptoc.cc index e103948eb..c040fa15a 100644 --- a/libcef_dll/cpptoc/drag_data_cpptoc.cc +++ b/libcef_dll/cpptoc/drag_data_cpptoc.cc @@ -11,11 +11,54 @@ // #include "libcef_dll/cpptoc/drag_data_cpptoc.h" +#include "libcef_dll/cpptoc/stream_writer_cpptoc.h" #include "libcef_dll/transfer_util.h" +// GLOBAL FUNCTIONS - Body may be edited by hand. + +CEF_EXPORT cef_drag_data_t* cef_drag_data_create() { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + CefRefPtr _retval = CefDragData::Create(); + + // Return type: refptr_same + return CefDragDataCppToC::Wrap(_retval); +} + + // MEMBER FUNCTIONS - Body may be edited by hand. +struct _cef_drag_data_t* CEF_CALLBACK drag_data_clone( + struct _cef_drag_data_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return NULL; + + // Execute + CefRefPtr _retval = CefDragDataCppToC::Get(self)->Clone(); + + // Return type: refptr_same + return CefDragDataCppToC::Wrap(_retval); +} + +int CEF_CALLBACK drag_data_is_read_only(struct _cef_drag_data_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + + // Execute + bool _retval = CefDragDataCppToC::Get(self)->IsReadOnly(); + + // Return type: bool + return _retval; +} + int CEF_CALLBACK drag_data_is_link(struct _cef_drag_data_t* self) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING @@ -163,6 +206,23 @@ cef_string_userfree_t CEF_CALLBACK drag_data_get_file_name( return _retval.DetachToUserFree(); } +size_t CEF_CALLBACK drag_data_get_file_contents(struct _cef_drag_data_t* self, + struct _cef_stream_writer_t* writer) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + // Unverified params: writer + + // Execute + size_t _retval = CefDragDataCppToC::Get(self)->GetFileContents( + CefStreamWriterCppToC::Unwrap(writer)); + + // Return type: simple + return _retval; +} + int CEF_CALLBACK drag_data_get_file_names(struct _cef_drag_data_t* self, cef_string_list_t names) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING @@ -191,11 +251,127 @@ int CEF_CALLBACK drag_data_get_file_names(struct _cef_drag_data_t* self, return _retval; } +void CEF_CALLBACK drag_data_set_link_url(struct _cef_drag_data_t* self, + const cef_string_t* url) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Unverified params: url + + // Execute + CefDragDataCppToC::Get(self)->SetLinkURL( + CefString(url)); +} + +void CEF_CALLBACK drag_data_set_link_title(struct _cef_drag_data_t* self, + const cef_string_t* title) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Unverified params: title + + // Execute + CefDragDataCppToC::Get(self)->SetLinkTitle( + CefString(title)); +} + +void CEF_CALLBACK drag_data_set_link_metadata(struct _cef_drag_data_t* self, + const cef_string_t* data) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Unverified params: data + + // Execute + CefDragDataCppToC::Get(self)->SetLinkMetadata( + CefString(data)); +} + +void CEF_CALLBACK drag_data_set_fragment_text(struct _cef_drag_data_t* self, + const cef_string_t* text) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Unverified params: text + + // Execute + CefDragDataCppToC::Get(self)->SetFragmentText( + CefString(text)); +} + +void CEF_CALLBACK drag_data_set_fragment_html(struct _cef_drag_data_t* self, + const cef_string_t* html) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Unverified params: html + + // Execute + CefDragDataCppToC::Get(self)->SetFragmentHtml( + CefString(html)); +} + +void CEF_CALLBACK drag_data_set_fragment_base_url(struct _cef_drag_data_t* self, + const cef_string_t* base_url) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Unverified params: base_url + + // Execute + CefDragDataCppToC::Get(self)->SetFragmentBaseURL( + CefString(base_url)); +} + +void CEF_CALLBACK drag_data_reset_file_contents(struct _cef_drag_data_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefDragDataCppToC::Get(self)->ResetFileContents(); +} + +void CEF_CALLBACK drag_data_add_file(struct _cef_drag_data_t* self, + const cef_string_t* path, const cef_string_t* display_name) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: path; type: string_byref_const + DCHECK(path); + if (!path) + return; + // Unverified params: display_name + + // Execute + CefDragDataCppToC::Get(self)->AddFile( + CefString(path), + CefString(display_name)); +} + // CONSTRUCTOR - Do not edit by hand. CefDragDataCppToC::CefDragDataCppToC(CefDragData* cls) : CefCppToC(cls) { + struct_.struct_.clone = drag_data_clone; + struct_.struct_.is_read_only = drag_data_is_read_only; struct_.struct_.is_link = drag_data_is_link; struct_.struct_.is_fragment = drag_data_is_fragment; struct_.struct_.is_file = drag_data_is_file; @@ -206,7 +382,16 @@ CefDragDataCppToC::CefDragDataCppToC(CefDragData* cls) struct_.struct_.get_fragment_html = drag_data_get_fragment_html; struct_.struct_.get_fragment_base_url = drag_data_get_fragment_base_url; struct_.struct_.get_file_name = drag_data_get_file_name; + struct_.struct_.get_file_contents = drag_data_get_file_contents; struct_.struct_.get_file_names = drag_data_get_file_names; + struct_.struct_.set_link_url = drag_data_set_link_url; + struct_.struct_.set_link_title = drag_data_set_link_title; + struct_.struct_.set_link_metadata = drag_data_set_link_metadata; + struct_.struct_.set_fragment_text = drag_data_set_fragment_text; + struct_.struct_.set_fragment_html = drag_data_set_fragment_html; + struct_.struct_.set_fragment_base_url = drag_data_set_fragment_base_url; + struct_.struct_.reset_file_contents = drag_data_reset_file_contents; + struct_.struct_.add_file = drag_data_add_file; } #ifndef NDEBUG diff --git a/libcef_dll/cpptoc/render_handler_cpptoc.cc b/libcef_dll/cpptoc/render_handler_cpptoc.cc new file mode 100644 index 000000000..60fe7383f --- /dev/null +++ b/libcef_dll/cpptoc/render_handler_cpptoc.cc @@ -0,0 +1,359 @@ +// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#include "libcef_dll/cpptoc/render_handler_cpptoc.h" +#include "libcef_dll/ctocpp/browser_ctocpp.h" +#include "libcef_dll/ctocpp/drag_data_ctocpp.h" + + +// MEMBER FUNCTIONS - Body may be edited by hand. + +int CEF_CALLBACK render_handler_get_root_screen_rect( + struct _cef_render_handler_t* self, cef_browser_t* browser, + cef_rect_t* rect) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + // Verify param: browser; type: refptr_diff + DCHECK(browser); + if (!browser) + return 0; + // Verify param: rect; type: simple_byref + DCHECK(rect); + if (!rect) + return 0; + + // Translate param: rect; type: simple_byref + CefRect rectVal = rect?*rect:CefRect(); + + // Execute + bool _retval = CefRenderHandlerCppToC::Get(self)->GetRootScreenRect( + CefBrowserCToCpp::Wrap(browser), + rectVal); + + // Restore param: rect; type: simple_byref + if (rect) + *rect = rectVal; + + // Return type: bool + return _retval; +} + +int CEF_CALLBACK render_handler_get_view_rect( + struct _cef_render_handler_t* self, cef_browser_t* browser, + cef_rect_t* rect) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + // Verify param: browser; type: refptr_diff + DCHECK(browser); + if (!browser) + return 0; + // Verify param: rect; type: simple_byref + DCHECK(rect); + if (!rect) + return 0; + + // Translate param: rect; type: simple_byref + CefRect rectVal = rect?*rect:CefRect(); + + // Execute + bool _retval = CefRenderHandlerCppToC::Get(self)->GetViewRect( + CefBrowserCToCpp::Wrap(browser), + rectVal); + + // Restore param: rect; type: simple_byref + if (rect) + *rect = rectVal; + + // Return type: bool + return _retval; +} + +int CEF_CALLBACK render_handler_get_screen_point( + struct _cef_render_handler_t* self, cef_browser_t* browser, int viewX, + int viewY, int* screenX, int* screenY) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + // Verify param: browser; type: refptr_diff + DCHECK(browser); + if (!browser) + return 0; + // Verify param: screenX; type: simple_byref + DCHECK(screenX); + if (!screenX) + return 0; + // Verify param: screenY; type: simple_byref + DCHECK(screenY); + if (!screenY) + return 0; + + // Translate param: screenX; type: simple_byref + int screenXVal = screenX?*screenX:0; + // Translate param: screenY; type: simple_byref + int screenYVal = screenY?*screenY:0; + + // Execute + bool _retval = CefRenderHandlerCppToC::Get(self)->GetScreenPoint( + CefBrowserCToCpp::Wrap(browser), + viewX, + viewY, + screenXVal, + screenYVal); + + // Restore param: screenX; type: simple_byref + if (screenX) + *screenX = screenXVal; + // Restore param: screenY; type: simple_byref + if (screenY) + *screenY = screenYVal; + + // Return type: bool + return _retval; +} + +int CEF_CALLBACK render_handler_get_screen_info( + struct _cef_render_handler_t* self, cef_browser_t* browser, + struct _cef_screen_info_t* screen_info) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + // Verify param: browser; type: refptr_diff + DCHECK(browser); + if (!browser) + return 0; + // Verify param: screen_info; type: struct_byref + DCHECK(screen_info); + if (!screen_info) + return 0; + + // Translate param: screen_info; type: struct_byref + CefScreenInfo screen_infoObj; + if (screen_info) + screen_infoObj.AttachTo(*screen_info); + + // Execute + bool _retval = CefRenderHandlerCppToC::Get(self)->GetScreenInfo( + CefBrowserCToCpp::Wrap(browser), + screen_infoObj); + + // Restore param: screen_info; type: struct_byref + if (screen_info) + screen_infoObj.DetachTo(*screen_info); + + // Return type: bool + return _retval; +} + +void CEF_CALLBACK render_handler_on_popup_show( + struct _cef_render_handler_t* self, cef_browser_t* browser, int show) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: browser; type: refptr_diff + DCHECK(browser); + if (!browser) + return; + + // Execute + CefRenderHandlerCppToC::Get(self)->OnPopupShow( + CefBrowserCToCpp::Wrap(browser), + show?true:false); +} + +void CEF_CALLBACK render_handler_on_popup_size( + struct _cef_render_handler_t* self, cef_browser_t* browser, + const cef_rect_t* rect) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: browser; type: refptr_diff + DCHECK(browser); + if (!browser) + return; + // Verify param: rect; type: simple_byref_const + DCHECK(rect); + if (!rect) + return; + + // Translate param: rect; type: simple_byref_const + CefRect rectVal = rect?*rect:CefRect(); + + // Execute + CefRenderHandlerCppToC::Get(self)->OnPopupSize( + CefBrowserCToCpp::Wrap(browser), + rectVal); +} + +void CEF_CALLBACK render_handler_on_paint(struct _cef_render_handler_t* self, + cef_browser_t* browser, cef_paint_element_type_t type, + size_t dirtyRectsCount, cef_rect_t const* dirtyRects, const void* buffer, + int width, int height) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: browser; type: refptr_diff + DCHECK(browser); + if (!browser) + return; + // Verify param: dirtyRects; type: simple_vec_byref_const + DCHECK(dirtyRectsCount == 0 || dirtyRects); + if (dirtyRectsCount > 0 && !dirtyRects) + return; + // Verify param: buffer; type: simple_byaddr + DCHECK(buffer); + if (!buffer) + return; + + // Translate param: dirtyRects; type: simple_vec_byref_const + std::vector dirtyRectsList; + if (dirtyRectsCount > 0) { + for (size_t i = 0; i < dirtyRectsCount; ++i) { + dirtyRectsList.push_back(dirtyRects[i]); + } + } + + // Execute + CefRenderHandlerCppToC::Get(self)->OnPaint( + CefBrowserCToCpp::Wrap(browser), + type, + dirtyRectsList, + buffer, + width, + height); +} + +void CEF_CALLBACK render_handler_on_cursor_change( + struct _cef_render_handler_t* self, cef_browser_t* browser, + cef_cursor_handle_t cursor) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: browser; type: refptr_diff + DCHECK(browser); + if (!browser) + return; + + // Execute + CefRenderHandlerCppToC::Get(self)->OnCursorChange( + CefBrowserCToCpp::Wrap(browser), + cursor); +} + +int CEF_CALLBACK render_handler_start_dragging( + struct _cef_render_handler_t* self, cef_browser_t* browser, + cef_drag_data_t* drag_data, cef_drag_operations_mask_t allowed_ops, int x, + int y) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + // Verify param: browser; type: refptr_diff + DCHECK(browser); + if (!browser) + return 0; + // Verify param: drag_data; type: refptr_diff + DCHECK(drag_data); + if (!drag_data) + return 0; + + // Execute + bool _retval = CefRenderHandlerCppToC::Get(self)->StartDragging( + CefBrowserCToCpp::Wrap(browser), + CefDragDataCToCpp::Wrap(drag_data), + allowed_ops, + x, + y); + + // Return type: bool + return _retval; +} + +void CEF_CALLBACK render_handler_update_drag_cursor( + struct _cef_render_handler_t* self, cef_browser_t* browser, + cef_drag_operations_mask_t operation) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: browser; type: refptr_diff + DCHECK(browser); + if (!browser) + return; + + // Execute + CefRenderHandlerCppToC::Get(self)->UpdateDragCursor( + CefBrowserCToCpp::Wrap(browser), + operation); +} + +void CEF_CALLBACK render_handler_on_scroll_offset_changed( + struct _cef_render_handler_t* self, cef_browser_t* browser) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: browser; type: refptr_diff + DCHECK(browser); + if (!browser) + return; + + // Execute + CefRenderHandlerCppToC::Get(self)->OnScrollOffsetChanged( + CefBrowserCToCpp::Wrap(browser)); +} + + +// CONSTRUCTOR - Do not edit by hand. + +CefRenderHandlerCppToC::CefRenderHandlerCppToC(CefRenderHandler* cls) + : CefCppToC( + cls) { + struct_.struct_.get_root_screen_rect = render_handler_get_root_screen_rect; + struct_.struct_.get_view_rect = render_handler_get_view_rect; + struct_.struct_.get_screen_point = render_handler_get_screen_point; + struct_.struct_.get_screen_info = render_handler_get_screen_info; + struct_.struct_.on_popup_show = render_handler_on_popup_show; + struct_.struct_.on_popup_size = render_handler_on_popup_size; + struct_.struct_.on_paint = render_handler_on_paint; + struct_.struct_.on_cursor_change = render_handler_on_cursor_change; + struct_.struct_.start_dragging = render_handler_start_dragging; + struct_.struct_.update_drag_cursor = render_handler_update_drag_cursor; + struct_.struct_.on_scroll_offset_changed = + render_handler_on_scroll_offset_changed; +} + +#ifndef NDEBUG +template<> long CefCppToC::DebugObjCt = 0; +#endif + diff --git a/libcef_dll/cpptoc/render_handler_cpptoc.h b/libcef_dll/cpptoc/render_handler_cpptoc.h new file mode 100644 index 000000000..3c0498af7 --- /dev/null +++ b/libcef_dll/cpptoc/render_handler_cpptoc.h @@ -0,0 +1,37 @@ +// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#ifndef CEF_LIBCEF_DLL_CPPTOC_RENDER_HANDLER_CPPTOC_H_ +#define CEF_LIBCEF_DLL_CPPTOC_RENDER_HANDLER_CPPTOC_H_ +#pragma once + +#ifndef USING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed wrapper-side only") +#else // USING_CEF_SHARED + +#include "include/cef_render_handler.h" +#include "include/capi/cef_render_handler_capi.h" +#include "libcef_dll/cpptoc/cpptoc.h" + +// Wrap a C++ class with a C structure. +// This class may be instantiated and accessed wrapper-side only. +class CefRenderHandlerCppToC + : public CefCppToC { + public: + explicit CefRenderHandlerCppToC(CefRenderHandler* cls); + virtual ~CefRenderHandlerCppToC() {} +}; + +#endif // USING_CEF_SHARED +#endif // CEF_LIBCEF_DLL_CPPTOC_RENDER_HANDLER_CPPTOC_H_ + diff --git a/libcef_dll/ctocpp/browser_host_ctocpp.cc b/libcef_dll/ctocpp/browser_host_ctocpp.cc index 4292fd5e6..f2de69cee 100644 --- a/libcef_dll/ctocpp/browser_host_ctocpp.cc +++ b/libcef_dll/ctocpp/browser_host_ctocpp.cc @@ -14,6 +14,7 @@ #include "libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.h" #include "libcef_dll/ctocpp/browser_ctocpp.h" #include "libcef_dll/ctocpp/browser_host_ctocpp.h" +#include "libcef_dll/ctocpp/drag_data_ctocpp.h" #include "libcef_dll/ctocpp/request_context_ctocpp.h" #include "libcef_dll/transfer_util.h" @@ -330,6 +331,61 @@ bool CefBrowserHostCToCpp::IsMouseCursorChangeDisabled() { return _retval?true:false; } +bool CefBrowserHostCToCpp::IsWindowRenderingDisabled() { + if (CEF_MEMBER_MISSING(struct_, is_window_rendering_disabled)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + int _retval = struct_->is_window_rendering_disabled(struct_); + + // Return type: bool + return _retval?true:false; +} + +void CefBrowserHostCToCpp::WasResized() { + if (CEF_MEMBER_MISSING(struct_, was_resized)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + struct_->was_resized(struct_); +} + +void CefBrowserHostCToCpp::WasHidden(bool hidden) { + if (CEF_MEMBER_MISSING(struct_, was_hidden)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + struct_->was_hidden(struct_, + hidden); +} + +void CefBrowserHostCToCpp::NotifyScreenInfoChanged() { + if (CEF_MEMBER_MISSING(struct_, notify_screen_info_changed)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + struct_->notify_screen_info_changed(struct_); +} + +void CefBrowserHostCToCpp::Invalidate(PaintElementType type) { + if (CEF_MEMBER_MISSING(struct_, invalidate)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + struct_->invalidate(struct_, + type); +} + void CefBrowserHostCToCpp::SendKeyEvent(const CefKeyEvent& event) { if (CEF_MEMBER_MISSING(struct_, send_key_event)) return; @@ -404,6 +460,120 @@ void CefBrowserHostCToCpp::SendCaptureLostEvent() { struct_->send_capture_lost_event(struct_); } +CefTextInputContext CefBrowserHostCToCpp::GetNSTextInputContext() { + if (CEF_MEMBER_MISSING(struct_, get_nstext_input_context)) + return NULL; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_text_input_context_t _retval = struct_->get_nstext_input_context(struct_); + + // Return type: simple + return _retval; +} + +void CefBrowserHostCToCpp::HandleKeyEventBeforeTextInputClient( + CefEventHandle keyEvent) { + if (CEF_MEMBER_MISSING(struct_, handle_key_event_before_text_input_client)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + struct_->handle_key_event_before_text_input_client(struct_, + keyEvent); +} + +void CefBrowserHostCToCpp::HandleKeyEventAfterTextInputClient( + CefEventHandle keyEvent) { + if (CEF_MEMBER_MISSING(struct_, handle_key_event_after_text_input_client)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + struct_->handle_key_event_after_text_input_client(struct_, + keyEvent); +} + +void CefBrowserHostCToCpp::DragTargetDragEnter(CefRefPtr drag_data, + const CefMouseEvent& event, DragOperationsMask allowed_ops) { + if (CEF_MEMBER_MISSING(struct_, drag_target_drag_enter)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: drag_data; type: refptr_same + DCHECK(drag_data.get()); + if (!drag_data.get()) + return; + + // Execute + struct_->drag_target_drag_enter(struct_, + CefDragDataCToCpp::Unwrap(drag_data), + &event, + allowed_ops); +} + +void CefBrowserHostCToCpp::DragTargetDragOver(const CefMouseEvent& event, + DragOperationsMask allowed_ops) { + if (CEF_MEMBER_MISSING(struct_, drag_target_drag_over)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + struct_->drag_target_drag_over(struct_, + &event, + allowed_ops); +} + +void CefBrowserHostCToCpp::DragTargetDragLeave() { + if (CEF_MEMBER_MISSING(struct_, drag_target_drag_leave)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + struct_->drag_target_drag_leave(struct_); +} + +void CefBrowserHostCToCpp::DragTargetDrop(const CefMouseEvent& event) { + if (CEF_MEMBER_MISSING(struct_, drag_target_drop)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + struct_->drag_target_drop(struct_, + &event); +} + +void CefBrowserHostCToCpp::DragSourceEndedAt(int x, int y, + DragOperationsMask op) { + if (CEF_MEMBER_MISSING(struct_, drag_source_ended_at)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + struct_->drag_source_ended_at(struct_, + x, + y, + op); +} + +void CefBrowserHostCToCpp::DragSourceSystemDragEnded() { + if (CEF_MEMBER_MISSING(struct_, drag_source_system_drag_ended)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + struct_->drag_source_system_drag_ended(struct_); +} + #ifndef NDEBUG template<> long CefCToCpp drag_data, + const CefMouseEvent& event, DragOperationsMask allowed_ops) OVERRIDE; + virtual void DragTargetDragOver(const CefMouseEvent& event, + DragOperationsMask allowed_ops) OVERRIDE; + virtual void DragTargetDragLeave() OVERRIDE; + virtual void DragTargetDrop(const CefMouseEvent& event) OVERRIDE; + virtual void DragSourceEndedAt(int x, int y, DragOperationsMask op) OVERRIDE; + virtual void DragSourceSystemDragEnded() OVERRIDE; }; #endif // USING_CEF_SHARED diff --git a/libcef_dll/ctocpp/client_ctocpp.cc b/libcef_dll/ctocpp/client_ctocpp.cc index 55c125266..59457bf93 100644 --- a/libcef_dll/ctocpp/client_ctocpp.cc +++ b/libcef_dll/ctocpp/client_ctocpp.cc @@ -24,6 +24,7 @@ #include "libcef_dll/ctocpp/keyboard_handler_ctocpp.h" #include "libcef_dll/ctocpp/life_span_handler_ctocpp.h" #include "libcef_dll/ctocpp/load_handler_ctocpp.h" +#include "libcef_dll/ctocpp/render_handler_ctocpp.h" #include "libcef_dll/ctocpp/request_handler_ctocpp.h" @@ -174,6 +175,19 @@ CefRefPtr CefClientCToCpp::GetLoadHandler() { return CefLoadHandlerCToCpp::Wrap(_retval); } +CefRefPtr CefClientCToCpp::GetRenderHandler() { + if (CEF_MEMBER_MISSING(struct_, get_render_handler)) + return NULL; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_render_handler_t* _retval = struct_->get_render_handler(struct_); + + // Return type: refptr_same + return CefRenderHandlerCToCpp::Wrap(_retval); +} + CefRefPtr CefClientCToCpp::GetRequestHandler() { if (CEF_MEMBER_MISSING(struct_, get_request_handler)) return NULL; diff --git a/libcef_dll/ctocpp/client_ctocpp.h b/libcef_dll/ctocpp/client_ctocpp.h index f017223c0..e793c39f1 100644 --- a/libcef_dll/ctocpp/client_ctocpp.h +++ b/libcef_dll/ctocpp/client_ctocpp.h @@ -43,6 +43,7 @@ class CefClientCToCpp virtual CefRefPtr GetKeyboardHandler() OVERRIDE; virtual CefRefPtr GetLifeSpanHandler() OVERRIDE; virtual CefRefPtr GetLoadHandler() OVERRIDE; + virtual CefRefPtr GetRenderHandler() OVERRIDE; virtual CefRefPtr GetRequestHandler() OVERRIDE; virtual bool OnProcessMessageReceived(CefRefPtr browser, CefProcessId source_process, diff --git a/libcef_dll/ctocpp/drag_data_ctocpp.cc b/libcef_dll/ctocpp/drag_data_ctocpp.cc index 26c3adb36..34dab5fc9 100644 --- a/libcef_dll/ctocpp/drag_data_ctocpp.cc +++ b/libcef_dll/ctocpp/drag_data_ctocpp.cc @@ -11,11 +11,51 @@ // #include "libcef_dll/ctocpp/drag_data_ctocpp.h" +#include "libcef_dll/ctocpp/stream_writer_ctocpp.h" #include "libcef_dll/transfer_util.h" +// STATIC METHODS - Body may be edited by hand. + +CefRefPtr CefDragData::Create() { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_drag_data_t* _retval = cef_drag_data_create(); + + // Return type: refptr_same + return CefDragDataCToCpp::Wrap(_retval); +} + + // VIRTUAL METHODS - Body may be edited by hand. +CefRefPtr CefDragDataCToCpp::Clone() { + if (CEF_MEMBER_MISSING(struct_, clone)) + return NULL; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_drag_data_t* _retval = struct_->clone(struct_); + + // Return type: refptr_same + return CefDragDataCToCpp::Wrap(_retval); +} + +bool CefDragDataCToCpp::IsReadOnly() { + if (CEF_MEMBER_MISSING(struct_, is_read_only)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + int _retval = struct_->is_read_only(struct_); + + // Return type: bool + return _retval?true:false; +} + bool CefDragDataCToCpp::IsLink() { if (CEF_MEMBER_MISSING(struct_, is_link)) return false; @@ -160,6 +200,22 @@ CefString CefDragDataCToCpp::GetFileName() { return _retvalStr; } +size_t CefDragDataCToCpp::GetFileContents(CefRefPtr writer) { + if (CEF_MEMBER_MISSING(struct_, get_file_contents)) + return 0; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Unverified params: writer + + // Execute + size_t _retval = struct_->get_file_contents(struct_, + CefStreamWriterCToCpp::Unwrap(writer)); + + // Return type: simple + return _retval; +} + bool CefDragDataCToCpp::GetFileNames(std::vector& names) { if (CEF_MEMBER_MISSING(struct_, get_file_names)) return false; @@ -187,6 +243,113 @@ bool CefDragDataCToCpp::GetFileNames(std::vector& names) { return _retval?true:false; } +void CefDragDataCToCpp::SetLinkURL(const CefString& url) { + if (CEF_MEMBER_MISSING(struct_, set_link_url)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Unverified params: url + + // Execute + struct_->set_link_url(struct_, + url.GetStruct()); +} + +void CefDragDataCToCpp::SetLinkTitle(const CefString& title) { + if (CEF_MEMBER_MISSING(struct_, set_link_title)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Unverified params: title + + // Execute + struct_->set_link_title(struct_, + title.GetStruct()); +} + +void CefDragDataCToCpp::SetLinkMetadata(const CefString& data) { + if (CEF_MEMBER_MISSING(struct_, set_link_metadata)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Unverified params: data + + // Execute + struct_->set_link_metadata(struct_, + data.GetStruct()); +} + +void CefDragDataCToCpp::SetFragmentText(const CefString& text) { + if (CEF_MEMBER_MISSING(struct_, set_fragment_text)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Unverified params: text + + // Execute + struct_->set_fragment_text(struct_, + text.GetStruct()); +} + +void CefDragDataCToCpp::SetFragmentHtml(const CefString& html) { + if (CEF_MEMBER_MISSING(struct_, set_fragment_html)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Unverified params: html + + // Execute + struct_->set_fragment_html(struct_, + html.GetStruct()); +} + +void CefDragDataCToCpp::SetFragmentBaseURL(const CefString& base_url) { + if (CEF_MEMBER_MISSING(struct_, set_fragment_base_url)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Unverified params: base_url + + // Execute + struct_->set_fragment_base_url(struct_, + base_url.GetStruct()); +} + +void CefDragDataCToCpp::ResetFileContents() { + if (CEF_MEMBER_MISSING(struct_, reset_file_contents)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + struct_->reset_file_contents(struct_); +} + +void CefDragDataCToCpp::AddFile(const CefString& path, + const CefString& display_name) { + if (CEF_MEMBER_MISSING(struct_, add_file)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: path; type: string_byref_const + DCHECK(!path.empty()); + if (path.empty()) + return; + // Unverified params: display_name + + // Execute + struct_->add_file(struct_, + path.GetStruct(), + display_name.GetStruct()); +} + #ifndef NDEBUG template<> long CefCToCpp Clone() OVERRIDE; + virtual bool IsReadOnly() OVERRIDE; virtual bool IsLink() OVERRIDE; virtual bool IsFragment() OVERRIDE; virtual bool IsFile() OVERRIDE; @@ -43,7 +45,17 @@ class CefDragDataCToCpp virtual CefString GetFragmentHtml() OVERRIDE; virtual CefString GetFragmentBaseURL() OVERRIDE; virtual CefString GetFileName() OVERRIDE; + virtual size_t GetFileContents(CefRefPtr writer) OVERRIDE; virtual bool GetFileNames(std::vector& names) OVERRIDE; + virtual void SetLinkURL(const CefString& url) OVERRIDE; + virtual void SetLinkTitle(const CefString& title) OVERRIDE; + virtual void SetLinkMetadata(const CefString& data) OVERRIDE; + virtual void SetFragmentText(const CefString& text) OVERRIDE; + virtual void SetFragmentHtml(const CefString& html) OVERRIDE; + virtual void SetFragmentBaseURL(const CefString& base_url) OVERRIDE; + virtual void ResetFileContents() OVERRIDE; + virtual void AddFile(const CefString& path, + const CefString& display_name) OVERRIDE; }; #endif // USING_CEF_SHARED diff --git a/libcef_dll/ctocpp/render_handler_ctocpp.cc b/libcef_dll/ctocpp/render_handler_ctocpp.cc new file mode 100644 index 000000000..f6c70cde0 --- /dev/null +++ b/libcef_dll/ctocpp/render_handler_ctocpp.cc @@ -0,0 +1,275 @@ +// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#include "libcef_dll/cpptoc/browser_cpptoc.h" +#include "libcef_dll/cpptoc/drag_data_cpptoc.h" +#include "libcef_dll/ctocpp/render_handler_ctocpp.h" + + +// VIRTUAL METHODS - Body may be edited by hand. + +bool CefRenderHandlerCToCpp::GetRootScreenRect(CefRefPtr browser, + CefRect& rect) { + if (CEF_MEMBER_MISSING(struct_, get_root_screen_rect)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: browser; type: refptr_diff + DCHECK(browser.get()); + if (!browser.get()) + return false; + + // Execute + int _retval = struct_->get_root_screen_rect(struct_, + CefBrowserCppToC::Wrap(browser), + &rect); + + // Return type: bool + return _retval?true:false; +} + +bool CefRenderHandlerCToCpp::GetViewRect(CefRefPtr browser, + CefRect& rect) { + if (CEF_MEMBER_MISSING(struct_, get_view_rect)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: browser; type: refptr_diff + DCHECK(browser.get()); + if (!browser.get()) + return false; + + // Execute + int _retval = struct_->get_view_rect(struct_, + CefBrowserCppToC::Wrap(browser), + &rect); + + // Return type: bool + return _retval?true:false; +} + +bool CefRenderHandlerCToCpp::GetScreenPoint(CefRefPtr browser, + int viewX, int viewY, int& screenX, int& screenY) { + if (CEF_MEMBER_MISSING(struct_, get_screen_point)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: browser; type: refptr_diff + DCHECK(browser.get()); + if (!browser.get()) + return false; + + // Execute + int _retval = struct_->get_screen_point(struct_, + CefBrowserCppToC::Wrap(browser), + viewX, + viewY, + &screenX, + &screenY); + + // Return type: bool + return _retval?true:false; +} + +bool CefRenderHandlerCToCpp::GetScreenInfo(CefRefPtr browser, + CefScreenInfo& screen_info) { + if (CEF_MEMBER_MISSING(struct_, get_screen_info)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: browser; type: refptr_diff + DCHECK(browser.get()); + if (!browser.get()) + return false; + + // Execute + int _retval = struct_->get_screen_info(struct_, + CefBrowserCppToC::Wrap(browser), + &screen_info); + + // Return type: bool + return _retval?true:false; +} + +void CefRenderHandlerCToCpp::OnPopupShow(CefRefPtr browser, + bool show) { + if (CEF_MEMBER_MISSING(struct_, on_popup_show)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: browser; type: refptr_diff + DCHECK(browser.get()); + if (!browser.get()) + return; + + // Execute + struct_->on_popup_show(struct_, + CefBrowserCppToC::Wrap(browser), + show); +} + +void CefRenderHandlerCToCpp::OnPopupSize(CefRefPtr browser, + const CefRect& rect) { + if (CEF_MEMBER_MISSING(struct_, on_popup_size)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: browser; type: refptr_diff + DCHECK(browser.get()); + if (!browser.get()) + return; + + // Execute + struct_->on_popup_size(struct_, + CefBrowserCppToC::Wrap(browser), + &rect); +} + +void CefRenderHandlerCToCpp::OnPaint(CefRefPtr browser, + PaintElementType type, const RectList& dirtyRects, const void* buffer, + int width, int height) { + if (CEF_MEMBER_MISSING(struct_, on_paint)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: browser; type: refptr_diff + DCHECK(browser.get()); + if (!browser.get()) + return; + // Verify param: buffer; type: simple_byaddr + DCHECK(buffer); + if (!buffer) + return; + + // Translate param: dirtyRects; type: simple_vec_byref_const + const size_t dirtyRectsCount = dirtyRects.size(); + cef_rect_t* dirtyRectsList = NULL; + if (dirtyRectsCount > 0) { + dirtyRectsList = new cef_rect_t[dirtyRectsCount]; + DCHECK(dirtyRectsList); + if (dirtyRectsList) { + for (size_t i = 0; i < dirtyRectsCount; ++i) { + dirtyRectsList[i] = dirtyRects[i]; + } + } + } + + // Execute + struct_->on_paint(struct_, + CefBrowserCppToC::Wrap(browser), + type, + dirtyRectsCount, + dirtyRectsList, + buffer, + width, + height); + + // Restore param:dirtyRects; type: simple_vec_byref_const + if (dirtyRectsList) + delete [] dirtyRectsList; +} + +void CefRenderHandlerCToCpp::OnCursorChange(CefRefPtr browser, + CefCursorHandle cursor) { + if (CEF_MEMBER_MISSING(struct_, on_cursor_change)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: browser; type: refptr_diff + DCHECK(browser.get()); + if (!browser.get()) + return; + + // Execute + struct_->on_cursor_change(struct_, + CefBrowserCppToC::Wrap(browser), + cursor); +} + +bool CefRenderHandlerCToCpp::StartDragging(CefRefPtr browser, + CefRefPtr drag_data, DragOperationsMask allowed_ops, int x, + int y) { + if (CEF_MEMBER_MISSING(struct_, start_dragging)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: browser; type: refptr_diff + DCHECK(browser.get()); + if (!browser.get()) + return false; + // Verify param: drag_data; type: refptr_diff + DCHECK(drag_data.get()); + if (!drag_data.get()) + return false; + + // Execute + int _retval = struct_->start_dragging(struct_, + CefBrowserCppToC::Wrap(browser), + CefDragDataCppToC::Wrap(drag_data), + allowed_ops, + x, + y); + + // Return type: bool + return _retval?true:false; +} + +void CefRenderHandlerCToCpp::UpdateDragCursor(CefRefPtr browser, + DragOperation operation) { + if (CEF_MEMBER_MISSING(struct_, update_drag_cursor)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: browser; type: refptr_diff + DCHECK(browser.get()); + if (!browser.get()) + return; + + // Execute + struct_->update_drag_cursor(struct_, + CefBrowserCppToC::Wrap(browser), + operation); +} + +void CefRenderHandlerCToCpp::OnScrollOffsetChanged( + CefRefPtr browser) { + if (CEF_MEMBER_MISSING(struct_, on_scroll_offset_changed)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: browser; type: refptr_diff + DCHECK(browser.get()); + if (!browser.get()) + return; + + // Execute + struct_->on_scroll_offset_changed(struct_, + CefBrowserCppToC::Wrap(browser)); +} + + +#ifndef NDEBUG +template<> long CefCToCpp::DebugObjCt = 0; +#endif + diff --git a/libcef_dll/ctocpp/render_handler_ctocpp.h b/libcef_dll/ctocpp/render_handler_ctocpp.h new file mode 100644 index 000000000..9d8b790e6 --- /dev/null +++ b/libcef_dll/ctocpp/render_handler_ctocpp.h @@ -0,0 +1,63 @@ +// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#ifndef CEF_LIBCEF_DLL_CTOCPP_RENDER_HANDLER_CTOCPP_H_ +#define CEF_LIBCEF_DLL_CTOCPP_RENDER_HANDLER_CTOCPP_H_ +#pragma once + +#ifndef BUILDING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed DLL-side only") +#else // BUILDING_CEF_SHARED + +#include "include/cef_render_handler.h" +#include "include/capi/cef_render_handler_capi.h" +#include "libcef_dll/ctocpp/ctocpp.h" + +// Wrap a C structure with a C++ class. +// This class may be instantiated and accessed DLL-side only. +class CefRenderHandlerCToCpp + : public CefCToCpp { + public: + explicit CefRenderHandlerCToCpp(cef_render_handler_t* str) + : CefCToCpp(str) {} + virtual ~CefRenderHandlerCToCpp() {} + + // CefRenderHandler methods + virtual bool GetRootScreenRect(CefRefPtr browser, + CefRect& rect) OVERRIDE; + virtual bool GetViewRect(CefRefPtr browser, + CefRect& rect) OVERRIDE; + virtual bool GetScreenPoint(CefRefPtr browser, int viewX, + int viewY, int& screenX, int& screenY) OVERRIDE; + virtual bool GetScreenInfo(CefRefPtr browser, + CefScreenInfo& screen_info) OVERRIDE; + virtual void OnPopupShow(CefRefPtr browser, bool show) OVERRIDE; + virtual void OnPopupSize(CefRefPtr browser, + const CefRect& rect) OVERRIDE; + virtual void OnPaint(CefRefPtr browser, PaintElementType type, + const RectList& dirtyRects, const void* buffer, int width, + int height) OVERRIDE; + virtual void OnCursorChange(CefRefPtr browser, + CefCursorHandle cursor) OVERRIDE; + virtual bool StartDragging(CefRefPtr browser, + CefRefPtr drag_data, DragOperationsMask allowed_ops, int x, + int y) OVERRIDE; + virtual void UpdateDragCursor(CefRefPtr browser, + DragOperation operation) OVERRIDE; + virtual void OnScrollOffsetChanged(CefRefPtr browser) OVERRIDE; +}; + +#endif // BUILDING_CEF_SHARED +#endif // CEF_LIBCEF_DLL_CTOCPP_RENDER_HANDLER_CTOCPP_H_ + diff --git a/libcef_dll/libcef_dll.cc b/libcef_dll/libcef_dll.cc index f71c7f116..960d68a87 100644 --- a/libcef_dll/libcef_dll.cc +++ b/libcef_dll/libcef_dll.cc @@ -89,6 +89,7 @@ #include "libcef_dll/ctocpp/life_span_handler_ctocpp.h" #include "libcef_dll/ctocpp/load_handler_ctocpp.h" #include "libcef_dll/ctocpp/read_handler_ctocpp.h" +#include "libcef_dll/ctocpp/render_handler_ctocpp.h" #include "libcef_dll/ctocpp/render_process_handler_ctocpp.h" #include "libcef_dll/ctocpp/request_handler_ctocpp.h" #include "libcef_dll/ctocpp/resource_bundle_handler_ctocpp.h" @@ -217,6 +218,7 @@ CEF_EXPORT void cef_shutdown() { DCHECK_EQ(CefProcessMessageCppToC::DebugObjCt, 0); DCHECK_EQ(CefQuotaCallbackCppToC::DebugObjCt, 0); DCHECK_EQ(CefReadHandlerCToCpp::DebugObjCt, 0); + DCHECK_EQ(CefRenderHandlerCToCpp::DebugObjCt, 0); DCHECK_EQ(CefRenderProcessHandlerCToCpp::DebugObjCt, 0); DCHECK_EQ(CefRequestHandlerCToCpp::DebugObjCt, 0); DCHECK_EQ(CefResourceBundleHandlerCToCpp::DebugObjCt, 0); diff --git a/libcef_dll/wrapper/libcef_dll_wrapper.cc b/libcef_dll/wrapper/libcef_dll_wrapper.cc index 21a3de52f..94f69577e 100644 --- a/libcef_dll/wrapper/libcef_dll_wrapper.cc +++ b/libcef_dll/wrapper/libcef_dll_wrapper.cc @@ -53,6 +53,7 @@ #include "libcef_dll/cpptoc/life_span_handler_cpptoc.h" #include "libcef_dll/cpptoc/load_handler_cpptoc.h" #include "libcef_dll/cpptoc/read_handler_cpptoc.h" +#include "libcef_dll/cpptoc/render_handler_cpptoc.h" #include "libcef_dll/cpptoc/render_process_handler_cpptoc.h" #include "libcef_dll/cpptoc/request_handler_cpptoc.h" #include "libcef_dll/cpptoc/resource_bundle_handler_cpptoc.h" @@ -209,6 +210,7 @@ CEF_GLOBAL void CefShutdown() { DCHECK_EQ(CefProcessMessageCToCpp::DebugObjCt, 0); DCHECK_EQ(CefQuotaCallbackCToCpp::DebugObjCt, 0); DCHECK_EQ(CefReadHandlerCppToC::DebugObjCt, 0); + DCHECK_EQ(CefRenderHandlerCppToC::DebugObjCt, 0); DCHECK_EQ(CefRenderProcessHandlerCppToC::DebugObjCt, 0); DCHECK_EQ(CefRequestHandlerCppToC::DebugObjCt, 0); DCHECK_EQ(CefResourceBundleHandlerCppToC::DebugObjCt, 0); diff --git a/patch/patch.cfg b/patch/patch.cfg index 36c0594f8..d7bb9d2b2 100644 --- a/patch/patch.cfg +++ b/patch/patch.cfg @@ -47,6 +47,11 @@ patches = [ 'name': 'gyp_331', 'path': '../tools/gyp/pylib/', }, + { + # Enable popups in offscreen rendering on OS X. + 'name': 'webkit_popups', + 'path': '../third_party/WebKit/', + }, { # Fix export of UnderlayOpenGLHostingWindow for 64-bit OS X builds. # http://code.google.com/p/chromiumembedded/issues/detail?id=1051 @@ -74,9 +79,18 @@ patches = [ { # Allow customization of the background color with Aura. # http://code.google.com/p/chromiumembedded/issues/detail?id=1161 - 'name': 'public_browser_1161', + # + # Allow specification of a custom WebContentsView. + # http://code.google.com/p/chromiumembedded/issues/detail?id=1257 + 'name': 'public_browser_1161_1257', 'path': '../content/public/browser/', }, + { + # Allow specification of a custom WebContentsView. + # http://code.google.com/p/chromiumembedded/issues/detail?id=1257 + 'name': 'browser_web_contents_1257', + 'path': '../content/browser/web_contents/', + }, { # Allow customization of the WebView background color. # http://code.google.com/p/chromiumembedded/issues/detail?id=1161 diff --git a/patch/patches/browser_web_contents_1257.patch b/patch/patches/browser_web_contents_1257.patch new file mode 100644 index 000000000..64329ec22 --- /dev/null +++ b/patch/patches/browser_web_contents_1257.patch @@ -0,0 +1,78 @@ +Index: web_contents_impl.cc +=================================================================== +--- web_contents_impl.cc (revision 275973) ++++ web_contents_impl.cc (working copy) +@@ -1059,22 +1059,29 @@ + params.browser_context, params.site_instance, params.routing_id, + params.main_frame_routing_id); + +- WebContentsViewDelegate* delegate = +- GetContentClient()->browser()->GetWebContentsViewDelegate(this); ++ if (params.view && params.delegate_view) { ++ view_.reset(params.view); ++ render_view_host_delegate_view_ = params.delegate_view; ++ } + +- if (browser_plugin_guest_) { +- scoped_ptr platform_view(CreateWebContentsView( +- this, delegate, &render_view_host_delegate_view_)); ++ if (!view_) { ++ WebContentsViewDelegate* delegate = ++ GetContentClient()->browser()->GetWebContentsViewDelegate(this); + +- WebContentsViewGuest* rv = new WebContentsViewGuest( +- this, browser_plugin_guest_.get(), platform_view.Pass(), +- render_view_host_delegate_view_); +- render_view_host_delegate_view_ = rv; +- view_.reset(rv); +- } else { +- // Regular WebContentsView. +- view_.reset(CreateWebContentsView( +- this, delegate, &render_view_host_delegate_view_)); ++ if (browser_plugin_guest_) { ++ scoped_ptr platform_view(CreateWebContentsView( ++ this, delegate, &render_view_host_delegate_view_)); ++ ++ WebContentsViewGuest* rv = new WebContentsViewGuest( ++ this, browser_plugin_guest_.get(), platform_view.Pass(), ++ render_view_host_delegate_view_); ++ render_view_host_delegate_view_ = rv; ++ view_.reset(rv); ++ } else { ++ // Regular WebContentsView. ++ view_.reset(CreateWebContentsView( ++ this, delegate, &render_view_host_delegate_view_)); ++ } + } + CHECK(render_view_host_delegate_view_); + CHECK(view_.get()); +@@ -1381,6 +1388,9 @@ + static_cast(session_storage_namespace); + CHECK(session_storage_namespace_impl->IsFromContext(dom_storage_context)); + ++ content::WebContentsView* view = NULL; ++ content::RenderViewHostDelegateView* delegate_view = NULL; ++ + if (delegate_ && + !delegate_->ShouldCreateWebContents(this, + route_id, +@@ -1388,7 +1398,9 @@ + params.frame_name, + params.target_url, + partition_id, +- session_storage_namespace)) { ++ session_storage_namespace, ++ &view, ++ &delegate_view)) { + if (route_id != MSG_ROUTING_NONE && + !RenderViewHost::FromID(render_process_id, route_id)) { + // If the embedder didn't create a WebContents for this route, we need to +@@ -1408,6 +1420,8 @@ + create_params.main_frame_routing_id = main_frame_route_id; + create_params.opener = this; + create_params.opener_suppressed = params.opener_suppressed; ++ create_params.view = view; ++ create_params.delegate_view = delegate_view; + if (params.disposition == NEW_BACKGROUND_TAB) + create_params.initially_hidden = true; + diff --git a/patch/patches/public_browser_1161.patch b/patch/patches/public_browser_1161.patch deleted file mode 100644 index 496a3c853..000000000 --- a/patch/patches/public_browser_1161.patch +++ /dev/null @@ -1,37 +0,0 @@ -Index: content_browser_client.cc -=================================================================== ---- content_browser_client.cc (revision 275973) -+++ content_browser_client.cc (working copy) -@@ -252,6 +252,10 @@ - return true; - } - -+SkColor ContentBrowserClient::GetBaseBackgroundColor(RenderViewHost* rvh) { -+ return SK_ColorWHITE; -+} -+ - base::FilePath ContentBrowserClient::GetDefaultDownloadDirectory() { - return base::FilePath(); - } -Index: content_browser_client.h -=================================================================== ---- content_browser_client.h (revision 275973) -+++ content_browser_client.h (working copy) -@@ -23,6 +23,7 @@ - #include "net/cookies/canonical_cookie.h" - #include "net/url_request/url_request_interceptor.h" - #include "net/url_request/url_request_job_factory.h" -+#include "third_party/skia/include/core/SkColor.h" - #include "third_party/WebKit/public/web/WebNotificationPresenter.h" - #include "ui/base/window_open_disposition.h" - #include "webkit/browser/fileapi/file_system_context.h" -@@ -533,6 +534,9 @@ - // Clears browser cookies. - virtual void ClearCookies(RenderViewHost* rvh) {} - -+ // Returns the base background color. -+ virtual SkColor GetBaseBackgroundColor(RenderViewHost* rvh); -+ - // Returns the default download directory. - // This can be called on any thread. - virtual base::FilePath GetDefaultDownloadDirectory(); diff --git a/patch/patches/public_browser_1161_1257.patch b/patch/patches/public_browser_1161_1257.patch new file mode 100644 index 000000000..6f927a15e --- /dev/null +++ b/patch/patches/public_browser_1161_1257.patch @@ -0,0 +1,132 @@ +Index: content_browser_client.cc +=================================================================== +--- content_browser_client.cc (revision 275973) ++++ content_browser_client.cc (working copy) +@@ -252,6 +252,10 @@ + return true; + } + ++SkColor ContentBrowserClient::GetBaseBackgroundColor(RenderViewHost* rvh) { ++ return SK_ColorWHITE; ++} ++ + base::FilePath ContentBrowserClient::GetDefaultDownloadDirectory() { + return base::FilePath(); + } +Index: content_browser_client.h +=================================================================== +--- content_browser_client.h (revision 275973) ++++ content_browser_client.h (working copy) +@@ -23,6 +23,7 @@ + #include "net/cookies/canonical_cookie.h" + #include "net/url_request/url_request_interceptor.h" + #include "net/url_request/url_request_job_factory.h" ++#include "third_party/skia/include/core/SkColor.h" + #include "third_party/WebKit/public/web/WebNotificationPresenter.h" + #include "ui/base/window_open_disposition.h" + #include "webkit/browser/fileapi/file_system_context.h" +@@ -533,6 +534,9 @@ + // Clears browser cookies. + virtual void ClearCookies(RenderViewHost* rvh) {} + ++ // Returns the base background color. ++ virtual SkColor GetBaseBackgroundColor(RenderViewHost* rvh); ++ + // Returns the default download directory. + // This can be called on any thread. + virtual base::FilePath GetDefaultDownloadDirectory(); +Index: web_contents.cc +=================================================================== +--- web_contents.cc (revision 275973) ++++ web_contents.cc (working copy) +@@ -17,7 +17,9 @@ + main_frame_routing_id(MSG_ROUTING_NONE), + initially_hidden(false), + guest_instance_id(0), +- context(NULL) {} ++ context(NULL), ++ view(NULL), ++ delegate_view(NULL) {} + + WebContents::CreateParams::CreateParams( + BrowserContext* context, SiteInstance* site) +@@ -29,7 +31,9 @@ + main_frame_routing_id(MSG_ROUTING_NONE), + initially_hidden(false), + guest_instance_id(0), +- context(NULL) {} ++ context(NULL), ++ view(NULL), ++ delegate_view(NULL) {} + + WebContents::CreateParams::~CreateParams() { + } +Index: web_contents.h +=================================================================== +--- web_contents.h (revision 275973) ++++ web_contents.h (working copy) +@@ -50,9 +50,11 @@ + class RenderFrameHost; + class RenderProcessHost; + class RenderViewHost; ++class RenderViewHostDelegateView; + class RenderWidgetHostView; + class SiteInstance; + class WebContentsDelegate; ++class WebContentsView; + struct CustomContextMenuContext; + struct DropData; + struct RendererPreferences; +@@ -120,6 +122,10 @@ + // Used to specify the location context which display the new view should + // belong. This can be NULL if not needed. + gfx::NativeView context; ++ ++ // Optionally specify the view and delegate view. ++ content::WebContentsView* view; ++ content::RenderViewHostDelegateView* delegate_view; + }; + + // Creates a new WebContents. +Index: web_contents_delegate.cc +=================================================================== +--- web_contents_delegate.cc (revision 275973) ++++ web_contents_delegate.cc (working copy) +@@ -136,7 +136,9 @@ + const base::string16& frame_name, + const GURL& target_url, + const std::string& partition_id, +- SessionStorageNamespace* session_storage_namespace) { ++ SessionStorageNamespace* session_storage_namespace, ++ content::WebContentsView** view, ++ content::RenderViewHostDelegateView** delegate_view) { + return true; + } + +Index: web_contents_delegate.h +=================================================================== +--- web_contents_delegate.h (revision 275973) ++++ web_contents_delegate.h (working copy) +@@ -36,9 +36,11 @@ + class JavaScriptDialogManager; + class PageState; + class RenderViewHost; ++class RenderViewHostDelegateView; + class SessionStorageNamespace; + class WebContents; + class WebContentsImpl; ++class WebContentsView; + struct ColorSuggestion; + struct ContextMenuParams; + struct DropData; +@@ -312,7 +314,9 @@ + const base::string16& frame_name, + const GURL& target_url, + const std::string& partition_id, +- SessionStorageNamespace* session_storage_namespace); ++ SessionStorageNamespace* session_storage_namespace, ++ content::WebContentsView** view, ++ content::RenderViewHostDelegateView** delegate_view); + + // Notifies the delegate about the creation of a new WebContents. This + // typically happens when popups are created. diff --git a/patch/patches/views_widget_180.patch b/patch/patches/views_widget_180.patch index 2d8c33b1a..b6d4856f3 100644 --- a/patch/patches/views_widget_180.patch +++ b/patch/patches/views_widget_180.patch @@ -11,6 +11,20 @@ Index: desktop_aura/desktop_screen_win.cc aura::WindowTreeHost* host = window->GetHost(); return host ? host->GetAcceleratedWidget() : NULL; } +Index: desktop_aura/desktop_screen_x11.cc +=================================================================== +--- desktop_aura/desktop_screen_x11.cc (revision 275973) ++++ desktop_aura/desktop_screen_x11.cc (working copy) +@@ -220,6 +220,9 @@ + + gfx::Display DesktopScreenX11::GetDisplayNearestWindow( + gfx::NativeView window) const { ++ if (!window) ++ return GetPrimaryDisplay(); ++ + // Getting screen bounds here safely is hard. + // + // You'd think we'd be able to just call window->GetBoundsInScreen(), but we Index: desktop_aura/desktop_window_tree_host_win.cc =================================================================== --- desktop_aura/desktop_window_tree_host_win.cc (revision 275973) diff --git a/patch/patches/webkit_popups.patch b/patch/patches/webkit_popups.patch new file mode 100644 index 000000000..15c92d564 --- /dev/null +++ b/patch/patches/webkit_popups.patch @@ -0,0 +1,76 @@ +Index: public/web/WebView.h +=================================================================== +--- public/web/WebView.h (revision 175829) ++++ public/web/WebView.h (working copy) +@@ -416,6 +416,7 @@ + + // Sets whether select popup menus should be rendered by the browser. + BLINK_EXPORT static void setUseExternalPopupMenus(bool); ++ virtual void setUseExternalPopupMenusThisInstance(bool) = 0; + + // Hides any popup (suggestions, selects...) that might be showing. + virtual void hidePopups() = 0; +Index: Source/web/ChromeClientImpl.cpp +=================================================================== +--- Source/web/ChromeClientImpl.cpp (revision 175829) ++++ Source/web/ChromeClientImpl.cpp (working copy) +@@ -729,7 +729,7 @@ + + PassRefPtr ChromeClientImpl::createPopupMenu(LocalFrame& frame, PopupMenuClient* client) const + { +- if (WebViewImpl::useExternalPopupMenus()) ++ if (m_webView->useExternalPopupMenus()) + return adoptRef(new ExternalPopupMenu(frame, client, *m_webView)); + + return adoptRef(new PopupMenuChromium(frame, client)); +Index: Source/web/WebViewImpl.cpp +=================================================================== +--- Source/web/WebViewImpl.cpp (revision 175829) ++++ Source/web/WebViewImpl.cpp (working copy) +@@ -365,6 +365,7 @@ + , m_fakePageScaleAnimationPageScaleFactor(0) + , m_fakePageScaleAnimationUseAnchor(false) + , m_contextMenuAllowed(false) ++ , m_shouldUseExternalPopupMenus(shouldUseExternalPopupMenus) + , m_doingDragAndDrop(false) + , m_ignoreInputEvents(false) + , m_compositorDeviceScaleFactorOverride(0) +@@ -3628,9 +3629,14 @@ + updateLayerTreeViewport(); + } + ++void WebViewImpl::setUseExternalPopupMenusThisInstance(bool useExternalPopupMenus) ++{ ++ m_shouldUseExternalPopupMenus = useExternalPopupMenus; ++} ++ + bool WebViewImpl::useExternalPopupMenus() + { +- return shouldUseExternalPopupMenus; ++ return m_shouldUseExternalPopupMenus; + } + + void WebViewImpl::startDragging(LocalFrame* frame, +Index: Source/web/WebViewImpl.h +=================================================================== +--- Source/web/WebViewImpl.h (revision 175829) ++++ Source/web/WebViewImpl.h (working copy) +@@ -352,7 +352,8 @@ + + // Returns true if popup menus should be rendered by the browser, false if + // they should be rendered by WebKit (which is the default). +- static bool useExternalPopupMenus(); ++ void setUseExternalPopupMenusThisInstance(bool); ++ bool useExternalPopupMenus(); + + bool contextMenuAllowed() const + { +@@ -628,6 +629,8 @@ + + bool m_contextMenuAllowed; + ++ bool m_shouldUseExternalPopupMenus; ++ + bool m_doingDragAndDrop; + + bool m_ignoreInputEvents; diff --git a/tests/cefclient/bytes_write_handler.cpp b/tests/cefclient/bytes_write_handler.cpp new file mode 100644 index 000000000..7b0692d22 --- /dev/null +++ b/tests/cefclient/bytes_write_handler.cpp @@ -0,0 +1,95 @@ +// Copyright (c) 2014 The Chromium Embedded Framework 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 "cefclient/bytes_write_handler.h" + +#include +#include + +#include "cefclient/util.h" + +BytesWriteHandler::BytesWriteHandler(size_t grow) + : grow_(grow), + datasize_(grow), + offset_(0) { + ASSERT(grow > 0); // NOLINT(readability/check) + data_ = malloc(grow); + ASSERT(data_ != NULL); +} + +BytesWriteHandler::~BytesWriteHandler() { + AutoLock lock_scope(this); + if (data_) + free(data_); +} + +size_t BytesWriteHandler::Write(const void* ptr, size_t size, size_t n) { + AutoLock lock_scope(this); + size_t rv; + if (offset_ + static_cast(size * n) >= datasize_ && + Grow(size * n) == 0) { + rv = 0; + } else { + memcpy(reinterpret_cast(data_) + offset_, ptr, size * n); + offset_ += size * n; + rv = n; + } + + return rv; +} + +int BytesWriteHandler::Seek(int64 offset, int whence) { + int rv = -1L; + AutoLock lock_scope(this); + switch (whence) { + case SEEK_CUR: + if (offset_ + offset > datasize_ || offset_ + offset < 0) + break; + offset_ += offset; + rv = 0; + break; + case SEEK_END: { + int64 offset_abs = std::abs(offset); + if (offset_abs > datasize_) + break; + offset_ = datasize_ - offset_abs; + rv = 0; + break; + } + case SEEK_SET: + if (offset > datasize_ || offset < 0) + break; + offset_ = offset; + rv = 0; + break; + } + + return rv; +} + +int64 BytesWriteHandler::Tell() { + AutoLock lock_scope(this); + return offset_; +} + +int BytesWriteHandler::Flush() { + return 0; +} + +size_t BytesWriteHandler::Grow(size_t size) { + AutoLock lock_scope(this); + size_t rv; + size_t s = (size > grow_ ? size : grow_); + void* tmp = realloc(data_, datasize_ + s); + ASSERT(tmp != NULL); + if (tmp) { + data_ = tmp; + datasize_ += s; + rv = datasize_; + } else { + rv = 0; + } + + return rv; +} diff --git a/tests/cefclient/bytes_write_handler.h b/tests/cefclient/bytes_write_handler.h new file mode 100644 index 000000000..653fcc854 --- /dev/null +++ b/tests/cefclient/bytes_write_handler.h @@ -0,0 +1,37 @@ +// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#ifndef CEF_TESTS_CEFCLIENT_BYTES_WRITE_HANDLER_H_ +#define CEF_TESTS_CEFCLIENT_BYTES_WRITE_HANDLER_H_ +#pragma once + +#include "include/cef_stream.h" + +class BytesWriteHandler : public CefWriteHandler { + public: + explicit BytesWriteHandler(size_t grow); + virtual ~BytesWriteHandler(); + + virtual size_t Write(const void* ptr, size_t size, size_t n) OVERRIDE; + virtual int Seek(int64 offset, int whence) OVERRIDE; + virtual int64 Tell() OVERRIDE; + virtual int Flush() OVERRIDE; + virtual bool MayBlock() OVERRIDE { return false; } + + void* GetData() { return data_; } + int64 GetDataSize() { return offset_; } + + protected: + size_t Grow(size_t size); + + size_t grow_; + void* data_; + int64 datasize_; + int64 offset_; + + IMPLEMENT_REFCOUNTING(BytesWriteHandler); + IMPLEMENT_LOCKING(BytesWriteHandler); +}; + +#endif // CEF_TESTS_CEFCLIENT_BYTES_WRITE_HANDLER_H_ diff --git a/tests/cefclient/cefclient.cpp b/tests/cefclient/cefclient.cpp index a1dd69a56..39fa16acf 100644 --- a/tests/cefclient/cefclient.cpp +++ b/tests/cefclient/cefclient.cpp @@ -62,6 +62,28 @@ void AppGetSettings(CefSettings& settings) { CefString(&settings.cache_path) = g_command_line->GetSwitchValue(cefclient::kCachePath); + + if (g_command_line->HasSwitch(cefclient::kOffScreenRenderingEnabled)) + settings.windowless_rendering_enabled = true; +} + +void AppGetBrowserSettings(CefBrowserSettings& settings) { + ASSERT(g_command_line.get()); + if (!g_command_line.get()) + return; + + if (g_command_line->HasSwitch(cefclient::kOffScreenFrameRate)) { + settings.windowless_frame_rate = atoi(g_command_line-> + GetSwitchValue(cefclient::kOffScreenFrameRate).ToString().c_str()); + } +} + +bool AppIsOffScreenRenderingEnabled() { + ASSERT(g_command_line.get()); + if (!g_command_line.get()) + return false; + + return g_command_line->HasSwitch(cefclient::kOffScreenRenderingEnabled); } void RunGetSourceTest(CefRefPtr browser) { diff --git a/tests/cefclient/cefclient.h b/tests/cefclient/cefclient.h index 5a467f02c..8f6d73bb9 100644 --- a/tests/cefclient/cefclient.h +++ b/tests/cefclient/cefclient.h @@ -32,6 +32,11 @@ CefRefPtr AppGetCommandLine(); // Returns the application settings based on command line arguments. void AppGetSettings(CefSettings& settings); +void AppGetBrowserSettings(CefBrowserSettings& settings); + +// Returns true if off-screen rendering is enabled via the command line +// argument. +bool AppIsOffScreenRenderingEnabled(); // Quit the application message loop. void AppQuitMessageLoop(); diff --git a/tests/cefclient/cefclient.rc b/tests/cefclient/cefclient.rc index a645797cf..18b8c4f84 100644 --- a/tests/cefclient/cefclient.rc +++ b/tests/cefclient/cefclient.rc @@ -33,6 +33,7 @@ IDS_DIALOGS BINARY "res\\dialogs.html" IDS_DOMACCESS BINARY "res\\domaccess.html" IDS_LOCALSTORAGE BINARY "res\\localstorage.html" IDS_LOGO BINARY "res\\logo.png" +IDS_OSRTEST BINARY "res\\osr_test.html" IDS_OTHER_TESTS BINARY "res\\other_tests.html" IDS_PERFORMANCE BINARY "res\\performance.html" IDS_PERFORMANCE2 BINARY "res\\performance2.html" diff --git a/tests/cefclient/cefclient_gtk.cpp b/tests/cefclient/cefclient_gtk.cpp index f30e014a9..ea104b4fa 100644 --- a/tests/cefclient/cefclient_gtk.cpp +++ b/tests/cefclient/cefclient_gtk.cpp @@ -2,13 +2,10 @@ // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. -// This value is defined in build/common.gypi and must be undefined here -// in order for gtkglext to compile. -#undef GTK_DISABLE_SINGLE_INCLUDES - #include #include #include +#include #include #undef Success // Definition conflicts with cef_message_router.h @@ -22,10 +19,12 @@ #include "include/cef_browser.h" #include "include/cef_frame.h" #include "include/cef_runnable.h" +#include "cefclient/cefclient_osr_widget_gtk.h" #include "cefclient/client_handler.h" #include "cefclient/client_switches.h" #include "cefclient/scheme_test.h" #include "cefclient/string_util.h" +#include "cefclient/util.h" // The global ClientHandler reference. extern CefRefPtr g_handler; @@ -37,6 +36,15 @@ char szWorkingDir[512]; // The current working directory // Height of the buttons at the top of the GTK window. int g_toolbar_height = 0; +class MainBrowserProvider : public OSRBrowserProvider { + virtual CefRefPtr GetBrowser() { + if (g_handler.get()) + return g_handler->GetBrowser(); + + return NULL; + } +} g_main_browser_provider; + void destroy(GtkWidget* widget, gpointer data) { // Quitting CEF is handled in ClientHandler::OnBeforeClose(). } @@ -69,7 +77,7 @@ void VboxSizeAllocated(GtkWidget *widget, void *data) { if (g_handler) { CefRefPtr browser = g_handler->GetBrowser(); - if (browser) { + if (browser && !browser->GetHost()->IsWindowRenderingDisabled()) { // Size the browser window to match the GTK widget. ::Display* xdisplay = cef_get_xdisplay(); ::Window xwindow = browser->GetHost()->GetWindowHandle(); @@ -93,9 +101,14 @@ gboolean WindowFocusIn(GtkWidget* widget, if (g_handler && event->in) { CefRefPtr browser = g_handler->GetBrowser(); if (browser) { - // Give focus to the browser window. - browser->GetHost()->SetFocus(true); - return TRUE; + if (browser->GetHost()->IsWindowRenderingDisabled()) { + // Give focus to the off-screen browser. + browser->GetHost()->SendFocusEvent(true); + } else { + // Give focus to the browser window. + browser->GetHost()->SetFocus(true); + return TRUE; + } } } @@ -303,6 +316,11 @@ GtkWidget* CreateMenuBar() { } // namespace int main(int argc, char* argv[]) { + // Create a copy of |argv| on Linux because Chromium mangles the value + // internally (see issue #620). + ScopedArgArray scoped_arg_array(argc, argv); + char** argv_copy = scoped_arg_array.array(); + CefMainArgs main_args(argc, argv); CefRefPtr app(new ClientApp); @@ -315,7 +333,7 @@ int main(int argc, char* argv[]) { return -1; // Parse command line arguments. - AppInitCommandLine(argc, argv); + AppInitCommandLine(argc, argv_copy); CefSettings settings; @@ -327,7 +345,10 @@ int main(int argc, char* argv[]) { // The Chromium sandbox requires that there only be a single thread during // initialization. Therefore initialize GTK after CEF. - gtk_init(&argc, &argv); + gtk_init(&argc, &argv_copy); + + // Perform gtkglext initialization required by the OSR example. + gtk_gl_init(&argc, &argv_copy); // Register the scheme handler. scheme_test::InitTest(); @@ -397,16 +418,38 @@ int main(int argc, char* argv[]) { g_handler->SetButtonHwnds(GTK_WIDGET(back), GTK_WIDGET(forward), GTK_WIDGET(reload), GTK_WIDGET(stop)); - // Show the GTK window. - gtk_widget_show_all(GTK_WIDGET(window)); - CefWindowInfo window_info; CefBrowserSettings browserSettings; - // The GTK window must be visible before we can retrieve the XID. - ::Window xwindow = GDK_WINDOW_XID(gtk_widget_get_window(window)); - window_info.SetAsChild(xwindow, - CefRect(0, g_toolbar_height, 800, 600 - g_toolbar_height)); + // Populate the browser settings based on command line arguments. + AppGetBrowserSettings(browserSettings); + + if (AppIsOffScreenRenderingEnabled()) { + CefRefPtr cmd_line = AppGetCommandLine(); + bool transparent = + cmd_line->HasSwitch(cefclient::kTransparentPaintingEnabled); + + // Create the GTKGL surface. + CefRefPtr osr_window = + OSRWindow::Create(&g_main_browser_provider, transparent, vbox); + + // Show the GTK window. + gtk_widget_show_all(GTK_WIDGET(window)); + + // The GTK window must be visible before we can retrieve the XID. + ::Window xwindow = + GDK_WINDOW_XID(gtk_widget_get_window(osr_window->GetWindowHandle())); + window_info.SetAsWindowless(xwindow, transparent); + g_handler->SetOSRHandler(osr_window.get()); + } else { + // Show the GTK window. + gtk_widget_show_all(GTK_WIDGET(window)); + + // The GTK window must be visible before we can retrieve the XID. + ::Window xwindow = GDK_WINDOW_XID(gtk_widget_get_window(window)); + window_info.SetAsChild(xwindow, + CefRect(0, g_toolbar_height, 800, 600 - g_toolbar_height)); + } // Create the browser window. CefBrowserHost::CreateBrowserSync( diff --git a/tests/cefclient/cefclient_mac.mm b/tests/cefclient/cefclient_mac.mm index 4f23e58cc..d44b783ae 100644 --- a/tests/cefclient/cefclient_mac.mm +++ b/tests/cefclient/cefclient_mac.mm @@ -11,6 +11,7 @@ #include "include/cef_browser.h" #include "include/cef_frame.h" #include "include/cef_runnable.h" +#include "cefclient/cefclient_osr_widget_mac.h" #include "cefclient/client_handler.h" #include "cefclient/client_switches.h" #include "cefclient/resource_util.h" @@ -20,6 +21,15 @@ // The global ClientHandler reference. extern CefRefPtr g_handler; +class MainBrowserProvider : public OSRBrowserProvider { + virtual CefRefPtr GetBrowser() { + if (g_handler.get()) + return g_handler->GetBrowser(); + + return NULL; + } +} g_main_browser_provider; + char szWorkingDir[512]; // The current working directory // Sizes for URL bar layout @@ -206,8 +216,12 @@ const int kWindowHeight = 600; - (void)windowDidBecomeKey:(NSNotification*)notification { if (g_handler.get()) { CefRefPtr browser = g_handler->GetBrowser(); - if (browser.get()) - browser->GetHost()->SetFocus(true); + if (browser.get()) { + if (AppIsOffScreenRenderingEnabled()) + browser->GetHost()->SendFocusEvent(true); + else + browser->GetHost()->SetFocus(true); + } } } @@ -215,8 +229,12 @@ const int kWindowHeight = 600; - (void)windowDidResignKey:(NSNotification*)notification { if (g_handler.get()) { CefRefPtr browser = g_handler->GetBrowser(); - if (browser.get()) - browser->GetHost()->SetFocus(false); + if (browser.get()) { + if (AppIsOffScreenRenderingEnabled()) + browser->GetHost()->SendFocusEvent(false); + else + browser->GetHost()->SetFocus(false); + } } } @@ -436,8 +454,23 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) { CefWindowInfo window_info; CefBrowserSettings settings; - // Initialize window info to the defaults for a child window. - window_info.SetAsChild(contentView, 0, 0, kWindowWidth, kWindowHeight); + // Populate the browser settings based on command line arguments. + AppGetBrowserSettings(settings); + + if (AppIsOffScreenRenderingEnabled()) { + CefRefPtr cmd_line = AppGetCommandLine(); + bool transparent = + cmd_line->HasSwitch(cefclient::kTransparentPaintingEnabled); + + CefRefPtr osr_window = + OSRWindow::Create(&g_main_browser_provider, transparent, contentView, + CefRect(0, 0, kWindowWidth, kWindowHeight)); + window_info.SetAsWindowless(osr_window->GetWindowHandle(), transparent); + g_handler->SetOSRHandler(osr_window->GetRenderHandler().get()); + } else { + // Initialize window info to the defaults for a child window. + window_info.SetAsChild(contentView, 0, 0, kWindowWidth, kWindowHeight); + } CefBrowserHost::CreateBrowser(window_info, g_handler.get(), g_handler->GetStartupURL(), settings, NULL); diff --git a/tests/cefclient/cefclient_osr_dragdrop_win.cpp b/tests/cefclient/cefclient_osr_dragdrop_win.cpp new file mode 100644 index 000000000..a8bdcd0b9 --- /dev/null +++ b/tests/cefclient/cefclient_osr_dragdrop_win.cpp @@ -0,0 +1,649 @@ +// Copyright (c) 2014 The Chromium Embedded Framework 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 "cefclient/cefclient_osr_dragdrop_win.h" + +#include +#include +#include + +#include +#include + +#include "include/cef_runnable.h" +#include "cefclient/bytes_write_handler.h" +#include "cefclient/cefclient_osr_widget_win.h" +#include "cefclient/resource.h" +#include "cefclient/util.h" + +namespace { + +DWORD DragOperationToDropEffect(CefRenderHandler::DragOperation allowed_ops) { + DWORD effect = DROPEFFECT_NONE; + if (allowed_ops & DRAG_OPERATION_COPY) + effect |= DROPEFFECT_COPY; + if (allowed_ops & DRAG_OPERATION_LINK) + effect |= DROPEFFECT_LINK; + if (allowed_ops & DRAG_OPERATION_MOVE) + effect |= DROPEFFECT_MOVE; + return effect; +} + +CefRenderHandler::DragOperationsMask DropEffectToDragOperation(DWORD effect) { + DWORD operation = DRAG_OPERATION_NONE; + if (effect & DROPEFFECT_COPY) + operation |= DRAG_OPERATION_COPY; + if (effect & DROPEFFECT_LINK) + operation |= DRAG_OPERATION_LINK; + if (effect & DROPEFFECT_MOVE) + operation |= DRAG_OPERATION_MOVE; + return static_cast(operation); +} + +CefMouseEvent ToMouseEvent(POINTL p, DWORD key_state, HWND hWnd) { + CefMouseEvent ev; + POINT screen_point = { p.x, p.y }; + ScreenToClient(hWnd, &screen_point); + ev.x = screen_point.x; + ev.y = screen_point.y; + ev.modifiers = OSRWindow::GetCefMouseModifiers(key_state); + return ev; +} + + +void GetStorageForBytes(STGMEDIUM* storage, const void* data, size_t bytes) { + HANDLE handle = GlobalAlloc(GPTR, static_cast(bytes)); + if (handle) { + memcpy(handle, data, bytes); + } + + storage->hGlobal = handle; + storage->tymed = TYMED_HGLOBAL; + storage->pUnkForRelease = NULL; +} + +template +void GetStorageForString(STGMEDIUM* stgmed, const std::basic_string& data) { + GetStorageForBytes(stgmed, data.c_str(), + (data.size() + 1) * sizeof(std::basic_string::value_type)); +} + +void GetStorageForFileDescriptor(STGMEDIUM* storage, + const std::wstring& file_name) { + ASSERT(!file_name.empty()); + HANDLE hdata = GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTOR)); + + FILEGROUPDESCRIPTOR* descriptor = + reinterpret_cast(hdata); + descriptor->cItems = 1; + descriptor->fgd[0].dwFlags = FD_LINKUI; + wcsncpy_s(descriptor->fgd[0].cFileName, MAX_PATH, file_name.c_str(), + std::min(file_name.size(), static_cast(MAX_PATH - 1u))); + + storage->tymed = TYMED_HGLOBAL; + storage->hGlobal = hdata; + storage->pUnkForRelease = NULL; +} + +// Helper method for converting from text/html to MS CF_HTML. +// Documentation for the CF_HTML format is available at +// http://msdn.microsoft.com/en-us/library/aa767917(VS.85).aspx +std::string HtmlToCFHtml(const std::string& html, const std::string& base_url) { + if (html.empty()) + return std::string(); + +#define MAX_DIGITS 10 +#define MAKE_NUMBER_FORMAT_1(digits) MAKE_NUMBER_FORMAT_2(digits) +#define MAKE_NUMBER_FORMAT_2(digits) "%0" #digits "u" +#define NUMBER_FORMAT MAKE_NUMBER_FORMAT_1(MAX_DIGITS) + + static const char* header = "Version:0.9\r\n" + "StartHTML:" NUMBER_FORMAT "\r\n" + "EndHTML:" NUMBER_FORMAT "\r\n" + "StartFragment:" NUMBER_FORMAT "\r\n" + "EndFragment:" NUMBER_FORMAT "\r\n"; + static const char* source_url_prefix = "SourceURL:"; + + static const char* start_markup = "\r\n\r\n"; + static const char* end_markup = "\r\n\r\n"; + + // Calculate offsets + size_t start_html_offset = strlen(header) - strlen(NUMBER_FORMAT) * 4 + + MAX_DIGITS * 4; + if (!base_url.empty()) { + start_html_offset += strlen(source_url_prefix) + base_url.length() + + 2; // Add 2 for \r\n. + } + size_t start_fragment_offset = start_html_offset + strlen(start_markup); + size_t end_fragment_offset = start_fragment_offset + html.length(); + size_t end_html_offset = end_fragment_offset + strlen(end_markup); + char raw_result[1024]; + _snprintf(raw_result, sizeof(1024), + header, + start_html_offset, + end_html_offset, + start_fragment_offset, + end_fragment_offset); + std::string result = raw_result; + if (!base_url.empty()) { + result.append(source_url_prefix); + result.append(base_url); + result.append("\r\n"); + } + result.append(start_markup); + result.append(html); + result.append(end_markup); + +#undef MAX_DIGITS +#undef MAKE_NUMBER_FORMAT_1 +#undef MAKE_NUMBER_FORMAT_2 +#undef NUMBER_FORMAT + + return result; +} + +void CFHtmlExtractMetadata(const std::string& cf_html, + std::string* base_url, + size_t* html_start, + size_t* fragment_start, + size_t* fragment_end) { + // Obtain base_url if present. + if (base_url) { + static std::string src_url_str("SourceURL:"); + size_t line_start = cf_html.find(src_url_str); + if (line_start != std::string::npos) { + size_t src_end = cf_html.find("\n", line_start); + size_t src_start = line_start + src_url_str.length(); + if (src_end != std::string::npos && src_start != std::string::npos) { + *base_url = cf_html.substr(src_start, src_end - src_start); + } + } + } + + // Find the markup between "" and "". + // If the comments cannot be found, like copying from OpenOffice Writer, + // we simply fall back to using StartFragment/EndFragment bytecount values + // to determine the fragment indexes. + std::string cf_html_lower = cf_html; + size_t markup_start = cf_html_lower.find("(atoi(cf_html.c_str() + + start_fragment_start + start_fragment_str.length())); + } + + static std::string end_fragment_str("EndFragment:"); + size_t end_fragment_start = cf_html.find(end_fragment_str); + if (end_fragment_start != std::string::npos) { + *fragment_end = static_cast(atoi(cf_html.c_str() + + end_fragment_start + end_fragment_str.length())); + } + } else { + *fragment_start = cf_html.find('>', tag_start) + 1; + size_t tag_end = cf_html.rfind("