diff --git a/cef.gyp b/cef.gyp index e28dec175..f741a08ac 100644 --- a/cef.gyp +++ b/cef.gyp @@ -89,6 +89,10 @@ 'tests/cefclient/cefclient_win.cpp', 'tests/cefclient/clientplugin.cpp', 'tests/cefclient/clientplugin.h', + 'tests/cefclient/osrlugin.cpp', + 'tests/cefclient/osrplugin.h', + 'tests/cefclient/osrplugin_test.cpp', + 'tests/cefclient/osrplugin_test.h', 'tests/cefclient/plugin_test.cpp', 'tests/cefclient/plugin_test.h', 'tests/cefclient/Resource.h', @@ -620,6 +624,7 @@ 'libcef/v8_impl.h', 'libcef/web_urlrequest_impl.cc', 'libcef/web_urlrequest_impl.h', + 'libcef/webview_host.cc', 'libcef/webview_host.h', 'libcef/webwidget_host.cc', 'libcef/webwidget_host.h', diff --git a/include/cef.h b/include/cef.h index 745bfff58..439d33385 100644 --- a/include/cef.h +++ b/include/cef.h @@ -85,12 +85,24 @@ bool CefInitialize(const CefSettings& settings, /*--cef()--*/ void CefShutdown(); -// Perform message loop processing. This function must be called on the main -// application thread if CefInitialize() is called with a -// CefSettings.multi_threaded_message_loop value of false. +// Perform a single iteration of CEF message loop processing. This function is +// used to integrate the CEF message loop into an existing application message +// loop. Care must be taken to balance performance against excessive CPU usage. +// This function should only be called on the main application thread and only +// if CefInitialize() is called with a CefSettings.multi_threaded_message_loop +// value of false. This function will not block. /*--cef()--*/ void CefDoMessageLoopWork(); +// Run the CEF message loop. Use this function instead of an application- +// provided message loop to get the best balance between performance and CPU +// usage. This function should only be called on the main application thread and +// only if CefInitialize() is called with a +// CefSettings.multi_threaded_message_loop value of false. This function will +// block until a quit message is received by the system. +/*--cef()--*/ +void CefRunMessageLoop(); + // Register a new V8 extension with the specified JavaScript extension code and // handler. Functions implemented by the handler are prototyped using the // keyword 'native'. The calling of a native function is restricted to the scope @@ -242,7 +254,7 @@ public: virtual int Release() =0; // Return the current number of references. - virtual int GetRefCt() = 0; + virtual int GetRefCt() =0; }; @@ -396,6 +408,10 @@ public: class CefBrowser : public CefBase { public: + typedef cef_key_type_t KeyType; + typedef cef_mouse_button_type_t MouseButtonType; + typedef cef_paint_element_type_t PaintElementType; + // Create a new browser window using the window parameters specified by // |windowInfo|. All values will be copied internally and the actual window // will be created on the UI thread. The |popup| parameter should be true if @@ -505,6 +521,73 @@ public: // instance. /*--cef()--*/ virtual void CloseDevTools() =0; + + // Returns true if window rendering is disabled. + /*--cef()--*/ + virtual bool IsWindowRenderingDisabled() =0; + + // Get the size of the specified element. This method should only be called on + // the UI thread. + /*--cef()--*/ + virtual bool GetSize(PaintElementType type, int& width, int& height) =0; + + // Set the size of the specified element. This method is only used when window + // rendering is disabled. + /*--cef()--*/ + virtual void SetSize(PaintElementType type, int width, int height) =0; + + // Returns true if a popup is currently visible. This method should only be + // called on the UI thread. + /*--cef()--*/ + virtual bool IsPopupVisible() =0; + + // Hide the currently visible popup, if any. + /*--cef()--*/ + virtual void HidePopup() =0; + + // Invalidate the |dirtyRect| region of the view. This method is only used + // when window rendering is disabled and will result in a call to + // HandlePaint(). + /*--cef()--*/ + virtual void Invalidate(const CefRect& dirtyRect) =0; + + // Get the raw image data contained in the specified element without + // performing validation. The specified |width| and |height| dimensions must + // match the current element size. On Windows |buffer| must be width*height*4 + // bytes in size and represents a BGRA image with an upper-left origin. This + // method should only be called on the UI thread. + /*--cef()--*/ + virtual bool GetImage(PaintElementType type, int width, int height, + void* buffer) =0; + + // Send a key event to the browser. + /*--cef()--*/ + virtual void SendKeyEvent(KeyType type, int key, int modifiers, bool sysChar, + bool imeChar) =0; + + // Send a mouse click event to the browser. The |x| and |y| coordinates are + // relative to the upper-left corner of the view. + /*--cef()--*/ + virtual void SendMouseClickEvent(int x, int y, MouseButtonType type, + bool mouseUp, int clickCount) =0; + + // Send a mouse move event to the browser. The |x| and |y| coordinates are + // relative to the upper-left corner of the view. + /*--cef()--*/ + virtual void SendMouseMoveEvent(int x, int y, bool mouseLeave) =0; + + // Send a mouse wheel event to the browser. The |x| and |y| coordinates are + // relative to the upper-left corner of the view. + /*--cef()--*/ + virtual void SendMouseWheelEvent(int x, int y, int delta) =0; + + // Send a focus event to the browser. + /*--cef()--*/ + virtual void SendFocusEvent(bool setFocus) =0; + + // Send a capture lost event to the browser. + /*--cef()--*/ + virtual void SendCaptureLostEvent() =0; }; @@ -662,6 +745,12 @@ public: virtual RetVal HandleTitleChange(CefRefPtr browser, const CefString& title) =0; + // Called on the UI thread when the navigation state has changed. The return + // value is currently ignored. + /*--cef()--*/ + virtual RetVal HandleNavStateChange(CefRefPtr browser, + bool canGoBack, bool canGoForward) =0; + // Various browser navigation types supported by chrome. typedef cef_handler_navtype_t NavType; @@ -805,7 +894,7 @@ public: // options or RV_HANDLED to display the modified |printOptions|. /*--cef()--*/ virtual RetVal HandlePrintOptions(CefRefPtr browser, - CefPrintOptions& printOptions) = 0; + CefPrintOptions& printOptions) =0; // Called on the UI thread to format print headers and footers. |printInfo| // contains platform-specific information about the printer context. |url| is @@ -943,8 +1032,56 @@ public: int identifier, int count, const CefRect& selectionRect, int activeMatchOrdinal, bool finalUpdate) =0; -}; + // Called on the UI thread to retrieve either the simulated screen rectangle + // if |screen| is true or the view rectangle if |screen| is false. The view + // rectangle is relative to the screen coordinates. This method is only called + // if window rendering has been disabled. Return RV_CONTINUE if the rectangle + // was provided. + /*--cef()--*/ + virtual RetVal HandleGetRect(CefRefPtr browser, bool screen, + CefRect& rect) =0; + + // Called on the UI thread retrieve the translation from view coordinates to + // actual screen coordinates. This method is only called if window rendering + // has been disabled. Return RV_CONTINUE if the screen coordinates were + // provided. + /*--cef()--*/ + virtual RetVal HandleGetScreenPoint(CefRefPtr browser, + int viewX, int viewY, int& screenX, + int& screenY) =0; + + // Called on the UI thread when the browser wants to show, hide, resize or + // move the popup. If |show| is true and |rect| is zero size then the popup + // should be shown. If |show| is true and |rect| is non-zero size then |rect| + // represents the popup location in view coordinates. If |show| is false + // then the popup should be hidden. This method is only called if window + // rendering has been disabled. The return value is currently ignored. + /*--cef()--*/ + virtual RetVal HandlePopupChange(CefRefPtr browser, bool show, + const CefRect& rect) =0; + + typedef cef_paint_element_type_t PaintElementType; + + // Called when an element should be painted. |type| indicates whether the + // element is the view or the popup. |buffer| contains the pixel data for the + // whole image. |dirtyRect| indicates the portion of the image that has been + // repainted. On Windows |buffer| will be width*height*4 bytes in size and + // represents a BGRA image with an upper-left origin. This method is only + // called if window rendering has been disabled. The return value is currently + // ignored. + /*--cef()--*/ + virtual RetVal HandlePaint(CefRefPtr browser, + PaintElementType type, const CefRect& dirtyRect, + const void* buffer) =0; + + // Called when the browser window's cursor has changed. This method is only + // called if window rendering has been disabled. The return value is currently + // ignored. + /*--cef()--*/ + virtual RetVal HandleCursorChange(CefRefPtr browser, + CefCursorHandle cursor) =0; +}; // Class used to represent a web request. The methods of this class may be // called on any thread. @@ -993,16 +1130,16 @@ public: // Optional flags. Used in combination with CefWebURLRequest. /*--cef()--*/ - virtual RequestFlags GetFlags() = 0; + virtual RequestFlags GetFlags() =0; /*--cef()--*/ - virtual void SetFlags(RequestFlags flags) = 0; + virtual void SetFlags(RequestFlags flags) =0; // Optional URL to the first party for cookies. Used in combination with // CefWebURLRequest. /*--cef()--*/ - virtual CefString GetFirstPartyForCookies() = 0; + virtual CefString GetFirstPartyForCookies() =0; /*--cef()--*/ - virtual void SetFirstPartyForCookies(const CefString& url) = 0; + virtual void SetFirstPartyForCookies(const CefString& url) =0; }; @@ -1096,15 +1233,15 @@ public: // Returns the response status code. /*--cef()--*/ - virtual int GetStatus() = 0; + virtual int GetStatus() =0; // Returns the response status text. /*--cef()--*/ - virtual CefString GetStatusText() = 0; + virtual CefString GetStatusText() =0; // Returns the value for the specified response header field. /*--cef()--*/ - virtual CefString GetHeader(const CefString& name) = 0; + virtual CefString GetHeader(const CefString& name) =0; // Retrieves a map of all response header fields. /*--cef()--*/ diff --git a/include/cef_capi.h b/include/cef_capi.h index 8cd20e64e..5851f1223 100644 --- a/include/cef_capi.h +++ b/include/cef_capi.h @@ -58,11 +58,22 @@ CEF_EXPORT int cef_initialize(const struct _cef_settings_t* settings, // CEF before the application exits. CEF_EXPORT void cef_shutdown(); -// Perform message loop processing. This function must be called on the main -// application thread if cef_initialize() is called with a -// CefSettings.multi_threaded_message_loop value of false (0). +// Perform a single iteration of CEF message loop processing. This function is +// used to integrate the CEF message loop into an existing application message +// loop. Care must be taken to balance performance against excessive CPU usage. +// This function should only be called on the main application thread and only +// if cef_initialize() is called with a CefSettings.multi_threaded_message_loop +// value of false (0). This function will not block. CEF_EXPORT void cef_do_message_loop_work(); +// Run the CEF message loop. Use this function instead of an application- +// provided message loop to get the best balance between performance and CPU +// usage. This function should only be called on the main application thread and +// only if cef_initialize() is called with a +// CefSettings.multi_threaded_message_loop value of false (0). This function +// will block until a quit message is received by the system. +CEF_EXPORT void cef_run_message_loop(); + // Register a new V8 extension with the specified JavaScript extension code and // handler. Functions implemented by the handler are prototyped using the // keyword 'native'. The calling of a native function is restricted to the scope @@ -316,6 +327,69 @@ typedef struct _cef_browser_t // instance. void (CEF_CALLBACK *close_dev_tools)(struct _cef_browser_t* self); + // Returns true (1) if window rendering is disabled. + int (CEF_CALLBACK *is_window_rendering_disabled)(struct _cef_browser_t* self); + + // Get the size of the specified element. This function should only be called + // on the UI thread. + int (CEF_CALLBACK *get_size)(struct _cef_browser_t* self, + enum cef_paint_element_type_t type, int* width, int* height); + + // Set the size of the specified element. This function is only used when + // window rendering is disabled. + void (CEF_CALLBACK *set_size)(struct _cef_browser_t* self, + enum cef_paint_element_type_t type, int width, int height); + + // Returns true (1) if a popup is currently visible. This function should only + // be called on the UI thread. + int (CEF_CALLBACK *is_popup_visible)(struct _cef_browser_t* self); + + // Hide the currently visible popup, if any. + void (CEF_CALLBACK *hide_popup)(struct _cef_browser_t* self); + + // Invalidate the |dirtyRect| region of the view. This function is only used + // when window rendering is disabled and will result in a call to + // handle_paint(). + void (CEF_CALLBACK *invalidate)(struct _cef_browser_t* self, + const cef_rect_t* dirtyRect); + + // Get the raw image data contained in the specified element without + // performing validation. The specified |width| and |height| dimensions must + // match the current element size. On Windows |buffer| must be width*height*4 + // bytes in size and represents a BGRA image with an upper-left origin. This + // function should only be called on the UI thread. + int (CEF_CALLBACK *get_image)(struct _cef_browser_t* self, + enum cef_paint_element_type_t type, int width, int height, + void* buffer); + + // Send a key event to the browser. + void (CEF_CALLBACK *send_key_event)(struct _cef_browser_t* self, + enum cef_key_type_t type, int key, int modifiers, int sysChar, + int imeChar); + + // Send a mouse click event to the browser. The |x| and |y| coordinates are + // relative to the upper-left corner of the view. + void (CEF_CALLBACK *send_mouse_click_event)(struct _cef_browser_t* self, + int x, int y, enum cef_mouse_button_type_t type, int mouseUp, + int clickCount); + + // Send a mouse move event to the browser. The |x| and |y| coordinates are + // relative to the upper-left corner of the view. + void (CEF_CALLBACK *send_mouse_move_event)(struct _cef_browser_t* self, int x, + int y, int mouseLeave); + + // Send a mouse wheel event to the browser. The |x| and |y| coordinates are + // relative to the upper-left corner of the view. + void (CEF_CALLBACK *send_mouse_wheel_event)(struct _cef_browser_t* self, + int x, int y, int delta); + + // Send a focus event to the browser. + void (CEF_CALLBACK *send_focus_event)(struct _cef_browser_t* self, + int setFocus); + + // Send a capture lost event to the browser. + void (CEF_CALLBACK *send_capture_lost_event)(struct _cef_browser_t* self); + } cef_browser_t; @@ -473,6 +547,12 @@ typedef struct _cef_handler_t struct _cef_handler_t* self, struct _cef_browser_t* browser, const cef_string_t* title); + // Called on the UI thread when the navigation state has changed. The return + // value is currently ignored. + enum cef_retval_t (CEF_CALLBACK *handle_nav_state_change)( + struct _cef_handler_t* self, struct _cef_browser_t* browser, + int canGoBack, int canGoForward); + // Called on the UI thread before browser navigation. The client has an // opportunity to modify the |request| object if desired. Return RV_HANDLED // to cancel navigation. @@ -703,6 +783,50 @@ typedef struct _cef_handler_t int identifier, int count, const cef_rect_t* selectionRect, int activeMatchOrdinal, int finalUpdate); + // Called on the UI thread to retrieve either the simulated screen rectangle + // if |screen| is true (1) or the view rectangle if |screen| is false (0). The + // view rectangle is relative to the screen coordinates. This function is only + // called if window rendering has been disabled. Return RV_CONTINUE if the + // rectangle was provided. + enum cef_retval_t (CEF_CALLBACK *handle_get_rect)(struct _cef_handler_t* self, + struct _cef_browser_t* browser, int screen, cef_rect_t* rect); + + // Called on the UI thread retrieve the translation from view coordinates to + // actual screen coordinates. This function is only called if window rendering + // has been disabled. Return RV_CONTINUE if the screen coordinates were + // provided. + enum cef_retval_t (CEF_CALLBACK *handle_get_screen_point)( + struct _cef_handler_t* self, struct _cef_browser_t* browser, int viewX, + int viewY, int* screenX, int* screenY); + + // Called on the UI thread when the browser wants to show, hide, resize or + // move the popup. If |show| is true (1) and |rect| is zero size then the + // popup should be shown. If |show| is true (1) and |rect| is non-zero size + // then |rect| represents the popup location in view coordinates. If |show| is + // false (0) then the popup should be hidden. This function is only called if + // window rendering has been disabled. The return value is currently ignored. + enum cef_retval_t (CEF_CALLBACK *handle_popup_change)( + struct _cef_handler_t* self, struct _cef_browser_t* browser, int show, + const cef_rect_t* rect); + + // Called when an element should be painted. |type| indicates whether the + // element is the view or the popup. |buffer| contains the pixel data for the + // whole image. |dirtyRect| indicates the portion of the image that has been + // repainted. On Windows |buffer| will be width*height*4 bytes in size and + // represents a BGRA image with an upper-left origin. This function is only + // called if window rendering has been disabled. The return value is currently + // ignored. + enum cef_retval_t (CEF_CALLBACK *handle_paint)(struct _cef_handler_t* self, + struct _cef_browser_t* browser, enum cef_paint_element_type_t type, + const cef_rect_t* dirtyRect, const void* buffer); + + // Called when the browser window's cursor has changed. This function is only + // called if window rendering has been disabled. The return value is currently + // ignored. + enum cef_retval_t (CEF_CALLBACK *handle_cursor_change)( + struct _cef_handler_t* self, struct _cef_browser_t* browser, + cef_cursor_handle_t cursor); + } cef_handler_t; diff --git a/include/cef_linux.h b/include/cef_linux.h index 8653ce6ad..bf55927fc 100644 --- a/include/cef_linux.h +++ b/include/cef_linux.h @@ -73,8 +73,9 @@ public: pthread_mutexattr_t attr_; }; -// Window handle. +// Handle types. #define CefWindowHandle cef_window_handle_t +#define CefCursorHandle cef_cursor_handle_t // Class representing window information. class CefWindowInfo : public cef_window_info_t diff --git a/include/cef_mac.h b/include/cef_mac.h index 19c55bc61..f42275f92 100644 --- a/include/cef_mac.h +++ b/include/cef_mac.h @@ -45,8 +45,9 @@ inline long CefAtomicDecrement(long volatile *pDest) return __sync_sub_and_fetch(pDest, 1); } -// Window handle. +// Handle types. #define CefWindowHandle cef_window_handle_t +#define CefCursorHandle cef_cursor_handle_t // Critical section wrapper. class CefCriticalSection diff --git a/include/cef_types.h b/include/cef_types.h index dddee811f..f3561e687 100644 --- a/include/cef_types.h +++ b/include/cef_types.h @@ -269,6 +269,22 @@ typedef struct _cef_urlparts_t cef_string_t query; } cef_urlparts_t; +// Mouse button types. +enum cef_mouse_button_type_t +{ + MBT_LEFT = 0, + MBT_MIDDLE, + MBT_RIGHT, +}; + +// Key types. +enum cef_key_type_t +{ + KT_KEYUP = 0, + KT_KEYDOWN, + KT_CHAR, +}; + // Define handler return value types. Returning RV_HANDLED indicates // that the implementation completely handled the method and that no further // processing is required. Returning RV_CONTINUE indicates that the @@ -348,16 +364,24 @@ enum cef_handler_errorcode_t // Structure representing menu information. typedef struct _cef_handler_menuinfo_t { + // Values from the cef_handler_menutypebits_t enumeration. int typeFlags; + + // If window rendering is enabled |x| and |y| will be in screen coordinates. + // Otherwise, |x| and |y| will be in view coordinates. int x; int y; + cef_string_t linkUrl; cef_string_t imageUrl; cef_string_t pageUrl; cef_string_t frameUrl; cef_string_t selectionText; cef_string_t misspelledWord; + + // Values from the cef_handler_menucapabilitybits_t enumeration. int editFlags; + cef_string_t securityInfo; } cef_handler_menuinfo_t; @@ -425,6 +449,12 @@ enum cef_handler_menuid_t MENU_ID_VIEWSOURCE = 31, }; +enum cef_paint_element_type_t +{ + PET_VIEW = 0, + PET_POPUP, +}; + // Post data elements may represent either bytes or files. enum cef_postdataelement_type_t { diff --git a/include/cef_types_linux.h b/include/cef_types_linux.h index 328ee63f1..5cc291f14 100644 --- a/include/cef_types_linux.h +++ b/include/cef_types_linux.h @@ -41,6 +41,7 @@ extern "C" { // Window handle. #define cef_window_handle_t GtkWidget* +#define cef_cursor_handle_t void* // Class representing window information. typedef struct _cef_window_info_t diff --git a/include/cef_types_mac.h b/include/cef_types_mac.h index 4afba9991..1ec632c39 100644 --- a/include/cef_types_mac.h +++ b/include/cef_types_mac.h @@ -45,6 +45,7 @@ class NSView; #else #define cef_window_handle_t void* #endif +#define cef_cursor_handle_t void* #ifdef __cplusplus extern "C" { diff --git a/include/cef_types_win.h b/include/cef_types_win.h index 89e5a1f1c..6ca6fba2d 100644 --- a/include/cef_types_win.h +++ b/include/cef_types_win.h @@ -41,6 +41,7 @@ extern "C" { // Window handle. #define cef_window_handle_t HWND +#define cef_cursor_handle_t HCURSOR // Class representing window information. typedef struct _cef_window_info_t @@ -55,6 +56,11 @@ typedef struct _cef_window_info_t int m_nHeight; cef_window_handle_t m_hWndParent; HMENU m_hMenu; + + // If window rendering is disabled no browser window will be created. Set + // |m_hWndParent| to the window that will act as the parent for popup menus, + // dialog boxes, etc. + BOOL m_bWindowRenderingDisabled; // Handle for the new browser window. cef_window_handle_t m_hWnd; diff --git a/include/cef_win.h b/include/cef_win.h index 4dad42d56..af479e989 100644 --- a/include/cef_win.h +++ b/include/cef_win.h @@ -64,6 +64,10 @@ public: CRITICAL_SECTION m_sec; }; +// Handle types. +#define CefWindowHandle cef_window_handle_t +#define CefCursorHandle cef_cursor_handle_t + // Class representing window information. class CefWindowInfo : public cef_window_info_t { @@ -120,6 +124,7 @@ public: m_nHeight = r.m_nHeight; m_hWndParent = r.m_hWndParent; m_hMenu = r.m_hMenu; + m_bWindowRenderingDisabled = r.m_bWindowRenderingDisabled; m_hWnd = r.m_hWnd; return *this; } @@ -148,6 +153,12 @@ public: cef_string_copy(windowName.c_str(), windowName.length(), &m_windowName); } + void SetAsOffScreen(HWND hWndParent) + { + m_bWindowRenderingDisabled = TRUE; + m_hWndParent = hWndParent; + } + protected: void Init() { @@ -201,8 +212,6 @@ public: } }; -// Window handle. -#define CefWindowHandle cef_window_handle_t #endif // _WIN32 #endif // _CEF_WIN_H diff --git a/libcef/browser_impl.cc b/libcef/browser_impl.cc index fb45af706..41b98dd80 100644 --- a/libcef/browser_impl.cc +++ b/libcef/browser_impl.cc @@ -70,6 +70,29 @@ void UIT_CreateBrowserWithHelper(CreateBrowserHelper* helper) } // namespace + +CefBrowserImpl::PaintDelegate::PaintDelegate(CefBrowserImpl* browser) + : browser_(browser) +{ +} +CefBrowserImpl::PaintDelegate::~PaintDelegate() +{ +} + +void CefBrowserImpl::PaintDelegate::Paint(bool popup, + const gfx::Rect& dirtyRect, + const void* buffer) +{ + CefRefPtr handler = browser_->GetHandler(); + if (!handler.get()) + return; + + CefRect rect(dirtyRect.x(), dirtyRect.y(), dirtyRect.width(), + dirtyRect.height()); + handler->HandlePaint(browser_, (popup?PET_POPUP:PET_VIEW), rect, buffer); +} + + // static bool CefBrowser::CreateBrowser(CefWindowInfo& windowInfo, bool popup, CefRefPtr handler, @@ -282,6 +305,137 @@ void CefBrowserImpl::CloseDevTools() &CefBrowserImpl::UIT_CloseDevTools)); } +bool CefBrowserImpl::GetSize(PaintElementType type, int& width, int& height) +{ + if (!CefThread::CurrentlyOn(CefThread::UI)) { + NOTREACHED(); + return false; + } + + width = height = 0; + + if(type == PET_VIEW) { + WebViewHost* host = UIT_GetWebViewHost(); + if (host) { + host->GetSize(width, height); + return true; + } + } else if(type == PET_POPUP) { + if (popuphost_) { + popuphost_->GetSize(width, height); + return true; + } + } + + return false; +} + +void CefBrowserImpl::SetSize(PaintElementType type, int width, int height) +{ + // Intentially post event tasks in all cases so that painting tasks can be + // handled at sane times. + CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_SetSize, type, width, height)); +} + +bool CefBrowserImpl::IsPopupVisible() +{ + if (!CefThread::CurrentlyOn(CefThread::UI)) { + NOTREACHED(); + return false; + } + + return (popuphost_ != NULL); +} + +void CefBrowserImpl::HidePopup() +{ + // Intentially post event tasks in all cases so that painting tasks can be + // handled at sane times. + CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_ClosePopupWidget)); +} + +void CefBrowserImpl::Invalidate(const CefRect& dirtyRect) +{ + // Intentially post event tasks in all cases so that painting tasks can be + // handled at sane times. + CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_Invalidate, dirtyRect)); +} + +bool CefBrowserImpl::GetImage(PaintElementType type, int width, int height, + void* buffer) +{ + if (!CefThread::CurrentlyOn(CefThread::UI)) { + NOTREACHED(); + return false; + } + + if(type == PET_VIEW) { + WebViewHost* host = UIT_GetWebViewHost(); + if (host) + return host->GetImage(width, height, buffer); + } else if(type == PET_POPUP) { + if (popuphost_) + return popuphost_->GetImage(width, height, buffer); + } + + return false; +} + +void CefBrowserImpl::SendKeyEvent(KeyType type, int key, int modifiers, + bool sysChar, bool imeChar) +{ + // Intentially post event tasks in all cases so that painting tasks can be + // handled at sane times. + CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_SendKeyEvent, type, key, modifiers, sysChar, + imeChar)); +} + +void CefBrowserImpl::SendMouseClickEvent(int x, int y, MouseButtonType type, + bool mouseUp, int clickCount) +{ + // Intentially post event tasks in all cases so that painting tasks can be + // handled at sane times. + CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_SendMouseClickEvent, x, y, type, mouseUp, + clickCount)); +} + +void CefBrowserImpl::SendMouseMoveEvent(int x, int y, bool mouseLeave) +{ + // Intentially post event tasks in all cases so that painting tasks can be + // handled at sane times. + CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_SendMouseMoveEvent, x, y, mouseLeave)); +} + +void CefBrowserImpl::SendMouseWheelEvent(int x, int y, int delta) +{ + // Intentially post event tasks in all cases so that painting tasks can be + // handled at sane times. + CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_SendMouseWheelEvent, x, y, delta)); +} + +void CefBrowserImpl::SendFocusEvent(bool setFocus) +{ + // Intentially post event tasks in all cases so that painting tasks can be + // handled at sane times. + CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_SendFocusEvent, setFocus)); +} + +void CefBrowserImpl::SendCaptureLostEvent() +{ + // Intentially post event tasks in all cases so that painting tasks can be + // handled at sane times. + CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_SendCaptureLostEvent)); +} + void CefBrowserImpl::Undo(CefRefPtr frame) { CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this, @@ -474,17 +628,14 @@ CefRefPtr CefBrowserImpl::UIT_GetCefFrame(WebFrame* frame) CefRefPtr cef_frame; - WebView *view = UIT_GetWebView(); - if(view) { - if(frame == view->mainFrame()) { - // Use the single main frame reference. - cef_frame = GetMainCefFrame(); - } else { - // Locate or create the appropriate named reference. - CefString name = string16(frame->name()); - DCHECK(!name.empty()); - cef_frame = GetCefFrame(name); - } + if(frame->parent() == 0) { + // Use the single main frame reference. + cef_frame = GetMainCefFrame(); + } else { + // Locate or create the appropriate named reference. + CefString name = string16(frame->name()); + DCHECK(!name.empty()); + cef_frame = GetCefFrame(name); } return cef_frame; @@ -555,7 +706,10 @@ void CefBrowserImpl::UIT_DestroyBrowser() void CefBrowserImpl::UIT_CloseBrowser() { REQUIRE_UIT(); - UIT_CloseView(UIT_GetMainWndHandle()); + if (!IsWindowRenderingDisabled()) + UIT_CloseView(UIT_GetMainWndHandle()); + else + UIT_DestroyBrowser(); } void CefBrowserImpl::UIT_LoadURL(CefRefPtr frame, @@ -775,13 +929,110 @@ bool CefBrowserImpl::UIT_Navigate(const BrowserNavigationEntry& entry, view->setFocusedFrame(frame); // Give focus to the window if it is currently visible. - if(UIT_IsViewVisible(UIT_GetMainWndHandle())) + if (!IsWindowRenderingDisabled() && + UIT_IsViewVisible(UIT_GetMainWndHandle())) UIT_SetFocus(UIT_GetWebViewHost(), true); } return true; } + +void CefBrowserImpl::UIT_SetSize(PaintElementType type, int width, int height) +{ + if(type == PET_VIEW) { + WebViewHost* host = UIT_GetWebViewHost(); + if (host) + host->SetSize(width, height); + } else if(type == PET_POPUP) { + if (popuphost_) + popuphost_->SetSize(width, height); + } +} + +void CefBrowserImpl::UIT_Invalidate(const CefRect& dirtyRect) +{ + REQUIRE_UIT(); + WebViewHost* host = UIT_GetWebViewHost(); + if (host) { + host->InvalidateRect(gfx::Rect(dirtyRect.x, dirtyRect.y, dirtyRect.width, + dirtyRect.height)); + } +} + +void CefBrowserImpl::UIT_SendKeyEvent(KeyType type, int key, int modifiers, + bool sysChar, bool imeChar) +{ + REQUIRE_UIT(); + if (popuphost_) { + // Send the event to the popup. + popuphost_->SendKeyEvent(type, key, modifiers, sysChar, imeChar); + } else { + WebViewHost* host = UIT_GetWebViewHost(); + if (host) + host->SendKeyEvent(type, key, modifiers, sysChar, imeChar); + } +} + +void CefBrowserImpl::UIT_SendMouseClickEvent(int x, int y, MouseButtonType type, + bool mouseUp, int clickCount) +{ + REQUIRE_UIT(); + if (popuphost_ && popup_rect_.Contains(x, y)) { + // Send the event to the popup. + popuphost_->SendMouseClickEvent(x - popup_rect_.x(), y - popup_rect_.y(), + type, mouseUp, clickCount); + } else { + WebViewHost* host = UIT_GetWebViewHost(); + if (host) + host->SendMouseClickEvent(x, y, type, mouseUp, clickCount); + } +} + +void CefBrowserImpl::UIT_SendMouseMoveEvent(int x, int y, bool mouseLeave) +{ + REQUIRE_UIT(); + if (popuphost_ && popup_rect_.Contains(x, y)) { + // Send the event to the popup. + popuphost_->SendMouseMoveEvent(x - popup_rect_.x(), y - popup_rect_.y(), + mouseLeave); + } else { + WebViewHost* host = UIT_GetWebViewHost(); + if (host) + host->SendMouseMoveEvent(x, y, mouseLeave); + } +} + +void CefBrowserImpl::UIT_SendMouseWheelEvent(int x, int y, int delta) +{ + REQUIRE_UIT(); + if (popuphost_ && popup_rect_.Contains(x, y)) { + // Send the event to the popup. + popuphost_->SendMouseWheelEvent(x - popup_rect_.x(), y - popup_rect_.y(), + delta); + } else { + WebViewHost* host = UIT_GetWebViewHost(); + if (host) + host->SendMouseWheelEvent(x, y, delta); + } +} + +void CefBrowserImpl::UIT_SendFocusEvent(bool setFocus) +{ + REQUIRE_UIT(); + WebViewHost* host = UIT_GetWebViewHost(); + if (host) + host->SendFocusEvent(setFocus); +} + +void CefBrowserImpl::UIT_SendCaptureLostEvent() +{ + REQUIRE_UIT(); + WebViewHost* host = UIT_GetWebViewHost(); + if (host) + host->SendCaptureLostEvent(); +} + CefRefPtr CefBrowserImpl::UIT_CreatePopupWindow( const CefString& url, const CefPopupFeatures& features) { @@ -828,23 +1079,35 @@ CefRefPtr CefBrowserImpl::UIT_CreatePopupWindow( WebKit::WebWidget* CefBrowserImpl::UIT_CreatePopupWidget() { REQUIRE_UIT(); - + DCHECK(!popuphost_); - popuphost_ = WebWidgetHost::Create(UIT_GetMainWndHandle(), - popup_delegate_.get()); + popuphost_ = WebWidgetHost::Create( + (IsWindowRenderingDisabled()?NULL:UIT_GetMainWndHandle()), + popup_delegate_.get(), paint_delegate_.get()); popuphost_->set_popup(true); + return popuphost_->webwidget(); } void CefBrowserImpl::UIT_ClosePopupWidget() { REQUIRE_UIT(); + + if (!popuphost_) + return; #if !defined(OS_MACOSX) // Mac uses a WebPopupMenu for select lists so no closing is necessary. - UIT_CloseView(UIT_GetPopupWndHandle()); + if (!IsWindowRenderingDisabled()) + UIT_CloseView(UIT_GetPopupWndHandle()); #endif popuphost_ = NULL; + popup_rect_ = gfx::Rect(); + + if (IsWindowRenderingDisabled() && handler_.get()) { + // Notify the handler of popup visibility change. + handler_->HandlePopupChange(this, false, CefRect()); + } } void CefBrowserImpl::UIT_Show(WebKit::WebNavigationPolicy policy) diff --git a/libcef/browser_impl.h b/libcef/browser_impl.h index b76018262..2bd1bba3a 100644 --- a/libcef/browser_impl.h +++ b/libcef/browser_impl.h @@ -36,6 +36,19 @@ class WebView; class CefBrowserImpl : public CefThreadSafeBase { public: + class PaintDelegate : public WebWidgetHost::PaintDelegate + { + public: + PaintDelegate(CefBrowserImpl* browser); + virtual ~PaintDelegate(); + + virtual void Paint(bool popup, const gfx::Rect& dirtyRect, + const void* buffer); + + protected: + CefBrowserImpl* browser_; + }; + CefBrowserImpl(const CefWindowInfo& windowInfo, const CefBrowserSettings& settings, bool popup, CefRefPtr handler); @@ -71,6 +84,22 @@ public: virtual void SetZoomLevel(double zoomLevel); virtual void ShowDevTools(); virtual void CloseDevTools(); + virtual bool IsWindowRenderingDisabled(); + virtual bool GetSize(PaintElementType type, int& width, int& height); + virtual void SetSize(PaintElementType type, int width, int height); + virtual bool IsPopupVisible(); + virtual void HidePopup(); + virtual void Invalidate(const CefRect& dirtyRect); + virtual bool GetImage(PaintElementType type, int width, int height, + void* buffer); + virtual void SendKeyEvent(KeyType type, int key, int modifiers, bool sysChar, + bool imeChar); + virtual void SendMouseClickEvent(int x, int y, MouseButtonType type, + bool mouseUp, int clickCount); + virtual void SendMouseMoveEvent(int x, int y, bool mouseLeave); + virtual void SendMouseWheelEvent(int x, int y, int delta); + virtual void SendFocusEvent(bool setFocus); + virtual void SendCaptureLostEvent(); // Frame-related methods void Undo(CefRefPtr frame); @@ -134,8 +163,9 @@ public: REQUIRE_UIT(); return delegate_.get(); } - gfx::NativeView UIT_GetWebViewWndHandle() const { + gfx::NativeView UIT_GetWebViewWndHandle() { REQUIRE_UIT(); + DCHECK(!IsWindowRenderingDisabled()); return webviewhost_->view_handle(); } WebKit::WebWidget* UIT_GetPopup() const { @@ -150,11 +180,12 @@ public: REQUIRE_UIT(); return popup_delegate_.get(); } - gfx::NativeView UIT_GetPopupWndHandle() const { + gfx::NativeView UIT_GetPopupWndHandle() { REQUIRE_UIT(); + DCHECK(!IsWindowRenderingDisabled()); return popuphost_->view_handle(); } - gfx::NativeView UIT_GetMainWndHandle() const; + gfx::NativeView UIT_GetMainWndHandle(); BrowserNavigationController* UIT_GetNavigationController() { REQUIRE_UIT(); @@ -218,6 +249,16 @@ public: bool reload, bool ignoreCahce); void UIT_SetFocus(WebWidgetHost* host, bool enable); + void UIT_SetSize(PaintElementType type, int width, int height); + void UIT_Invalidate(const CefRect& dirtyRect); + void UIT_SendKeyEvent(KeyType type, int key, int modifiers, bool sysChar, + bool imeChar); + void UIT_SendMouseClickEvent(int x, int y, MouseButtonType type, + bool mouseUp, int clickCount); + void UIT_SendMouseMoveEvent(int x, int y, bool mouseLeave); + void UIT_SendMouseWheelEvent(int x, int y, int delta); + void UIT_SendFocusEvent(bool setFocus); + void UIT_SendCaptureLostEvent(); CefRefPtr UIT_CreatePopupWindow(const CefString& url, const CefPopupFeatures& features); @@ -276,6 +317,8 @@ public: bool can_go_back(); bool can_go_forward(); + void set_popup_rect(const gfx::Rect& rect) { popup_rect_ = rect; } + static bool ImplementsThreadSafeReferenceCounting() { return true; } protected: @@ -293,9 +336,11 @@ protected: CefRefPtr handler_; scoped_ptr webviewhost_; WebWidgetHost* popuphost_; + gfx::Rect popup_rect_; scoped_ptr delegate_; scoped_ptr popup_delegate_; scoped_ptr nav_controller_; + scoped_ptr paint_delegate_; scoped_ptr dev_tools_agent_; scoped_ptr dev_tools_client_; diff --git a/libcef/browser_impl_gtk.cc b/libcef/browser_impl_gtk.cc index 7d0b016b7..3a9ba5339 100644 --- a/libcef/browser_impl_gtk.cc +++ b/libcef/browser_impl_gtk.cc @@ -24,7 +24,13 @@ CefWindowHandle CefBrowserImpl::GetWindowHandle() return window_info_.m_Widget; } -gfx::NativeWindow CefBrowserImpl::UIT_GetMainWndHandle() const { +bool CefBrowserImpl::IsWindowRenderingDisabled() +{ + // TODO(port): Add support for off-screen rendering. + return false; +} + +gfx::NativeWindow CefBrowserImpl::UIT_GetMainWndHandle() { REQUIRE_UIT(); GtkWidget* toplevel = gtk_widget_get_ancestor(window_info_.m_Widget, GTK_TYPE_WINDOW); @@ -51,7 +57,8 @@ void CefBrowserImpl::UIT_CreateBrowser(const CefString& url) // Create the webview host object webviewhost_.reset( WebViewHost::Create(window_info_.m_ParentWidget, gfx::Rect(), - delegate_.get(), dev_tools_agent_.get(), prefs)); + delegate_.get(), NULL, dev_tools_agent_.get(), + prefs)); delegate_->RegisterDragDrop(); if (!settings_.developer_tools_disabled) diff --git a/libcef/browser_impl_mac.mm b/libcef/browser_impl_mac.mm index 29af5c6cd..7d390796b 100644 --- a/libcef/browser_impl_mac.mm +++ b/libcef/browser_impl_mac.mm @@ -25,7 +25,13 @@ CefWindowHandle CefBrowserImpl::GetWindowHandle() return window_info_.m_View; } -gfx::NativeView CefBrowserImpl::UIT_GetMainWndHandle() const { +bool CefBrowserImpl::IsWindowRenderingDisabled() +{ + // TODO(port): Add support for off-screen rendering. + return false; +} + +gfx::NativeView CefBrowserImpl::UIT_GetMainWndHandle() { REQUIRE_UIT(); return window_info_.m_View; } @@ -79,7 +85,7 @@ void CefBrowserImpl::UIT_CreateBrowser(const CefString& url) // Create the webview host object webviewhost_.reset( WebViewHost::Create(parentView, contentRect, delegate_.get(), - dev_tools_agent_.get(), prefs)); + NULL, dev_tools_agent_.get(), prefs)); delegate_->RegisterDragDrop(); if (!settings_.developer_tools_disabled) diff --git a/libcef/browser_impl_win.cc b/libcef/browser_impl_win.cc index dff3358a8..b09955892 100644 --- a/libcef/browser_impl_win.cc +++ b/libcef/browser_impl_win.cc @@ -89,9 +89,15 @@ CefWindowHandle CefBrowserImpl::GetWindowHandle() return window_info_.m_hWnd; } -gfx::NativeWindow CefBrowserImpl::UIT_GetMainWndHandle() const { +bool CefBrowserImpl::IsWindowRenderingDisabled() +{ + return (window_info_.m_bWindowRenderingDisabled ? true : false); +} + +gfx::NativeWindow CefBrowserImpl::UIT_GetMainWndHandle() { REQUIRE_UIT(); - return window_info_.m_hWnd; + return window_info_.m_bWindowRenderingDisabled ? + window_info_.m_hWndParent : window_info_.m_hWnd; } void CefBrowserImpl::UIT_CreateBrowser(const CefString& url) @@ -99,19 +105,24 @@ void CefBrowserImpl::UIT_CreateBrowser(const CefString& url) REQUIRE_UIT(); Lock(); - std::wstring windowName(CefString(&window_info_.m_windowName)); - - // Create the new browser window - window_info_.m_hWnd = CreateWindowEx(window_info_.m_dwExStyle, GetWndClass(), - windowName.c_str(), window_info_.m_dwStyle, - window_info_.m_x, window_info_.m_y, window_info_.m_nWidth, - window_info_.m_nHeight, window_info_.m_hWndParent, window_info_.m_hMenu, - ::GetModuleHandle(NULL), NULL); - DCHECK(window_info_.m_hWnd != NULL); + if (!window_info_.m_bWindowRenderingDisabled) { + std::wstring windowName(CefString(&window_info_.m_windowName)); - // Set window user data to this object for future reference from the window - // procedure - ui::SetWindowUserData(window_info_.m_hWnd, this); + // Create the new browser window + window_info_.m_hWnd = CreateWindowEx(window_info_.m_dwExStyle, + GetWndClass(), windowName.c_str(), window_info_.m_dwStyle, + window_info_.m_x, window_info_.m_y, window_info_.m_nWidth, + window_info_.m_nHeight, window_info_.m_hWndParent, window_info_.m_hMenu, + ::GetModuleHandle(NULL), NULL); + DCHECK(window_info_.m_hWnd != NULL); + + // Set window user data to this object for future reference from the window + // procedure + ui::SetWindowUserData(window_info_.m_hWnd, this); + } else { + // Create a new paint delegate. + paint_delegate_.reset(new PaintDelegate(this)); + } if (!settings_.developer_tools_disabled) dev_tools_agent_.reset(new BrowserDevToolsAgent()); @@ -128,29 +139,32 @@ void CefBrowserImpl::UIT_CreateBrowser(const CefString& url) // Create the webview host object webviewhost_.reset( WebViewHost::Create(window_info_.m_hWnd, gfx::Rect(), delegate_.get(), - dev_tools_agent_.get(), prefs)); + paint_delegate_.get(), dev_tools_agent_.get(), + prefs)); if (!settings_.developer_tools_disabled) dev_tools_agent_->SetWebView(webviewhost_->webview()); - if (!settings_.drag_drop_disabled) - delegate_->RegisterDragDrop(); - Unlock(); - // Size the web view window to the browser window - RECT cr; - GetClientRect(window_info_.m_hWnd, &cr); + if (!window_info_.m_bWindowRenderingDisabled) { + if (!settings_.drag_drop_disabled) + delegate_->RegisterDragDrop(); + + // Size the web view window to the browser window + RECT cr; + GetClientRect(window_info_.m_hWnd, &cr); - // Respect the WS_VISIBLE window style when setting the window's position - UINT flags = SWP_NOZORDER; - if (window_info_.m_dwStyle & WS_VISIBLE) - flags |= SWP_SHOWWINDOW; - else - flags |= SWP_NOACTIVATE; + // Respect the WS_VISIBLE window style when setting the window's position + UINT flags = SWP_NOZORDER; + if (window_info_.m_dwStyle & WS_VISIBLE) + flags |= SWP_SHOWWINDOW; + else + flags |= SWP_NOACTIVATE; - SetWindowPos(UIT_GetWebViewWndHandle(), NULL, cr.left, cr.top, cr.right, - cr.bottom, flags); + SetWindowPos(UIT_GetWebViewWndHandle(), NULL, cr.left, cr.top, cr.right, + cr.bottom, flags); + } if(handler_.get()) { // Notify the handler that we're done creating the new window diff --git a/libcef/browser_webview_delegate.cc b/libcef/browser_webview_delegate.cc index 7b4f8bc33..7572ccdfc 100644 --- a/libcef/browser_webview_delegate.cc +++ b/libcef/browser_webview_delegate.cc @@ -43,7 +43,6 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebKitClient.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebNode.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebPoint.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenu.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginParams.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebRange.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h" @@ -102,7 +101,6 @@ using WebKit::WebNode; using WebKit::WebPlugin; using WebKit::WebPluginParams; using WebKit::WebPoint; -using WebKit::WebPopupMenu; using WebKit::WebPopupType; using WebKit::WebRange; using WebKit::WebRect; @@ -425,6 +423,12 @@ void BrowserWebViewDelegate::startDragging( const WebImage& image, const WebPoint& image_offset) { #if defined(OS_WIN) + // Dragging is not supported when window rendering is disabled. + if (browser_->IsWindowRenderingDisabled()) { + EndDragging(); + return; + } + drag_delegate_ = new BrowserDragDelegate(this); drag_delegate_->StartDragging(WebDropData(data), mask, image.getSkBitmap(), image_offset); @@ -518,8 +522,22 @@ void BrowserWebViewDelegate::closeWidgetSoon() { } WebScreenInfo BrowserWebViewDelegate::screenInfo() { - if (WebWidgetHost* host = GetWidgetHost()) - return host->GetScreenInfo(); + if (WebWidgetHost* host = GetWidgetHost()) { + WebScreenInfo info = host->GetScreenInfo(); + + if (browser_->IsWindowRenderingDisabled()) { + // Retrieve the screen rectangle from the handler. + CefRefPtr handler = browser_->GetHandler(); + if (handler.get()) { + CefRect rect(info.rect.x, info.rect.y, info.rect.width, + info.rect.height); + if (handler->HandleGetRect(browser_, true, rect) == RV_CONTINUE) { + info.rect = WebRect(rect.x, rect.y, rect.width, rect.height); + info.availableRect = info.rect; + } + } + } + } return WebScreenInfo(); } @@ -985,14 +1003,13 @@ void BrowserWebViewDelegate::UpdateURL(WebFrame* frame) { } bool is_main_frame = (frame->parent() == 0); - if (is_main_frame) { - CefRefPtr handler = browser_->GetHandler(); - if(handler.get()) { - // Notify the handler of an address change - std::string url = std::string(entry->GetURL().spec().c_str()); - handler->HandleAddressChange(browser_, browser_->UIT_GetCefFrame(frame), - url); - } + CefRefPtr handler = browser_->GetHandler(); + + if (is_main_frame && handler.get()) { + // Notify the handler of an address change + std::string url = std::string(entry->GetURL().spec().c_str()); + handler->HandleAddressChange(browser_, browser_->UIT_GetCefFrame(frame), + url); } const WebHistoryItem& history_item = frame->currentHistoryItem(); @@ -1001,10 +1018,24 @@ void BrowserWebViewDelegate::UpdateURL(WebFrame* frame) { BrowserNavigationController* controller = browser_->UIT_GetNavigationController(); + + bool old_can_go_back = !controller->IsAtStart(); + bool old_can_go_forward = !controller->IsAtEnd(); controller->DidNavigateToEntry(entry.release()); - browser_->set_nav_state(!controller->IsAtStart(), !controller->IsAtEnd()); + bool new_can_go_back = !controller->IsAtStart(); + bool new_can_go_forward = !controller->IsAtEnd(); last_page_id_updated_ = std::max(last_page_id_updated_, page_id_); + + if (old_can_go_back != new_can_go_back || + old_can_go_forward != new_can_go_forward) { + browser_->set_nav_state(new_can_go_back, new_can_go_forward); + if (handler.get()) { + // Notify the handler of a navigation state change + handler->HandleNavStateChange(browser_, new_can_go_back, + new_can_go_forward); + } + } } void BrowserWebViewDelegate::UpdateSessionHistory(WebFrame* frame) { diff --git a/libcef/browser_webview_delegate_win.cc b/libcef/browser_webview_delegate_win.cc index 208cf5e91..ec54cfc71 100644 --- a/libcef/browser_webview_delegate_win.cc +++ b/libcef/browser_webview_delegate_win.cc @@ -35,6 +35,7 @@ #include "webkit/plugins/npapi/webplugin.h" #include "webkit/plugins/npapi/webplugin_delegate_impl.h" +using webkit::npapi::WebPluginDelegateImpl; using WebKit::WebContextMenuData; using WebKit::WebCursorInfo; using WebKit::WebFrame; @@ -43,6 +44,8 @@ using WebKit::WebPopupMenuInfo; using WebKit::WebRect; using WebKit::WebWidget; +static const wchar_t kPluginWindowClassName[] = L"WebPluginHost"; + // WebViewClient -------------------------------------------------------------- WebWidget* BrowserWebViewDelegate::createPopupMenu( @@ -55,16 +58,25 @@ WebWidget* BrowserWebViewDelegate::createPopupMenu( void BrowserWebViewDelegate::show(WebNavigationPolicy) { if (this == browser_->UIT_GetWebViewDelegate()) { - // Restore the window and bring it to the top if the window is currently - // visible. - HWND root = GetAncestor(browser_->UIT_GetMainWndHandle(), GA_ROOT); - if(IsWindowVisible(root)) { - ShowWindow(root, SW_SHOWNORMAL); - SetWindowPos(root, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + if (!browser_->IsWindowRenderingDisabled()) { + // Restore the window and bring it to the top if the window is currently + // visible. + HWND root = GetAncestor(browser_->UIT_GetMainWndHandle(), GA_ROOT); + if(IsWindowVisible(root)) { + ShowWindow(root, SW_SHOWNORMAL); + SetWindowPos(root, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + } } } else if (this == browser_->UIT_GetPopupDelegate()) { - // Show popup widgets without activation. - ShowWindow(browser_->UIT_GetPopupWndHandle(), SW_SHOWNA); + if (!browser_->IsWindowRenderingDisabled()) { + // Show popup widgets without activation. + ShowWindow(browser_->UIT_GetPopupWndHandle(), SW_SHOWNA); + } else { + // Notify the handler of popup visibility change. + CefRefPtr handler = browser_->GetHandler(); + if (handler.get()) + handler->HandlePopupChange(browser_, true, CefRect()); + } } } @@ -74,15 +86,34 @@ void BrowserWebViewDelegate::didChangeCursor(const WebCursorInfo& cursor_info) { HMODULE hModule = ::GetModuleHandle(L"libcef.dll"); if(!hModule) hModule = ::GetModuleHandle(NULL); - host->SetCursor(current_cursor_.GetCursor(hModule)); + HCURSOR hCursor = current_cursor_.GetCursor(hModule); + + if (!browser_->IsWindowRenderingDisabled()) { + host->SetCursor(hCursor); + } else { + // Notify the handler of cursor change. + CefRefPtr handler = browser_->GetHandler(); + if (handler.get()) + handler->HandleCursorChange(browser_, hCursor); + } } } WebRect BrowserWebViewDelegate::windowRect() { if (WebWidgetHost* host = GetWidgetHost()) { - RECT rect; - ::GetWindowRect(host->view_handle(), &rect); - return gfx::Rect(rect); + if (!browser_->IsWindowRenderingDisabled()) { + RECT rect; + ::GetWindowRect(host->view_handle(), &rect); + return gfx::Rect(rect); + } else { + // Retrieve the view rectangle from the handler. + CefRefPtr handler = browser_->GetHandler(); + if (handler.get()) { + CefRect rect(0, 0, 0, 0); + if (handler->HandleGetRect(browser_, false, rect) == RV_CONTINUE) + return WebRect(rect.x, rect.y, rect.width, rect.height); + } + } } return WebRect(); } @@ -91,8 +122,20 @@ void BrowserWebViewDelegate::setWindowRect(const WebRect& rect) { if (this == browser_->UIT_GetWebViewDelegate()) { // ignored } else if (this == browser_->UIT_GetPopupDelegate()) { - MoveWindow(browser_->UIT_GetPopupWndHandle(), - rect.x, rect.y, rect.width, rect.height, FALSE); + if (!browser_->IsWindowRenderingDisabled()) { + MoveWindow(browser_->UIT_GetPopupWndHandle(), rect.x, rect.y, rect.width, + rect.height, FALSE); + } else { + browser_->set_popup_rect(rect); + browser_->UIT_GetPopupHost()->SetSize(rect.width, rect.height); + + // Notify the handler of popup size change. + CefRefPtr handler = browser_->GetHandler(); + if (handler.get()) { + handler->HandlePopupChange(browser_, true, + CefRect(rect.x, rect.y, rect.width, rect.height)); + } + } } } @@ -147,23 +190,66 @@ webkit::npapi::WebPluginDelegate* BrowserWebViewDelegate::CreatePluginDelegate( const FilePath& file_path, const std::string& mime_type) { - HWND hwnd = browser_->UIT_GetWebViewHost() ? - browser_->UIT_GetWebViewHost()->view_handle() : NULL; - if (!hwnd) + WebViewHost* host = browser_->UIT_GetWebViewHost(); + if (!host) return NULL; - return webkit::npapi::WebPluginDelegateImpl::Create(file_path, mime_type, - hwnd); + HWND hwnd; + + if (!browser_->IsWindowRenderingDisabled()) { + // Parent the plugin container to the existing browser window. + hwnd = browser_->UIT_GetWebViewHost()->view_handle(); + DCHECK(hwnd != NULL); + } else { + // Parent the plugin container to the main window handle provided by the + // user. + hwnd = browser_->UIT_GetMainWndHandle(); + DCHECK(hwnd != NULL); + } + + return WebPluginDelegateImpl::Create(file_path, mime_type, hwnd); } void BrowserWebViewDelegate::CreatedPluginWindow( gfx::PluginWindowHandle handle) { - // ignored + if (browser_->IsWindowRenderingDisabled()) { + static bool registered_class = false; + if (!registered_class) { + WNDCLASSEX wcex = {0}; + wcex.cbSize = sizeof(wcex); + wcex.style = CS_DBLCLKS; + wcex.lpfnWndProc = DefWindowProc; + wcex.hInstance = GetModuleHandle(NULL); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.lpszClassName = kPluginWindowClassName; + RegisterClassEx(&wcex); + registered_class = true; + } + + // Parent windowed plugin containers to a hidden window. + HWND parent = CreateWindow(kPluginWindowClassName, NULL, + WS_OVERLAPPED|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, + 0, 0, 0, 0, NULL, NULL, + GetModuleHandle(NULL), NULL); + DCHECK(parent != NULL); + SetParent(handle, parent); + + WebViewHost* host = browser_->UIT_GetWebViewHost(); + if (host) + host->AddWindowedPlugin(handle); + } } void BrowserWebViewDelegate::WillDestroyPluginWindow( gfx::PluginWindowHandle handle) { - // ignored + if (browser_->IsWindowRenderingDisabled()) { + WebViewHost* host = browser_->UIT_GetWebViewHost(); + if (host) + host->RemoveWindowedPlugin(handle); + + // Destroy the hidden parent window. + DestroyWindow(GetParent(handle)); + } } void BrowserWebViewDelegate::DidMovePlugin( @@ -196,6 +282,13 @@ void BrowserWebViewDelegate::DidMovePlugin( move.window_rect.width(), move.window_rect.height(), flags); + + if (browser_->IsWindowRenderingDisabled()) { + WebViewHost* host = browser_->UIT_GetWebViewHost(); + if (host) { + host->MoveWindowedPlugin(move); + } + } } static void AddMenuItem(CefRefPtr browser, HMENU menu, int index, @@ -239,22 +332,30 @@ static void AddMenuSeparator(HMENU menu, int index) void BrowserWebViewDelegate::showContextMenu( WebFrame* frame, const WebContextMenuData& data) { - POINT screen_pt = { data.mousePosition.x, data.mousePosition.y }; - MapWindowPoints(browser_->UIT_GetMainWndHandle(), HWND_DESKTOP, - &screen_pt, 1); + int screenX = -1, screenY = -1; + + POINT mouse_pt = {data.mousePosition.x, data.mousePosition.y}; + if (!browser_->IsWindowRenderingDisabled()) { + // Perform the conversion to screen coordinates only if window rendering is + // enabled. + MapWindowPoints(browser_->UIT_GetMainWndHandle(), HWND_DESKTOP, + &mouse_pt, 1); + screenX = mouse_pt.x; + screenY = mouse_pt.y; + } HMENU menu = NULL; std::list label_list; // Enable recursive tasks on the message loop so we can get updates while - // the context menu is being displayed. - bool old_state = MessageLoop::current()->NestableTasksAllowed(); - MessageLoop::current()->SetNestableTasksAllowed(true); + // the context menu is being displayed. + bool old_state = MessageLoop::current()->NestableTasksAllowed(); + MessageLoop::current()->SetNestableTasksAllowed(true); int edit_flags = data.editFlags; if(browser_->UIT_CanGoBack()) edit_flags |= MENU_CAN_GO_BACK; - if(browser_->UIT_CanGoForward()) + if(browser_->UIT_CanGoForward()) edit_flags |= MENU_CAN_GO_FORWARD; int type_flags = MENUTYPE_NONE; @@ -276,7 +377,7 @@ void BrowserWebViewDelegate::showContextMenu( type_flags |= MENUTYPE_VIDEO; if(data.mediaType == WebContextMenuData::MediaTypeAudio) type_flags |= MENUTYPE_AUDIO; - + CefRefPtr handler = browser_->GetHandler(); if(handler.get()) { // Gather menu information @@ -290,10 +391,10 @@ void BrowserWebViewDelegate::showContextMenu( CefString selectedTextStr(string16(data.selectedText)); CefString misspelledWordStr(string16(data.misspelledWord)); CefString securityInfoStr(std::string(data.securityInfo)); - + menuInfo.typeFlags = type_flags; - menuInfo.x = screen_pt.x; - menuInfo.y = screen_pt.y; + menuInfo.x = mouse_pt.x; + menuInfo.y = mouse_pt.y; cef_string_set(linkStr.c_str(), linkStr.length(), &menuInfo.linkUrl, false); cef_string_set(imageStr.c_str(), imageStr.length(), &menuInfo.imageUrl, false); @@ -307,11 +408,18 @@ void BrowserWebViewDelegate::showContextMenu( menuInfo.editFlags = edit_flags; cef_string_set(securityInfoStr.c_str(), securityInfoStr.length(), &menuInfo.securityInfo, false); - + // Notify the handler that a context menu is requested CefHandler::RetVal rv = handler->HandleBeforeMenu(browser_, menuInfo); if(rv == RV_HANDLED) goto end; + + if (browser_->IsWindowRenderingDisabled()) { + rv = handler->HandleGetScreenPoint(browser_, mouse_pt.x, mouse_pt.y, + screenX, screenY); + if(rv != RV_CONTINUE) + goto end; + } } // Build the correct default context menu @@ -353,8 +461,8 @@ void BrowserWebViewDelegate::showContextMenu( if(menu) { // show the context menu int selected_id = TrackPopupMenu(menu, - TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_RECURSE, - screen_pt.x, screen_pt.y, 0, browser_->UIT_GetMainWndHandle(), NULL); + TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_RECURSE, + screenX, screenY, 0, browser_->UIT_GetMainWndHandle(), NULL); if(selected_id != 0) { // An action was chosen diff --git a/libcef/cef_context.cc b/libcef/cef_context.cc index aa6bca8c8..2c378605b 100644 --- a/libcef/cef_context.cc +++ b/libcef/cef_context.cc @@ -80,6 +80,23 @@ void CefDoMessageLoopWork() _Context->process()->DoMessageLoopIteration(); } +void CefRunMessageLoop() +{ + // Verify that the context is in a valid state. + if (!CONTEXT_STATE_VALID()) { + NOTREACHED(); + return; + } + + // Must always be called on the same thread as Initialize. + if(!_Context->process()->CalledOnValidThread()) { + NOTREACHED(); + return; + } + + _Context->process()->RunMessageLoop(); +} + static void UIT_RegisterPlugin(CefPluginInfo* plugin_info) { REQUIRE_UIT(); diff --git a/libcef/cef_process.cc b/libcef/cef_process.cc index 5e62cb137..e56e8cbb3 100644 --- a/libcef/cef_process.cc +++ b/libcef/cef_process.cc @@ -20,6 +20,7 @@ class CefMessageLoopForUI : public MessageLoopForUI public: CefMessageLoopForUI() + : is_iterating_(true) { } @@ -32,10 +33,12 @@ public: virtual bool DoIdleWork() { bool valueToRet = inherited::DoIdleWork(); - pump_->Quit(); + if (is_iterating_) + pump_->Quit(); return valueToRet; } + // Do a single interation of the UI message loop. void DoMessageLoopIteration() { #if defined(OS_MACOSX) Run(); @@ -44,7 +47,18 @@ public: #endif } + // Run the UI message loop. + void RunMessageLoop() { + is_iterating_ = false; + DoMessageLoopIteration(); + } + + bool is_iterating() { return is_iterating_; } + private: + // True if the message loop is doing one iteration at a time. + bool is_iterating_; + DISALLOW_COPY_AND_ASSIGN(CefMessageLoopForUI); }; @@ -79,9 +93,15 @@ CefProcess::~CefProcess() { void CefProcess::DoMessageLoopIteration() { DCHECK(CalledOnValidThread() && ui_message_loop_.get() != NULL); + DCHECK(ui_message_loop_->is_iterating()); ui_message_loop_->DoMessageLoopIteration(); } +void CefProcess::RunMessageLoop() { + DCHECK(CalledOnValidThread() && ui_message_loop_.get() != NULL); + ui_message_loop_->RunMessageLoop(); +} + void CefProcess::CreateUIThread() { DCHECK(!created_ui_thread_ && ui_thread_.get() == NULL); created_ui_thread_ = true; diff --git a/libcef/cef_process.h b/libcef/cef_process.h index b966e51fb..b7768b296 100644 --- a/libcef/cef_process.h +++ b/libcef/cef_process.h @@ -57,10 +57,13 @@ class CefProcess : public base::RefCounted, return ui_thread_.get(); } - // Necessary to perform work on the UI thread if started without a multi - // threaded message loop. + // Do a single iteration of the UI message loop on the current thread. If + // RunMessageLoop() was called you do not need to call this method. void DoMessageLoopIteration(); + // Run the UI message loop for the on the current thread. + void RunMessageLoop(); + // Returns the thread that we perform I/O coordination on (network requests, // communication with renderers, etc. // NOTE: You should ONLY use this to pass to IPC or other objects which must diff --git a/libcef/webview_host.cc b/libcef/webview_host.cc new file mode 100644 index 000000000..965bbecb5 --- /dev/null +++ b/libcef/webview_host.cc @@ -0,0 +1,13 @@ +// Copyright (c) 2011 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 "webview_host.h" + +WebViewHost::WebViewHost() +{ +} + +WebViewHost::~WebViewHost() +{ +} diff --git a/libcef/webview_host.h b/libcef/webview_host.h index 2fbfd99b6..d52976f2d 100644 --- a/libcef/webview_host.h +++ b/libcef/webview_host.h @@ -30,9 +30,12 @@ class WebViewHost : public WebWidgetHost { static WebViewHost* Create(gfx::NativeView parent_view, const gfx::Rect& rect, BrowserWebViewDelegate* delegate, + PaintDelegate* paint_delegate, WebKit::WebDevToolsAgentClient* devtools_client, const WebPreferences& prefs); + virtual ~WebViewHost(); + WebKit::WebView* webview() const; #if defined(TOOLKIT_USES_GTK) @@ -50,6 +53,8 @@ class WebViewHost : public WebWidgetHost { #endif protected: + WebViewHost(); + #if defined(OS_WIN) virtual bool WndProc(UINT message, WPARAM wparam, LPARAM lparam) { return false; diff --git a/libcef/webview_host_gtk.cc b/libcef/webview_host_gtk.cc index 639dfc593..564512577 100644 --- a/libcef/webview_host_gtk.cc +++ b/libcef/webview_host_gtk.cc @@ -22,6 +22,7 @@ using WebKit::WebView; WebViewHost* WebViewHost::Create(GtkWidget* parent_view, const gfx::Rect& rect, BrowserWebViewDelegate* delegate, + PaintDelegate* paint_delegate, WebDevToolsAgentClient* dev_tools_client, const WebPreferences& prefs) { WebViewHost* host = new WebViewHost(); diff --git a/libcef/webview_host_mac.mm b/libcef/webview_host_mac.mm index fc68d081f..4ad3945f1 100644 --- a/libcef/webview_host_mac.mm +++ b/libcef/webview_host_mac.mm @@ -23,6 +23,7 @@ using WebKit::WebView; WebViewHost* WebViewHost::Create(NSView* parent_view, const gfx::Rect& rect, BrowserWebViewDelegate* delegate, + PaintDelegate* paint_delegate, WebDevToolsAgentClient* dev_tools_client, const WebPreferences& prefs) { WebViewHost* host = new WebViewHost(); diff --git a/libcef/webview_host_win.cc b/libcef/webview_host_win.cc index cbd7fae4b..1171bf42d 100644 --- a/libcef/webview_host_win.cc +++ b/libcef/webview_host_win.cc @@ -20,28 +20,33 @@ static const wchar_t kWindowClassName[] = L"WebViewHost"; WebViewHost* WebViewHost::Create(HWND parent_view, const gfx::Rect&, BrowserWebViewDelegate* delegate, + PaintDelegate* paint_delegate, WebDevToolsAgentClient* dev_tools_client, const WebPreferences& prefs) { WebViewHost* host = new WebViewHost(); - static bool registered_class = false; - if (!registered_class) { - WNDCLASSEX wcex = {0}; - wcex.cbSize = sizeof(wcex); - wcex.style = CS_DBLCLKS; - wcex.lpfnWndProc = WebWidgetHost::WndProc; - wcex.hInstance = GetModuleHandle(NULL); - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.lpszClassName = kWindowClassName; - RegisterClassEx(&wcex); - registered_class = true; - } + if (!paint_delegate) { + static bool registered_class = false; + if (!registered_class) { + WNDCLASSEX wcex = {0}; + wcex.cbSize = sizeof(wcex); + wcex.style = CS_DBLCLKS; + wcex.lpfnWndProc = WebWidgetHost::WndProc; + wcex.hInstance = GetModuleHandle(NULL); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.lpszClassName = kWindowClassName; + RegisterClassEx(&wcex); + registered_class = true; + } - host->view_ = CreateWindow(kWindowClassName, NULL, - WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, 0, 0, - 0, 0, parent_view, NULL, - GetModuleHandle(NULL), NULL); - ui::SetWindowUserData(host->view_, host); + host->view_ = CreateWindow(kWindowClassName, NULL, + WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, 0, 0, + 0, 0, parent_view, NULL, + GetModuleHandle(NULL), NULL); + ui::SetWindowUserData(host->view_, host); + } else { + host->paint_delegate_ = paint_delegate; + } #if defined(WEBKIT_HAS_WEB_AUTO_FILL_CLIENT) host->webwidget_ = WebView::create(delegate, dev_tools_client, NULL); diff --git a/libcef/webwidget_host.cc b/libcef/webwidget_host.cc index b05660b46..82207c152 100644 --- a/libcef/webwidget_host.cc +++ b/libcef/webwidget_host.cc @@ -3,10 +3,106 @@ // found in the LICENSE file. #include "webwidget_host.h" +#include "cef_thread.h" #include "base/message_loop.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h" + +using webkit::npapi::WebPluginGeometry; +using WebKit::WebSize; + void WebWidgetHost::ScheduleAnimation() { MessageLoop::current()->PostDelayedTask(FROM_HERE, factory_.NewRunnableMethod(&WebWidgetHost::ScheduleComposite), 10); } + +void WebWidgetHost::DiscardBackingStore() { + canvas_.reset(); +} + +void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) { + paint_rect_ = paint_rect_.Union(rect); +} + +void WebWidgetHost::SetSize(int width, int height) { + // Force an entire re-paint. TODO(darin): Maybe reuse this memory buffer. + DiscardBackingStore(); + + webwidget_->resize(WebSize(width, height)); + EnsureTooltip(); +} + +void WebWidgetHost::GetSize(int& width, int& height) { + const WebSize& size = webwidget_->size(); + width = size.width; + height = size.height; +} + +void WebWidgetHost::AddWindowedPlugin(gfx::PluginWindowHandle handle) +{ + WebPluginGeometry geometry; + plugin_map_.insert(std::make_pair(handle, geometry)); +} + +void WebWidgetHost::RemoveWindowedPlugin(gfx::PluginWindowHandle handle) +{ + PluginMap::iterator it = plugin_map_.find(handle); + DCHECK(it != plugin_map_.end()); + plugin_map_.erase(it); +} + +void WebWidgetHost::MoveWindowedPlugin(const WebPluginGeometry& move) +{ + PluginMap::iterator it = plugin_map_.find(move.window); + DCHECK(it != plugin_map_.end()); + + it->second.window = move.window; + if (move.rects_valid) { + it->second.window_rect = move.window_rect; + it->second.clip_rect = move.clip_rect; + it->second.cutout_rects = move.cutout_rects; + it->second.rects_valid = true; + } + it->second.visible = move.visible; +} + +gfx::PluginWindowHandle WebWidgetHost::GetWindowedPluginAt(int x, int y) +{ + if (!plugin_map_.empty()) { + PluginMap::const_iterator it = plugin_map_.begin(); + for(; it != plugin_map_.end(); ++it) { + if (it->second.visible && it->second.window_rect.Contains(x, y)) + return it->second.window; + } + } + + return NULL; +} + +void WebWidgetHost::DoPaint() { + update_task_ = NULL; + + if (update_rect_.IsEmpty()) + return; + + // TODO(cef): The below code is cross-platform but the IsIdle() method + // currently requires patches to Chromium. Since this code is only executed + // on Windows it's been stuck behind an #ifdef for now to avoid having to + // patch Chromium code on other platforms. +#if defined(OS_WIN) + if (MessageLoop::current()->IsIdle()) { + // Perform the paint. + UpdatePaintRect(update_rect_); + update_rect_ = gfx::Rect(); + Paint(); + } else { + // Try again later. + update_task_ = factory_.NewRunnableMethod(&WebWidgetHost::DoPaint); + CefThread::PostTask(CefThread::UI, FROM_HERE, update_task_); + } +#else + NOTIMPLEMENTED(); +#endif +} diff --git a/libcef/webwidget_host.h b/libcef/webwidget_host.h index 442929ae1..ec6e2002f 100644 --- a/libcef/webwidget_host.h +++ b/libcef/webwidget_host.h @@ -6,6 +6,7 @@ #define _WEBWIDGET_HOST_H #include "include/cef_string.h" +#include "include/cef_types.h" #include "base/basictypes.h" #include "base/scoped_ptr.h" #include "base/task.h" @@ -13,6 +14,8 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/rect.h" +#include "webkit/plugins/npapi/webplugin.h" +#include namespace gfx { class Rect; @@ -37,11 +40,20 @@ class NSEvent; // This class is a simple NativeView-based host for a WebWidget class WebWidgetHost { public: + class PaintDelegate { + public: + virtual void Paint(bool popup, const gfx::Rect& dirtyRect, + const void* buffer) =0; + }; + // The new instance is deleted once the associated NativeView is destroyed. // The newly created window should be resized after it is created, using the // MoveWindow (or equivalent) function. static WebWidgetHost* Create(gfx::NativeView parent_view, - WebKit::WebWidgetClient* client); + WebKit::WebWidgetClient* client, + PaintDelegate* paint_delegate); + + virtual ~WebWidgetHost(); #if defined(OS_MACOSX) static void HandleEvent(gfx::NativeView view, NSEvent* event); @@ -62,7 +74,14 @@ class WebWidgetHost { // Allow clients to update the paint rect. For example, if we get a gdk // expose or WM_PAINT event, we need to update the paint rect. void UpdatePaintRect(const gfx::Rect& rect); + void Paint(); + void InvalidateRect(const gfx::Rect& rect); + + bool GetImage(int width, int height, void* buffer); + + void SetSize(int width, int height); + void GetSize(int& width, int& height); skia::PlatformCanvas* canvas() const { return canvas_.get(); } @@ -74,12 +93,33 @@ class WebWidgetHost { void SetTooltipText(const CefString& tooltip_text); + void SendKeyEvent(cef_key_type_t type, int key, int modifiers, bool sysChar, + bool imeChar); + void SendMouseClickEvent(int x, int y, cef_mouse_button_type_t type, + bool mouseUp, int clickCount); + void SendMouseMoveEvent(int x, int y, bool mouseLeave); + void SendMouseWheelEvent(int x, int y, int delta); + void SendFocusEvent(bool setFocus); + void SendCaptureLostEvent(); + + // Manage windowed plugins when window rendering is disabled. + bool HasWindowedPlugins() { return !plugin_map_.empty(); } + void AddWindowedPlugin(gfx::PluginWindowHandle handle); + void RemoveWindowedPlugin(gfx::PluginWindowHandle handle); + void MoveWindowedPlugin(const webkit::npapi::WebPluginGeometry& geometry); + gfx::PluginWindowHandle GetWindowedPluginAt(int x, int y); + + // If window rendering is disabled paint messages are generated after all + // other pending messages have been processed. + void DoPaint(); + void set_popup(bool popup) { popup_ = popup; } bool popup() { return popup_; } + PaintDelegate* paint_delegate() { return paint_delegate_; } + protected: WebWidgetHost(); - ~WebWidgetHost(); #if defined(OS_WIN) // Per-class wndproc. Returns true if the event should be swallowed. @@ -136,23 +176,41 @@ class WebWidgetHost { void ResetTooltip(); gfx::NativeView view_; + + // The paint delegate is used instead of the view when window rendering is + // disabled. + PaintDelegate* paint_delegate_; + WebKit::WebWidget* webwidget_; scoped_ptr canvas_; // True if this widget is a popup widget. bool popup_; - // specifies the portion of the webwidget that needs painting + // Specifies the portion of the webwidget that needs painting. gfx::Rect paint_rect_; - // specifies the portion of the webwidget that needs scrolling + // Specifies the portion of the webwidget that needs scrolling. gfx::Rect scroll_rect_; int scroll_dx_; int scroll_dy_; + // Specifies the portion of the webwidget that has been invalidated when + // window rendering is disabled. + gfx::Rect update_rect_; + CancelableTask* update_task_; + + // The map of windowed plugins that need to be drawn when window rendering is + // disabled. + typedef std::map + PluginMap; + PluginMap plugin_map_; + #if defined(OS_WIN) bool track_mouse_leave_; std::wstring tooltip_text_; + gfx::NativeView tooltip_view_; + bool tooltip_showing_; #endif #if defined(TOOLKIT_USES_GTK) @@ -162,8 +220,6 @@ class WebWidgetHost { #endif WebKit::WebKeyboardEvent last_key_event_; - gfx::NativeView tooltip_view_; - bool tooltip_showing_; #ifndef NDEBUG bool painting_; diff --git a/libcef/webwidget_host_gtk.cc b/libcef/webwidget_host_gtk.cc index 27a288900..2099f6ce4 100644 --- a/libcef/webwidget_host_gtk.cc +++ b/libcef/webwidget_host_gtk.cc @@ -284,7 +284,8 @@ gfx::NativeView WebWidgetHost::CreateWidget( // static WebWidgetHost* WebWidgetHost::Create(GtkWidget* parent_view, - WebWidgetClient* client) { + WebWidgetClient* client, + PaintDelegate* paint_delegate) { WebWidgetHost* host = new WebWidgetHost(); host->view_ = CreateWidget(parent_view, host); host->webwidget_ = WebPopupMenu::create(client); @@ -295,10 +296,6 @@ WebWidgetHost* WebWidgetHost::Create(GtkWidget* parent_view, return host; } -void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) { - paint_rect_ = paint_rect_.Union(rect); -} - void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) { DLOG_IF(WARNING, painting_) << "unexpected invalidation while painting"; @@ -331,10 +328,12 @@ void WebWidgetHost::ScheduleComposite() { WebWidgetHost::WebWidgetHost() : view_(NULL), + paint_delegate_(NULL), webwidget_(NULL), popup_(false), scroll_dx_(0), scroll_dy_(0), + update_task_(NULL), ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) { set_painting(false); } @@ -349,10 +348,8 @@ WebWidgetHost::~WebWidgetHost() { } void WebWidgetHost::Resize(const gfx::Size &newsize) { - // The pixel buffer backing us is now the wrong size - canvas_.reset(); logical_size_ = newsize; - webwidget_->resize(newsize); + SetSize(newsize.width(), newsize.height()); } void WebWidgetHost::Paint() { @@ -419,6 +416,27 @@ void WebWidgetHost::Paint() { gdk_window_end_paint(window); } +void WebWidgetHost::SetTooltipText(const CefString& tooltip_text) +{ + // TODO(port): Implement this method as part of tooltip support. +} + +void WebWidgetHost::InvalidateRect(const gfx::Rect& rect) +{ + // TODO(port): Implement this method as part of off-screen rendering support. + NOTIMPLEMENTED(); +} + +bool WebWidgetHost::GetImage(int width, int height, void* rgba_buffer) +{ + if (!canvas_.get()) + return false; + + // TODO(port): Implement this method as part of off-screen rendering support. + NOTIMPLEMENTED(); + return false; +} + WebScreenInfo WebWidgetHost::GetScreenInfo() { Display* display = GtkWidgetGetDisplay(view_); int screen_num = GtkWidgetGetScreenNum(view_); @@ -439,3 +457,52 @@ void WebWidgetHost::PaintRect(const gfx::Rect& rect) { void WebWidgetHost::WindowDestroyed() { delete this; } + +void WebWidgetHost::SendKeyEvent(cef_key_type_t type, int key, int modifiers, + bool sysChar, bool imeChar) +{ + // TODO(port): Implement this method as part of off-screen rendering support. + NOTIMPLEMENTED(); +} + +void WebWidgetHost::SendMouseClickEvent(int x, int y, + cef_mouse_button_type_t type, + bool mouseUp, int clickCount) +{ + // TODO(port): Implement this method as part of off-screen rendering support. + NOTIMPLEMENTED(); +} + +void WebWidgetHost::SendMouseMoveEvent(int x, int y, bool mouseLeave) +{ + // TODO(port): Implement this method as part of off-screen rendering support. + NOTIMPLEMENTED(); +} + +void WebWidgetHost::SendMouseWheelEvent(int x, int y, int delta) +{ + // TODO(port): Implement this method as part of off-screen rendering support. + NOTIMPLEMENTED(); +} + +void WebWidgetHost::SendFocusEvent(bool setFocus) +{ + // TODO(port): Implement this method as part of off-screen rendering support. + NOTIMPLEMENTED(); +} + +void WebWidgetHost::SendCaptureLostEvent() +{ + // TODO(port): Implement this method as part of off-screen rendering support. + NOTIMPLEMENTED(); +} + +void WebWidgetHost::EnsureTooltip() +{ + // TODO(port): Implement this method as part of tooltip support. +} + +void WebWidgetHost::ResetTooltip() +{ + // TODO(port): Implement this method as part of tooltip support. +} diff --git a/libcef/webwidget_host_mac.mm b/libcef/webwidget_host_mac.mm index 646e18bb2..63b3b9351 100644 --- a/libcef/webwidget_host_mac.mm +++ b/libcef/webwidget_host_mac.mm @@ -31,7 +31,8 @@ using WebKit::WebWidgetClient; /*static*/ WebWidgetHost* WebWidgetHost::Create(NSView* parent_view, - WebWidgetClient* client) { + WebWidgetClient* client, + PaintDelegate* paint_delegate) { WebWidgetHost* host = new WebWidgetHost(); NSRect content_rect = [parent_view frame]; @@ -133,16 +134,14 @@ void WebWidgetHost::ScheduleComposite() { [view_ setNeedsDisplayInRect:r]; } -void WebWidgetHost::DiscardBackingStore() { - canvas_.reset(); -} - WebWidgetHost::WebWidgetHost() : view_(NULL), + paint_delegate_(NULL), webwidget_(NULL), popup_(false), scroll_dx_(0), scroll_dy_(0), + update_task_(NULL), ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) { set_painting(false); } @@ -150,10 +149,6 @@ WebWidgetHost::WebWidgetHost() WebWidgetHost::~WebWidgetHost() { } -void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) { - paint_rect_ = paint_rect_.Union(rect); -} - void WebWidgetHost::Paint() { gfx::Rect client_rect(NSRectToCGRect([view_ frame])); NSGraphicsContext* view_context = [NSGraphicsContext currentContext]; @@ -218,8 +213,25 @@ void WebWidgetHost::Paint() { } } -void WebWidgetHost::SetTooltipText(const CefString& tooltip_text) { - // TODO(port): Implement this method. +void WebWidgetHost::SetTooltipText(const CefString& tooltip_text) +{ + // TODO(port): Implement this method as part of tooltip support. +} + +void WebWidgetHost::InvalidateRect(const gfx::Rect& rect) +{ + // TODO(port): Implement this method as part of off-screen rendering support. + NOTIMPLEMENTED(); +} + +bool WebWidgetHost::GetImage(int width, int height, void* rgba_buffer) +{ + if (!canvas_.get()) + return false; + + // TODO(port): Implement this method as part of off-screen rendering support. + NOTIMPLEMENTED(); + return false; } WebScreenInfo WebWidgetHost::GetScreenInfo() { @@ -227,9 +239,7 @@ WebScreenInfo WebWidgetHost::GetScreenInfo() { } void WebWidgetHost::Resize(const gfx::Rect& rect) { - // Force an entire re-paint. TODO(darin): Maybe reuse this memory buffer. - DiscardBackingStore(); - webwidget_->resize(WebSize(rect.width(), rect.height())); + SetSize(rect.width(), rect.height()); } void WebWidgetHost::MouseEvent(NSEvent *event) { @@ -275,3 +285,52 @@ void WebWidgetHost::PaintRect(const gfx::Rect& rect) { webwidget_->paint(webkit_glue::ToWebCanvas(canvas_.get()), rect); set_painting(false); } + +void WebWidgetHost::SendKeyEvent(cef_key_type_t type, int key, int modifiers, + bool sysChar, bool imeChar) +{ + // TODO(port): Implement this method as part of off-screen rendering support. + NOTIMPLEMENTED(); +} + +void WebWidgetHost::SendMouseClickEvent(int x, int y, + cef_mouse_button_type_t type, + bool mouseUp, int clickCount) +{ + // TODO(port): Implement this method as part of off-screen rendering support. + NOTIMPLEMENTED(); +} + +void WebWidgetHost::SendMouseMoveEvent(int x, int y, bool mouseLeave) +{ + // TODO(port): Implement this method as part of off-screen rendering support. + NOTIMPLEMENTED(); +} + +void WebWidgetHost::SendMouseWheelEvent(int x, int y, int delta) +{ + // TODO(port): Implement this method as part of off-screen rendering support. + NOTIMPLEMENTED(); +} + +void WebWidgetHost::SendFocusEvent(bool setFocus) +{ + // TODO(port): Implement this method as part of off-screen rendering support. + NOTIMPLEMENTED(); +} + +void WebWidgetHost::SendCaptureLostEvent() +{ + // TODO(port): Implement this method as part of off-screen rendering support. + NOTIMPLEMENTED(); +} + +void WebWidgetHost::EnsureTooltip() +{ + // TODO(port): Implement this method as part of tooltip support. +} + +void WebWidgetHost::ResetTooltip() +{ + // TODO(port): Implement this method as part of tooltip support. +} diff --git a/libcef/webwidget_host_win.cc b/libcef/webwidget_host_win.cc index 1308b2b22..9072c88ef 100644 --- a/libcef/webwidget_host_win.cc +++ b/libcef/webwidget_host_win.cc @@ -4,6 +4,7 @@ // found in the LICENSE file. #include "webwidget_host.h" +#include "cef_thread.h" #include "ui/gfx/rect.h" #include "base/logging.h" @@ -14,9 +15,11 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/win/WebInputEventFactory.h" #include "third_party/WebKit/Source/WebKit/chromium/public/win/WebScreenInfoFactory.h" #include "ui/base/win/hwnd_util.h" +#include "ui/gfx/gdi_util.h" #include +using webkit::npapi::WebPluginGeometry; using WebKit::WebInputEvent; using WebKit::WebInputEventFactory; using WebKit::WebKeyboardEvent; @@ -31,31 +34,64 @@ using WebKit::WebWidgetClient; static const wchar_t kWindowClassName[] = L"WebWidgetHost"; +namespace { + +struct MessageInfo { + UINT message; + WPARAM wParam; + LPARAM lParam; +}; + +BOOL CALLBACK SendMessageFunc(HWND hwnd, LPARAM lParam) +{ + MessageInfo* info = reinterpret_cast(lParam); + SendMessage(hwnd, info->message, info->wParam, info->lParam); + return TRUE; +} + +// Plugins are hosted in a Chromium-created parent window so it's necessary to +// send messages directly to the child window. +void SendMessageToPlugin(HWND hwnd, UINT message, WPARAM wParam, + LPARAM lParam) +{ + MessageInfo info = {message, wParam, lParam}; + EnumChildWindows(hwnd, SendMessageFunc, reinterpret_cast(&info)); +} + +} // namespace + /*static*/ WebWidgetHost* WebWidgetHost::Create(HWND parent_view, - WebWidgetClient* client) { + WebWidgetClient* client, + PaintDelegate* paint_delegate) { WebWidgetHost* host = new WebWidgetHost(); - static bool registered_class = false; - if (!registered_class) { - WNDCLASSEX wcex = {0}; - wcex.cbSize = sizeof(wcex); - wcex.style = CS_DBLCLKS; - wcex.lpfnWndProc = WebWidgetHost::WndProc; - wcex.hInstance = GetModuleHandle(NULL); - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.lpszClassName = kWindowClassName; - RegisterClassEx(&wcex); - registered_class = true; + if (!paint_delegate) { + // Create a window for the host. + static bool registered_class = false; + if (!registered_class) { + WNDCLASSEX wcex = {0}; + wcex.cbSize = sizeof(wcex); + wcex.style = CS_DBLCLKS; + wcex.lpfnWndProc = WebWidgetHost::WndProc; + wcex.hInstance = GetModuleHandle(NULL); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.lpszClassName = kWindowClassName; + RegisterClassEx(&wcex); + registered_class = true; + } + + host->view_ = CreateWindowEx(WS_EX_TOOLWINDOW, + kWindowClassName, kWindowClassName, WS_POPUP, + 0, 0, 0, 0, + parent_view, NULL, GetModuleHandle(NULL), + NULL); + + ui::SetWindowUserData(host->view_, host); + } else { + host->paint_delegate_ = paint_delegate; } - host->view_ = CreateWindowEx(WS_EX_TOOLWINDOW, - kWindowClassName, kWindowClassName, WS_POPUP, - 0, 0, 0, 0, - parent_view, NULL, GetModuleHandle(NULL), NULL); - - ui::SetWindowUserData(host->view_, host); - host->webwidget_ = WebPopupMenu::create(client); return host; @@ -73,6 +109,7 @@ LRESULT CALLBACK WebWidgetHost::WndProc(HWND hwnd, UINT message, WPARAM wparam, if (host && !host->WndProc(message, wparam, lparam)) { switch (message) { case WM_PAINT: { + // Paint to the window. RECT rect; if (GetUpdateRect(hwnd, &rect, FALSE)) { host->UpdatePaintRect(gfx::Rect(rect)); @@ -161,10 +198,8 @@ void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) { paint_rect_ = paint_rect_.Union(scroll_rect_); ResetScrollRect(); } - paint_rect_ = paint_rect_.Union(damaged_rect); - RECT r = damaged_rect.ToRECT(); - InvalidateRect(view_, &r, FALSE); + InvalidateRect(gfx::Rect(damaged_rect)); } void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { @@ -187,36 +222,32 @@ void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { scroll_dx_ = dx; scroll_dy_ = dy; - RECT r = clip_rect.ToRECT(); - InvalidateRect(view_, &r, FALSE); + InvalidateRect(clip_rect); } void WebWidgetHost::ScheduleComposite() { if (!webwidget_) return; WebSize size = webwidget_->size(); - gfx::Rect rect(0, 0, size.width, size.height); - RECT r = rect.ToRECT(); - InvalidateRect(view_, &r, FALSE); + InvalidateRect(gfx::Rect(0, 0, size.width, size.height)); } void WebWidgetHost::SetCursor(HCURSOR cursor) { + DCHECK(view_); SetClassLong(view_, GCL_HCURSOR, static_cast(reinterpret_cast(cursor))); ::SetCursor(cursor); } -void WebWidgetHost::DiscardBackingStore() { - canvas_.reset(); -} - WebWidgetHost::WebWidgetHost() : view_(NULL), + paint_delegate_(NULL), webwidget_(NULL), popup_(false), track_mouse_leave_(false), scroll_dx_(0), scroll_dy_(0), + update_task_(NULL), tooltip_view_(NULL), tooltip_showing_(false), ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) { @@ -224,7 +255,8 @@ WebWidgetHost::WebWidgetHost() } WebWidgetHost::~WebWidgetHost() { - ui::SetWindowUserData(view_, 0); + if (view_) + ui::SetWindowUserData(view_, 0); TrackMouseLeave(false); ResetTooltip(); @@ -243,15 +275,15 @@ bool WebWidgetHost::WndProc(UINT message, WPARAM wparam, LPARAM lparam) { return false; } -void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) { - paint_rect_ = paint_rect_.Union(rect); -} - void WebWidgetHost::Paint() { - RECT r; - GetClientRect(view_, &r); - gfx::Rect client_rect(r); - + if (canvas_.get() && paint_rect_.IsEmpty()) + return; + + int width, height; + GetSize(width, height); + gfx::Rect client_rect(width, height); + gfx::Rect damaged_rect; + // Allocate a canvas if necessary if (!canvas_.get()) { ResetScrollRect(); @@ -270,10 +302,10 @@ void WebWidgetHost::Paint() { if (!scroll_rect_.IsEmpty()) { HDC hdc = canvas_->getTopPlatformDevice().getBitmapDC(); - RECT damaged_rect, r = scroll_rect_.ToRECT(); - ScrollDC(hdc, scroll_dx_, scroll_dy_, NULL, &r, NULL, &damaged_rect); + RECT damaged_scroll_rect, r = scroll_rect_.ToRECT(); + ScrollDC(hdc, scroll_dx_, scroll_dy_, NULL, &r, NULL, &damaged_scroll_rect); - PaintRect(gfx::Rect(damaged_rect)); + PaintRect(gfx::Rect(damaged_scroll_rect)); } ResetScrollRect(); @@ -282,6 +314,7 @@ void WebWidgetHost::Paint() { // objects update their layout only when painted. for (int i = 0; i < 2; ++i) { paint_rect_ = client_rect.Intersect(paint_rect_); + damaged_rect = damaged_rect.Union(paint_rect_); if (!paint_rect_.IsEmpty()) { gfx::Rect rect(paint_rect_); paint_rect_ = gfx::Rect(); @@ -292,17 +325,116 @@ void WebWidgetHost::Paint() { } DCHECK(paint_rect_.IsEmpty()); - // Paint to the screen - PAINTSTRUCT ps; - BeginPaint(view_, &ps); - canvas_->getTopPlatformDevice().drawToHDC(ps.hdc, - ps.rcPaint.left, - ps.rcPaint.top, - &ps.rcPaint); - EndPaint(view_, &ps); + if (plugin_map_.size() > 0) { + typedef std::list PluginList; + PluginList visible_plugins; + + // Identify the visible plugins. + PluginMap::const_iterator it = plugin_map_.begin(); + for(; it != plugin_map_.end(); ++it) { + if (it->second.visible && client_rect.Intersects(it->second.window_rect)) + visible_plugins.push_back(&it->second); + } - // Draw children - UpdateWindow(view_); + if (!visible_plugins.empty()) { + HDC drawDC = canvas_->beginPlatformPaint(); + HRGN oldRGN, newRGN; + POINT oldViewport; + + // Paint the plugin windows. + PluginList::const_iterator it = visible_plugins.begin(); + for(; it != visible_plugins.end(); ++it) { + const WebPluginGeometry* geom = *(it); + + oldRGN = CreateRectRgn(0,0,1,1); + GetClipRgn(drawDC, oldRGN); + + // Only paint inside the clip region. + newRGN = CreateRectRgn(geom->clip_rect.x(), + geom->clip_rect.y(), + geom->clip_rect.right(), + geom->clip_rect.bottom()); + gfx::SubtractRectanglesFromRegion(newRGN, geom->cutout_rects); + OffsetRgn(newRGN, geom->window_rect.x(), geom->window_rect.y()); + SelectClipRgn(drawDC, newRGN); + + // Change the viewport origin to the plugin window origin. + SetViewportOrgEx(drawDC, geom->window_rect.x(), geom->window_rect.y(), + &oldViewport); + + SendMessageToPlugin(geom->window, WM_PRINT, + reinterpret_cast(drawDC), + PRF_OWNED | PRF_ERASEBKGND | PRF_CLIENT | PRF_NONCLIENT); + + SetViewportOrgEx(drawDC, oldViewport.x, oldViewport.y, NULL); + SelectClipRgn(drawDC, oldRGN); + + damaged_rect = damaged_rect.Union(geom->window_rect); + } + + canvas_->endPlatformPaint(); + + // Make sure the damaged rectangle is inside the client rectangle. + damaged_rect = damaged_rect.Intersect(client_rect); + } + } + + if (view_) { + // Paint to the window. + PAINTSTRUCT ps; + BeginPaint(view_, &ps); + canvas_->getTopPlatformDevice().drawToHDC(ps.hdc, + ps.rcPaint.left, + ps.rcPaint.top, + &ps.rcPaint); + EndPaint(view_, &ps); + + // Draw children + UpdateWindow(view_); + } else { + // Paint to the delegate. + DCHECK(paint_delegate_); + const SkBitmap& bitmap = + canvas_->getTopPlatformDevice().accessBitmap(false); + DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config); + const void* pixels = bitmap.getPixels(); + paint_delegate_->Paint(popup_, damaged_rect, pixels); + } +} + +void WebWidgetHost::InvalidateRect(const gfx::Rect& rect) +{ + if (rect.IsEmpty()) + return; + + if (view_) { + // Let the window handle painting. + RECT r = {rect.x(), rect.y(), rect.x() + rect.width(), + rect.y() + rect.height()}; + ::InvalidateRect(view_, &r, FALSE); + } else { + // The update rectangle will be painted by DoPaint(). + update_rect_ = update_rect_.Union(rect); + if (!update_task_) { + update_task_ = factory_.NewRunnableMethod(&WebWidgetHost::DoPaint); + CefThread::PostTask(CefThread::UI, FROM_HERE, update_task_); + } + } +} + +bool WebWidgetHost::GetImage(int width, int height, void* buffer) +{ + if (!canvas_.get()) + return false; + + DCHECK(width == canvas_->getTopPlatformDevice().width()); + DCHECK(height == canvas_->getTopPlatformDevice().height()); + + const SkBitmap& bitmap = canvas_->getTopPlatformDevice().accessBitmap(false); + DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config); + const void* pixels = bitmap.getPixels(); + memcpy(buffer, pixels, width * height * 4); + return true; } WebScreenInfo WebWidgetHost::GetScreenInfo() { @@ -310,11 +442,7 @@ WebScreenInfo WebWidgetHost::GetScreenInfo() { } void WebWidgetHost::Resize(LPARAM lparam) { - // Force an entire re-paint. TODO(darin): Maybe reuse this memory buffer. - DiscardBackingStore(); - - webwidget_->resize(WebSize(LOWORD(lparam), HIWORD(lparam))); - EnsureTooltip(); + SetSize(LOWORD(lparam), HIWORD(lparam)); } void WebWidgetHost::MouseEvent(UINT message, WPARAM wparam, LPARAM lparam) { @@ -393,6 +521,9 @@ void WebWidgetHost::OnNotify(WPARAM wparam, NMHDR* header) { } void WebWidgetHost::SetTooltipText(const CefString& tooltip_text) { + if (!view_) + return; + std::wstring new_tooltip_text(tooltip_text); if (new_tooltip_text != tooltip_text_) { tooltip_text_ = new_tooltip_text; @@ -417,33 +548,43 @@ void WebWidgetHost::SetTooltipText(const CefString& tooltip_text) { } void WebWidgetHost::EnsureTooltip() { + if (!view_) + return; + UINT message = TTM_NEWTOOLRECT; TOOLINFO ti; ti.cbSize = sizeof(ti); - ti.hwnd = view_handle(); + ti.hwnd = view_; ti.uId = 0; if (!::IsWindow(tooltip_view_)) { message = TTM_ADDTOOL; tooltip_view_ = CreateWindowEx( WS_EX_TRANSPARENT, - TOOLTIPS_CLASS, L"tooltip_view_", TTS_NOPREFIX, 0, 0, 0, 0, view_handle(), NULL, + TOOLTIPS_CLASS, L"tooltip_view_", TTS_NOPREFIX, 0, 0, 0, 0, + view_, NULL, NULL, NULL); ti.uFlags = TTF_SUBCLASS; ti.lpszText = LPSTR_TEXTCALLBACK; } - GetClientRect(view_handle(), &ti.rect); + GetClientRect(view_, &ti.rect); SendMessage(tooltip_view_, message, NULL, reinterpret_cast(&ti)); } void WebWidgetHost::ResetTooltip() { + if (!view_) + return; + if (::IsWindow(tooltip_view_)) ::DestroyWindow(tooltip_view_); tooltip_view_ = NULL; } void WebWidgetHost::TrackMouseLeave(bool track) { + if (!view_) + return; + if (track == track_mouse_leave_) return; track_mouse_leave_ = track; @@ -476,3 +617,168 @@ void WebWidgetHost::PaintRect(const gfx::Rect& rect) { webwidget_->paint(canvas_.get(), rect); set_painting(false); } + +void WebWidgetHost::SendKeyEvent(cef_key_type_t type, int key, int modifiers, + bool sysChar, bool imeChar) +{ + UINT message = 0; + WPARAM wparam = key; + LPARAM lparam = modifiers; + + if (type == KT_KEYUP) { + if (sysChar) + message = WM_SYSKEYUP; + else if(imeChar) + message = WM_IME_KEYUP; + else + message = WM_KEYUP; + } else if(type == KT_KEYDOWN) { + if (sysChar) + message = WM_SYSKEYDOWN; + else if(imeChar) + message = WM_IME_KEYDOWN; + else + message = WM_KEYDOWN; + } else if(type == KT_CHAR) { + if (sysChar) + message = WM_SYSCHAR; + else if(imeChar) + message = WM_IME_CHAR; + else + message = WM_CHAR; + } + + if (message == 0) { + NOTREACHED(); + return; + } + + const WebKeyboardEvent& event = WebInputEventFactory::keyboardEvent( + NULL, message, wparam, lparam); + last_key_event_ = event; + + webwidget_->handleInputEvent(event); +} + +void WebWidgetHost::SendMouseClickEvent(int x, int y, + cef_mouse_button_type_t type, + bool mouseUp, int clickCount) +{ + DCHECK(clickCount >=1 && clickCount <= 2); + + UINT message = 0; + WPARAM wparam = 0; + LPARAM lparam = MAKELPARAM(x, y); + + if (type == MBT_LEFT) { + if (mouseUp) + message = (clickCount==1?WM_LBUTTONUP:WM_LBUTTONDBLCLK); + else + message = WM_LBUTTONDOWN; + } else if (type == MBT_MIDDLE) { + if (mouseUp) + message = (clickCount==1?WM_MBUTTONUP:WM_MBUTTONDBLCLK); + else + message = WM_MBUTTONDOWN; + } else if (type == MBT_RIGHT) { + if (mouseUp) + message = (clickCount==1?WM_RBUTTONUP:WM_RBUTTONDBLCLK); + else + message = WM_RBUTTONDOWN; + } + + if (message == 0) { + NOTREACHED(); + return; + } + + if (GetKeyState(VK_CONTROL) & 0x8000) + wparam |= MK_CONTROL; + if (GetKeyState(VK_SHIFT) & 0x8000) + wparam |= MK_SHIFT; + if (GetKeyState(VK_LBUTTON) & 0x8000) + wparam |= MK_LBUTTON; + if (GetKeyState(VK_MBUTTON) & 0x8000) + wparam |= MK_MBUTTON; + if (GetKeyState(VK_RBUTTON) & 0x8000) + wparam |= MK_RBUTTON; + + gfx::PluginWindowHandle plugin = GetWindowedPluginAt(x, y); + if (plugin) { + SendMessageToPlugin(plugin, message, wparam, lparam); + } else { + const WebMouseEvent& event = WebInputEventFactory::mouseEvent(NULL, message, + wparam, lparam); + webwidget_->handleInputEvent(event); + } +} + +void WebWidgetHost::SendMouseMoveEvent(int x, int y, bool mouseLeave) +{ + UINT message; + WPARAM wparam = 0; + LPARAM lparam = 0; + + if (mouseLeave) { + message = WM_MOUSELEAVE; + } else { + message = WM_MOUSEMOVE; + lparam = MAKELPARAM(x, y); + } + + if (GetKeyState(VK_CONTROL) & 0x8000) + wparam |= MK_CONTROL; + if (GetKeyState(VK_SHIFT) & 0x8000) + wparam |= MK_SHIFT; + if (GetKeyState(VK_LBUTTON) & 0x8000) + wparam |= MK_LBUTTON; + if (GetKeyState(VK_MBUTTON) & 0x8000) + wparam |= MK_MBUTTON; + if (GetKeyState(VK_RBUTTON) & 0x8000) + wparam |= MK_RBUTTON; + + gfx::PluginWindowHandle plugin = GetWindowedPluginAt(x, y); + if (plugin) { + SendMessageToPlugin(plugin, message, wparam, lparam); + } else { + const WebMouseEvent& event = WebInputEventFactory::mouseEvent(NULL, message, + wparam, lparam); + webwidget_->handleInputEvent(event); + } +} + +void WebWidgetHost::SendMouseWheelEvent(int x, int y, int delta) +{ + WPARAM wparam = MAKEWPARAM(0, delta); + LPARAM lparam = MAKELPARAM(x, y); + + if (GetKeyState(VK_CONTROL) & 0x8000) + wparam |= MK_CONTROL; + if (GetKeyState(VK_SHIFT) & 0x8000) + wparam |= MK_SHIFT; + if (GetKeyState(VK_LBUTTON) & 0x8000) + wparam |= MK_LBUTTON; + if (GetKeyState(VK_MBUTTON) & 0x8000) + wparam |= MK_MBUTTON; + if (GetKeyState(VK_RBUTTON) & 0x8000) + wparam |= MK_RBUTTON; + + gfx::PluginWindowHandle plugin = GetWindowedPluginAt(x, y); + if (plugin) { + SendMessageToPlugin(plugin, WM_MOUSEWHEEL, wparam, lparam); + } else { + const WebMouseWheelEvent& event = WebInputEventFactory::mouseWheelEvent( + NULL, WM_MOUSEWHEEL, wparam, lparam); + webwidget_->handleInputEvent(event); + } +} + +void WebWidgetHost::SendFocusEvent(bool setFocus) +{ + SetFocus(setFocus); +} + +void WebWidgetHost::SendCaptureLostEvent() +{ + CaptureLostEvent(); +} diff --git a/libcef_dll/cpptoc/browser_cpptoc.cc b/libcef_dll/cpptoc/browser_cpptoc.cc index 725c5cba0..99c36e529 100644 --- a/libcef_dll/cpptoc/browser_cpptoc.cc +++ b/libcef_dll/cpptoc/browser_cpptoc.cc @@ -285,6 +285,142 @@ void CEF_CALLBACK browser_close_dev_tools(struct _cef_browser_t* self) CefBrowserCppToC::Get(self)->CloseDevTools(); } +int CEF_CALLBACK browser_is_window_rendering_disabled( + struct _cef_browser_t* self) +{ + DCHECK(self); + if(!self) + return 0; + + return CefBrowserCppToC::Get(self)->IsWindowRenderingDisabled(); +} + +int CEF_CALLBACK browser_get_size(struct _cef_browser_t* self, + enum cef_paint_element_type_t type, int* width, int* height) +{ + DCHECK(self); + DCHECK(width); + DCHECK(height); + if(!self || !width || !height) + return 0; + + return CefBrowserCppToC::Get(self)->GetSize(type, *width, *height); +} + +void CEF_CALLBACK browser_set_size(struct _cef_browser_t* self, + enum cef_paint_element_type_t type, int width, int height) +{ + DCHECK(self); + if(!self) + return; + + return CefBrowserCppToC::Get(self)->SetSize(type, width, height); +} + +int CEF_CALLBACK browser_is_popup_visible(struct _cef_browser_t* self) +{ + DCHECK(self); + if(!self) + return 0; + + return CefBrowserCppToC::Get(self)->IsPopupVisible(); +} + +void CEF_CALLBACK browser_hide_popup(struct _cef_browser_t* self) +{ + DCHECK(self); + if(!self) + return; + + CefBrowserCppToC::Get(self)->HidePopup(); +} + +void CEF_CALLBACK browser_invalidate(struct _cef_browser_t* self, + const cef_rect_t* dirtyRect) +{ + DCHECK(self); + DCHECK(dirtyRect); + if(!self || !dirtyRect) + return; + + CefRect rect(*dirtyRect); + CefBrowserCppToC::Get(self)->Invalidate(rect); +} + +int CEF_CALLBACK browser_get_image(struct _cef_browser_t* self, + enum cef_paint_element_type_t type, int width, int height, void* buffer) +{ + DCHECK(self); + DCHECK(buffer); + if(!self || !buffer) + return 0; + + return CefBrowserCppToC::Get(self)->GetImage(type, width, height, buffer); +} + +void CEF_CALLBACK browser_send_key_event(struct _cef_browser_t* self, + enum cef_key_type_t type, int key, int modifiers, int sysChar, + int imeChar) +{ + DCHECK(self); + if(!self) + return; + + CefBrowserCppToC::Get(self)->SendKeyEvent(type, key, modifiers, + sysChar?true:false, imeChar?true:false); +} + +void CEF_CALLBACK browser_send_mouse_click_event(struct _cef_browser_t* self, + int x, int y, enum cef_mouse_button_type_t type, int mouseUp, + int clickCount) +{ + DCHECK(self); + if(!self) + return; + + CefBrowserCppToC::Get(self)->SendMouseClickEvent(x, y, type, + mouseUp?true:false, clickCount); +} + +void CEF_CALLBACK browser_send_mouse_move_event(struct _cef_browser_t* self, + int x, int y, int mouseLeave) +{ + DCHECK(self); + if(!self) + return; + + CefBrowserCppToC::Get(self)->SendMouseMoveEvent(x, y, mouseLeave?true:false); +} + +void CEF_CALLBACK browser_send_mouse_wheel_event(struct _cef_browser_t* self, + int x, int y, int delta) +{ + DCHECK(self); + if(!self) + return; + + CefBrowserCppToC::Get(self)->SendMouseWheelEvent(x, y, delta); +} + +void CEF_CALLBACK browser_send_focus_event(struct _cef_browser_t* self, + int setFocus) +{ + DCHECK(self); + if(!self) + return; + + CefBrowserCppToC::Get(self)->SendFocusEvent(setFocus?true:false); +} + +void CEF_CALLBACK browser_send_capture_lost_event(struct _cef_browser_t* self) +{ + DCHECK(self); + if(!self) + return; + + CefBrowserCppToC::Get(self)->SendCaptureLostEvent(); +} + // CONSTRUCTOR - Do not edit by hand. @@ -313,6 +449,20 @@ CefBrowserCppToC::CefBrowserCppToC(CefBrowser* cls) struct_.struct_.set_zoom_level = browser_set_zoom_level; struct_.struct_.show_dev_tools = browser_show_dev_tools; struct_.struct_.close_dev_tools = browser_close_dev_tools; + struct_.struct_.is_window_rendering_disabled = + browser_is_window_rendering_disabled; + struct_.struct_.get_size = browser_get_size; + struct_.struct_.set_size = browser_set_size; + struct_.struct_.is_popup_visible = browser_is_popup_visible; + struct_.struct_.hide_popup = browser_hide_popup; + struct_.struct_.invalidate = browser_invalidate; + struct_.struct_.get_image = browser_get_image; + struct_.struct_.send_key_event = browser_send_key_event; + struct_.struct_.send_mouse_click_event = browser_send_mouse_click_event; + struct_.struct_.send_mouse_move_event = browser_send_mouse_move_event; + struct_.struct_.send_mouse_wheel_event = browser_send_mouse_wheel_event; + struct_.struct_.send_focus_event = browser_send_focus_event; + struct_.struct_.send_capture_lost_event = browser_send_capture_lost_event; } #ifdef _DEBUG diff --git a/libcef_dll/cpptoc/handler_cpptoc.cc b/libcef_dll/cpptoc/handler_cpptoc.cc index 735b58a92..4708063ab 100644 --- a/libcef_dll/cpptoc/handler_cpptoc.cc +++ b/libcef_dll/cpptoc/handler_cpptoc.cc @@ -117,6 +117,20 @@ enum cef_retval_t CEF_CALLBACK handler_handle_title_change( CefBrowserCToCpp::Wrap(browser), CefString(title)); } +enum cef_retval_t CEF_CALLBACK handler_handle_nav_state_change( + struct _cef_handler_t* self, cef_browser_t* browser, int canGoBack, + int canGoForward) +{ + DCHECK(self); + DCHECK(browser); + if(!self || !browser) + return RV_CONTINUE; + + return CefHandlerCppToC::Get(self)->HandleNavStateChange( + CefBrowserCToCpp::Wrap(browser), (canGoBack?true:false), + (canGoForward?true:false)); +} + enum cef_retval_t CEF_CALLBACK handler_handle_before_browse( struct _cef_handler_t* self, cef_browser_t* browser, cef_frame_t* frame, struct _cef_request_t* request, enum cef_handler_navtype_t navType, @@ -545,6 +559,81 @@ enum cef_retval_t CEF_CALLBACK handler_handle_find_result( activeMatchOrdinal, finalUpdate?true:false); } +enum cef_retval_t CEF_CALLBACK handler_handle_get_rect( + struct _cef_handler_t* self, cef_browser_t* browser, int screen, + cef_rect_t* rect) +{ + DCHECK(self); + DCHECK(browser); + DCHECK(rect); + if(!self || !browser || !rect) + return RV_CONTINUE; + + CefRect changeRect(*rect); + cef_retval_t rv = CefHandlerCppToC::Get(self)->HandleGetRect( + CefBrowserCToCpp::Wrap(browser), screen?true:false, changeRect); + *rect = changeRect; + return rv; +} + +enum cef_retval_t CEF_CALLBACK handler_handle_get_screen_point( + struct _cef_handler_t* self, cef_browser_t* browser, int viewX, int viewY, + int* screenX, int* screenY) +{ + DCHECK(self); + DCHECK(browser); + DCHECK(screenX); + DCHECK(screenY); + if(!self || !browser || !screenX || !screenY) + return RV_CONTINUE; + + return CefHandlerCppToC::Get(self)->HandleGetScreenPoint( + CefBrowserCToCpp::Wrap(browser), viewX, viewY, *screenX, *screenY); +} + +enum cef_retval_t CEF_CALLBACK handler_handle_popup_change( + struct _cef_handler_t* self, cef_browser_t* browser, int show, + const cef_rect_t* rect) +{ + DCHECK(self); + DCHECK(browser); + DCHECK(rect); + if(!self || !browser || !rect) + return RV_CONTINUE; + + CefRect changeRect(*rect); + return CefHandlerCppToC::Get(self)->HandlePopupChange( + CefBrowserCToCpp::Wrap(browser), show?true:false, changeRect); +} + +enum cef_retval_t CEF_CALLBACK handler_handle_paint(struct _cef_handler_t* self, + cef_browser_t* browser, enum cef_paint_element_type_t type, + const cef_rect_t* dirtyRect, const void* buffer) +{ + DCHECK(self); + DCHECK(browser); + DCHECK(dirtyRect); + if(!self || !browser || !dirtyRect) + return RV_CONTINUE; + + CefRect rect(*dirtyRect); + return CefHandlerCppToC::Get(self)->HandlePaint( + CefBrowserCToCpp::Wrap(browser), type, rect, buffer); +} + +enum cef_retval_t CEF_CALLBACK handler_handle_cursor_change( + struct _cef_handler_t* self, cef_browser_t* browser, + cef_cursor_handle_t cursor) +{ + DCHECK(self); + DCHECK(browser); + if(!self || !browser) + return RV_CONTINUE; + + return CefHandlerCppToC::Get(self)->HandleCursorChange( + CefBrowserCToCpp::Wrap(browser), cursor); +} + // CONSTRUCTOR - Do not edit by hand. @@ -555,6 +644,7 @@ CefHandlerCppToC::CefHandlerCppToC(CefHandler* cls) struct_.struct_.handle_after_created = handler_handle_after_created; struct_.struct_.handle_address_change = handler_handle_address_change; struct_.struct_.handle_title_change = handler_handle_title_change; + struct_.struct_.handle_nav_state_change = handler_handle_nav_state_change; struct_.struct_.handle_before_browse = handler_handle_before_browse; struct_.struct_.handle_load_start = handler_handle_load_start; struct_.struct_.handle_load_end = handler_handle_load_end; @@ -584,6 +674,11 @@ CefHandlerCppToC::CefHandlerCppToC(CefHandler* cls) struct_.struct_.handle_status = handler_handle_status; struct_.struct_.handle_console_message = handler_handle_console_message; struct_.struct_.handle_find_result = handler_handle_find_result; + struct_.struct_.handle_get_rect = handler_handle_get_rect; + struct_.struct_.handle_get_screen_point = handler_handle_get_screen_point; + struct_.struct_.handle_popup_change = handler_handle_popup_change; + struct_.struct_.handle_paint = handler_handle_paint; + struct_.struct_.handle_cursor_change = handler_handle_cursor_change; } #ifdef _DEBUG diff --git a/libcef_dll/ctocpp/browser_ctocpp.cc b/libcef_dll/ctocpp/browser_ctocpp.cc index 10f348c23..41de0b90a 100644 --- a/libcef_dll/ctocpp/browser_ctocpp.cc +++ b/libcef_dll/ctocpp/browser_ctocpp.cc @@ -236,6 +236,110 @@ void CefBrowserCToCpp::CloseDevTools() struct_->close_dev_tools(struct_); } +bool CefBrowserCToCpp::IsWindowRenderingDisabled() +{ + if (CEF_MEMBER_MISSING(struct_, is_window_rendering_disabled)) + return false; + + return struct_->is_window_rendering_disabled(struct_)?true:false; +} + +bool CefBrowserCToCpp::GetSize(PaintElementType type, int& width, int& height) +{ + if (CEF_MEMBER_MISSING(struct_, get_size)) + return false; + + return struct_->get_size(struct_, type, &width, &height)?true:false; +} + +void CefBrowserCToCpp::SetSize(PaintElementType type, int width, int height) +{ + if (CEF_MEMBER_MISSING(struct_, set_size)) + return; + + struct_->set_size(struct_, type, width, height); +} + +bool CefBrowserCToCpp::IsPopupVisible() +{ + if (CEF_MEMBER_MISSING(struct_, is_popup_visible)) + return false; + + return struct_->is_popup_visible(struct_)?true:false; +} + +void CefBrowserCToCpp::HidePopup() +{ + if (CEF_MEMBER_MISSING(struct_, hide_popup)) + return; + + struct_->hide_popup(struct_); +} + +void CefBrowserCToCpp::Invalidate(const CefRect& dirtyRect) +{ + if (CEF_MEMBER_MISSING(struct_, invalidate)) + return; + + struct_->invalidate(struct_, &dirtyRect); +} + +bool CefBrowserCToCpp::GetImage(PaintElementType type, int width, int height, + void* buffer) +{ + if (CEF_MEMBER_MISSING(struct_, get_image)) + return false; + + return struct_->get_image(struct_, type, width, height, buffer)?true:false; +} + +void CefBrowserCToCpp::SendKeyEvent(KeyType type, int key, int modifiers, + bool sysChar, bool imeChar) +{ + struct_->send_key_event(struct_, type, key, modifiers, sysChar, imeChar); +} + +void CefBrowserCToCpp::SendMouseClickEvent(int x, int y, MouseButtonType type, + bool mouseUp, int clickCount) +{ + if (CEF_MEMBER_MISSING(struct_, send_mouse_click_event)) + return; + + struct_->send_mouse_click_event(struct_, x, y, type, mouseUp, clickCount); +} + +void CefBrowserCToCpp::SendMouseMoveEvent(int x, int y, bool mouseLeave) +{ + if (CEF_MEMBER_MISSING(struct_, send_mouse_move_event)) + return; + + struct_->send_mouse_move_event(struct_, x, y, mouseLeave); +} + +void CefBrowserCToCpp::SendMouseWheelEvent(int x, int y, int delta) +{ + if (CEF_MEMBER_MISSING(struct_, send_mouse_wheel_event)) + return; + + struct_->send_mouse_wheel_event(struct_, x, y, delta); +} + +void CefBrowserCToCpp::SendFocusEvent(bool setFocus) +{ + if (CEF_MEMBER_MISSING(struct_, send_focus_event)) + return; + + struct_->send_focus_event(struct_, setFocus); +} + +void CefBrowserCToCpp::SendCaptureLostEvent() +{ + if (CEF_MEMBER_MISSING(struct_, send_capture_lost_event)) + return; + + struct_->send_capture_lost_event(struct_); +} + #ifdef _DEBUG template<> long CefCToCpp browser, bool canGoBack, bool canGoForward) +{ + if(CEF_MEMBER_MISSING(struct_, handle_nav_state_change)) + return RV_CONTINUE; + + return struct_->handle_nav_state_change(struct_, + CefBrowserCppToC::Wrap(browser), canGoBack, canGoForward); +} + CefHandler::RetVal CefHandlerCToCpp::HandleBeforeBrowse( CefRefPtr browser, CefRefPtr frame, CefRefPtr request, NavType navType, bool isRedirect) @@ -404,6 +414,57 @@ CefHandler::RetVal CefHandlerCToCpp::HandleFindResult( activeMatchOrdinal, finalUpdate); } +CefHandler::RetVal CefHandlerCToCpp::HandleGetRect( + CefRefPtr browser, bool screen, CefRect& rect) +{ + if(CEF_MEMBER_MISSING(struct_, handle_get_rect)) + return RV_CONTINUE; + + return struct_->handle_get_rect(struct_, CefBrowserCppToC::Wrap(browser), + screen, &rect); +} + +CefHandler::RetVal CefHandlerCToCpp::HandleGetScreenPoint( + CefRefPtr browser, int viewX, int viewY, int& screenX, + int& screenY) +{ + if(CEF_MEMBER_MISSING(struct_, handle_get_screen_point)) + return RV_CONTINUE; + + return struct_->handle_get_screen_point(struct_, + CefBrowserCppToC::Wrap(browser), viewX, viewY, &screenX, &screenY); +} + +CefHandler::RetVal CefHandlerCToCpp::HandlePopupChange( + CefRefPtr browser, bool show, const CefRect& rect) +{ + if(CEF_MEMBER_MISSING(struct_, handle_popup_change)) + return RV_CONTINUE; + + return struct_->handle_popup_change(struct_, CefBrowserCppToC::Wrap(browser), + show, &rect); +} + +CefHandler::RetVal CefHandlerCToCpp::HandlePaint(CefRefPtr browser, + PaintElementType type, const CefRect& dirtyRect, const void* buffer) +{ + if(CEF_MEMBER_MISSING(struct_, handle_paint)) + return RV_CONTINUE; + + return struct_->handle_paint(struct_, CefBrowserCppToC::Wrap(browser), type, + &dirtyRect, buffer); +} + +CefHandler::RetVal CefHandlerCToCpp::HandleCursorChange( + CefRefPtr browser, CefCursorHandle cursor) +{ + if(CEF_MEMBER_MISSING(struct_, handle_cursor_change)) + return RV_CONTINUE; + + return struct_->handle_cursor_change(struct_, CefBrowserCppToC::Wrap(browser), + cursor); +} + #ifdef _DEBUG template<> long CefCToCpp frame, const CefString& url); virtual RetVal HandleTitleChange(CefRefPtr browser, const CefString& title); + virtual RetVal HandleNavStateChange(CefRefPtr browser, + bool canGoBack, bool canGoForward); virtual RetVal HandleBeforeBrowse(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, NavType navType, bool isRedirect); @@ -96,6 +98,16 @@ public: virtual RetVal HandleFindResult(CefRefPtr browser, int identifier, int count, const CefRect& selectionRect, int activeMatchOrdinal, bool finalUpdate); + virtual RetVal HandleGetRect(CefRefPtr browser, bool screen, + CefRect& rect); + virtual RetVal HandleGetScreenPoint(CefRefPtr browser, int viewX, + int viewY, int& screenX, int& screenY); + virtual RetVal HandlePopupChange(CefRefPtr browser, bool show, + const CefRect& rect); + virtual RetVal HandlePaint(CefRefPtr browser, + PaintElementType type, const CefRect& dirtyRect, const void* buffer); + virtual RetVal HandleCursorChange(CefRefPtr browser, + CefCursorHandle cursor); }; #endif // BUILDING_CEF_SHARED diff --git a/libcef_dll/libcef_dll.cc b/libcef_dll/libcef_dll.cc index 8c0c579d7..d446f8d84 100644 --- a/libcef_dll/libcef_dll.cc +++ b/libcef_dll/libcef_dll.cc @@ -96,6 +96,11 @@ CEF_EXPORT void cef_do_message_loop_work() CefDoMessageLoopWork(); } +CEF_EXPORT void cef_run_message_loop() +{ + CefRunMessageLoop(); +} + CEF_EXPORT int cef_register_extension(const cef_string_t* extension_name, const cef_string_t* javascript_code, struct _cef_v8handler_t* handler) diff --git a/libcef_dll/wrapper/libcef_dll_wrapper.cc b/libcef_dll/wrapper/libcef_dll_wrapper.cc index f259d4abd..2d1a2cb9e 100644 --- a/libcef_dll/wrapper/libcef_dll_wrapper.cc +++ b/libcef_dll/wrapper/libcef_dll_wrapper.cc @@ -81,6 +81,11 @@ void CefDoMessageLoopWork() cef_do_message_loop_work(); } +void CefRunMessageLoop() +{ + cef_run_message_loop(); +} + bool CefRegisterExtension(const CefString& extension_name, const CefString& javascript_code, CefRefPtr handler) diff --git a/patch/patch_source.cfg b/patch/patch_source.cfg index b65c28a20..d506f97e2 100644 --- a/patch/patch_source.cfg +++ b/patch/patch_source.cfg @@ -3,4 +3,6 @@ # file entry should be proceeded by the code review or bug report link that it # relates to. patches = { + # http://codereview.chromium.org/6730028/ + 'base' : '../base/' } diff --git a/patch/patches/base.patch b/patch/patches/base.patch new file mode 100644 index 000000000..d043e5e0e --- /dev/null +++ b/patch/patches/base.patch @@ -0,0 +1,33 @@ +Index: message_loop.cc +=================================================================== +--- message_loop.cc (revision 74933) ++++ message_loop.cc (working copy) +@@ -287,9 +287,13 @@ + } + + void MessageLoop::AssertIdle() const { ++ DCHECK(IsIdle()); ++} ++ ++bool MessageLoop::IsIdle() const { + // We only check |incoming_queue_|, since we don't want to lock |work_queue_|. + base::AutoLock lock(incoming_queue_lock_); +- DCHECK(incoming_queue_.empty()); ++ return incoming_queue_.empty(); + } + + //------------------------------------------------------------------------------ +Index: message_loop.h +=================================================================== +--- message_loop.h (revision 74933) ++++ message_loop.h (working copy) +@@ -318,6 +318,9 @@ + // Asserts that the MessageLoop is "idle". + void AssertIdle() const; + ++ // Returns true if the MessageLoop is "idle". ++ bool IsIdle() const; ++ + //---------------------------------------------------------------------------- + protected: + struct RunState { diff --git a/tests/cefclient/cefclient.cpp b/tests/cefclient/cefclient.cpp index 00804cd31..2a9ab967d 100644 --- a/tests/cefclient/cefclient.cpp +++ b/tests/cefclient/cefclient.cpp @@ -35,8 +35,13 @@ void ClientHandler::ClientDownloadListener::NotifyDownloadError( // ClientHandler implementation ClientHandler::ClientHandler() - : m_MainHwnd(NULL), m_BrowserHwnd(NULL), m_EditHwnd(NULL), m_bLoading(false), - m_bCanGoBack(false), m_bCanGoForward(false), + : m_MainHwnd(NULL), + m_BrowserHwnd(NULL), + m_EditHwnd(NULL), + m_BackHwnd(NULL), + m_ForwardHwnd(NULL), + m_StopHwnd(NULL), + m_ReloadHwnd(NULL), ALLOW_THIS_IN_INITIALIZER_LIST( m_DownloadListener(new ClientDownloadListener(this))) { @@ -62,6 +67,17 @@ CefHandler::RetVal ClientHandler::HandleAfterCreated( return RV_CONTINUE; } + +CefHandler::RetVal ClientHandler::HandleNavStateChange( + CefRefPtr browser, bool canGoBack, bool canGoForward) +{ + REQUIRE_UI_THREAD(); + + SetNavState(canGoBack, canGoForward); + + return RV_CONTINUE; +} + CefHandler::RetVal ClientHandler::HandleLoadStart(CefRefPtr browser, CefRefPtr frame) { @@ -69,12 +85,8 @@ CefHandler::RetVal ClientHandler::HandleLoadStart(CefRefPtr browser, if(!browser->IsPopup() && frame->IsMain()) { - Lock(); // We've just started loading a page - m_bLoading = true; - m_bCanGoBack = false; - m_bCanGoForward = false; - Unlock(); + SetLoading(true); } return RV_CONTINUE; } @@ -86,16 +98,12 @@ CefHandler::RetVal ClientHandler::HandleLoadEnd(CefRefPtr browser, if(!browser->IsPopup() && frame->IsMain()) { - Lock(); // We've just finished loading a page - m_bLoading = false; - m_bCanGoBack = browser->CanGoBack(); - m_bCanGoForward = browser->CanGoForward(); + SetLoading(false); CefRefPtr visitor = GetDOMVisitor(frame->GetURL()); if(visitor.get()) frame->VisitDOM(visitor); - Unlock(); } return RV_CONTINUE; } @@ -227,16 +235,6 @@ CefHandler::RetVal ClientHandler::HandleConsoleMessage( return RV_HANDLED; } -void ClientHandler::GetNavState(bool &isLoading, bool &canGoBack, - bool &canGoForward) -{ - Lock(); - isLoading = m_bLoading; - canGoBack = m_bCanGoBack; - canGoForward = m_bCanGoForward; - Unlock(); -} - void ClientHandler::SetMainHwnd(CefWindowHandle hwnd) { Lock(); @@ -251,6 +249,19 @@ void ClientHandler::SetEditHwnd(CefWindowHandle hwnd) Unlock(); } +void ClientHandler::SetButtonHwnds(CefWindowHandle backHwnd, + CefWindowHandle forwardHwnd, + CefWindowHandle stopHwnd, + CefWindowHandle reloadHwnd) +{ + Lock(); + m_BackHwnd = backHwnd; + m_ForwardHwnd = forwardHwnd; + m_StopHwnd = stopHwnd; + m_ReloadHwnd = reloadHwnd; + Unlock(); +} + std::string ClientHandler::GetLogFile() { Lock(); diff --git a/tests/cefclient/cefclient.h b/tests/cefclient/cefclient.h index 850c79fcb..9da6d5cbb 100644 --- a/tests/cefclient/cefclient.h +++ b/tests/cefclient/cefclient.h @@ -11,7 +11,7 @@ // Define this value to redirect all popup URLs to the main application browser // window. -//s#define TEST_REDIRECT_POPUP_URLS +//#define TEST_REDIRECT_POPUP_URLS // Client implementation of the browser handler class class ClientHandler : public CefThreadSafeBase @@ -68,6 +68,11 @@ public: virtual RetVal HandleTitleChange(CefRefPtr browser, const CefString& title); + // Called on the UI thread when the navigation state has changed. The return + // value is currently ignored. + virtual RetVal HandleNavStateChange(CefRefPtr browser, + bool canGoBack, bool canGoForward); + // Called on the UI thread before browser navigation. The client has an // opportunity to modify the |request| object if desired. Return RV_HANDLED // to cancel navigation. @@ -365,11 +370,82 @@ public: return RV_CONTINUE; } + // Called on the UI thread to retrieve either the simulated screen rectangle + // if |screen| is true or the view rectangle if |screen| is false. The view + // rectangle is relative to the screen coordinates. This method is only called + // if window rendering has been disabled. Return RV_CONTINUE if the rectangle + // was provided. + virtual RetVal HandleGetRect(CefRefPtr browser, bool screen, + CefRect& rect) + { + // Only called when rendering off-screen. + ASSERT(false); + return RV_CONTINUE; + } + + // Called on the UI thread retrieve the translation from view coordinates to + // actual screen coordinates. This method is only called if window rendering + // has been disabled. Return RV_CONTINUE if the screen coordinates were + // provided. + virtual RetVal HandleGetScreenPoint(CefRefPtr browser, + int viewX, int viewY, int& screenX, + int& screenY) + { + // Only called when rendering off-screen. + ASSERT(false); + return RV_CONTINUE; + } + + // Called on the UI thread when the browser wants to show, hide, resize or + // move the popup. If |show| is true and |rect| is zero size then the popup + // should be shown. If |show| is true and |rect| is non-zero size then |rect| + // represents the popup location in view coordinates. If |show| is false + // then the popup should be hidden. This method is only called if window + // rendering has been disabled. The return value is currently ignored. + virtual RetVal HandlePopupChange(CefRefPtr browser, bool show, + const CefRect& rect) + { + // Only called when rendering off-screen. + ASSERT(false); + return RV_CONTINUE; + } + + // Called when an element should be painted. |type| indicates whether the + // element is the view or the popup. |buffer| contains the pixel data for the + // whole image. |dirtyRect| indicates the portion of the image that has been + // repainted. On Windows |buffer| will be width*height*4 bytes in size and + // represents a BGRA image with an upper-left origin. This method is only + // called if window rendering has been disabled. The return value is currently + // ignored. + virtual RetVal HandlePaint(CefRefPtr browser, + PaintElementType type, const CefRect& dirtyRect, + const void* buffer) + { + // Only called when rendering off-screen. + ASSERT(false); + return RV_CONTINUE; + } + + // Called when the browser window's cursor has changed. This method is only + // called if window rendering has been disabled. The return value is currently + // ignored. + virtual RetVal HandleCursorChange(CefRefPtr browser, + CefCursorHandle cursor) + { + // Only called when rendering off-screen. + ASSERT(false); + return RV_CONTINUE; + } + // Retrieve the current navigation state flags - void GetNavState(bool &isLoading, bool &canGoBack, bool &canGoForward); void SetMainHwnd(CefWindowHandle hwnd); CefWindowHandle GetMainHwnd() { return m_MainHwnd; } void SetEditHwnd(CefWindowHandle hwnd); + void SetButtonHwnds(CefWindowHandle backHwnd, + CefWindowHandle forwardHwnd, + CefWindowHandle reloadHwnd, + CefWindowHandle stopHwnd); + CefRefPtr GetBrowser() { return m_Browser; } CefWindowHandle GetBrowserHwnd() { return m_BrowserHwnd; } @@ -393,6 +469,9 @@ public: void SendNotification(NotificationType type); protected: + virtual void SetLoading(bool isLoading); + virtual void SetNavState(bool canGoBack, bool canGoForward); + // The child browser window CefRefPtr m_Browser; @@ -405,12 +484,11 @@ protected: // The edit window handle CefWindowHandle m_EditHwnd; - // True if the page is currently loading - bool m_bLoading; - // True if the user can navigate backwards - bool m_bCanGoBack; - // True if the user can navigate forwards - bool m_bCanGoForward; + // The button window handles + CefWindowHandle m_BackHwnd; + CefWindowHandle m_ForwardHwnd; + CefWindowHandle m_StopHwnd; + CefWindowHandle m_ReloadHwnd; std::string m_LogFile; @@ -422,8 +500,6 @@ protected: DOMVisitorMap m_DOMVisitors; }; - -#ifdef TEST_REDIRECT_POPUP_URLS // Handler for popup windows that loads the request in an existing browser // window. class ClientPopupHandler : public ClientHandler @@ -455,8 +531,6 @@ public: protected: CefRefPtr m_ParentBrowser; }; -#endif // TEST_REDIRECT_POPUP_URLS - // Returns the main browser window instance. CefRefPtr AppGetBrowser(); diff --git a/tests/cefclient/cefclient.rc b/tests/cefclient/cefclient.rc index 86a8d289b..a9202f51f 100644 --- a/tests/cefclient/cefclient.rc +++ b/tests/cefclient/cefclient.rc @@ -30,6 +30,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US IDS_LOGO BINARY "res\\logo.png" IDS_UIPLUGIN BINARY "res\\uiplugin.html" +IDS_OSRPLUGIN BINARY "res\\osrplugin.html" IDS_LOGOBALL BINARY "res\\logoball.png" IDS_LOCALSTORAGE BINARY "res\\localstorage.html" IDS_XMLHTTPREQUEST BINARY "res\\xmlhttprequest.html" @@ -76,6 +77,7 @@ BEGIN MENUITEM "Request", ID_TESTS_REQUEST MENUITEM "Scheme Handler", ID_TESTS_SCHEME_HANDLER MENUITEM "UI App Example", ID_TESTS_UIAPP + MENUITEM "Off-Screen Rendering Example",ID_TESTS_OSRAPP MENUITEM "Local Storage", ID_TESTS_LOCALSTORAGE MENUITEM "XMLHttpRequest", ID_TESTS_XMLHTTPREQUEST MENUITEM "WebURLRequest", ID_TESTS_WEBURLREQUEST diff --git a/tests/cefclient/cefclient_mac.mm b/tests/cefclient/cefclient_mac.mm index 36835d993..7441ccc3f 100644 --- a/tests/cefclient/cefclient_mac.mm +++ b/tests/cefclient/cefclient_mac.mm @@ -592,6 +592,16 @@ void ClientHandler::SendNotification(NotificationType type) [delegate performSelectorOnMainThread:sel withObject:nil waitUntilDone:NO]; } +void ClientHandler::SetLoading(bool isLoading) +{ + // TODO(port): Change button status. +} + +void ClientHandler::SetNavState(bool canGoBack, bool canGoForward) +{ + // TODO(port): Change button status. +} + // Global functions diff --git a/tests/cefclient/cefclient_win.cpp b/tests/cefclient/cefclient_win.cpp index c140ae67f..d6477fb49 100644 --- a/tests/cefclient/cefclient_win.cpp +++ b/tests/cefclient/cefclient_win.cpp @@ -7,6 +7,7 @@ #include "cefclient.h" #include "binding_test.h" #include "extension_test.h" +#include "osrplugin_test.h" #include "plugin_test.h" #include "resource.h" #include "resource_util.h" @@ -91,13 +92,15 @@ int APIENTRY wWinMain(HINSTANCE hInstance, // Register the internal UI client plugin. InitUIPluginTest(); + // Register the internal OSR client plugin. + InitOSRPluginTest(); + // Register the V8 extension handler. InitExtensionTest(); // Register the scheme handler. InitSchemeTest(); - MSG msg; HACCEL hAccelTable; // Initialize global strings @@ -116,29 +119,34 @@ int APIENTRY wWinMain(HINSTANCE hInstance, // Register the find event message. uFindMsg = RegisterWindowMessage(FINDMSGSTRING); - // Main message loop - while (GetMessage(&msg, NULL, 0, 0)) - { -#ifdef TEST_SINGLE_THREADED_MESSAGE_LOOP - // Allow the CEF to do its message loop processing. - CefDoMessageLoopWork(); -#endif + int result = 0; +#ifdef TEST_SINGLE_THREADED_MESSAGE_LOOP + // Run the CEF message loop. This function will block until the application + // recieves a WM_QUIT message. + CefRunMessageLoop(); +#else + MSG msg; + + // Run the application message loop. + while (GetMessage(&msg, NULL, 0, 0)) { // Allow processing of find dialog messages. - if(hFindDlg && IsDialogMessage(hFindDlg, &msg)) + if (hFindDlg && IsDialogMessage(hFindDlg, &msg)) continue; - if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) - { + if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } - // Shut down the CEF + result = (int)msg.wParam; +#endif + + // Shut down CEF. CefShutdown(); - return (int) msg.wParam; + return result; } // @@ -355,6 +363,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) SetWindowLongPtr(editWnd, GWLP_WNDPROC, reinterpret_cast(WndProc)); g_handler->SetEditHwnd(editWnd); + g_handler->SetButtonHwnds(backWnd, forwardWnd, reloadWnd, stopWnd); rect.top += URLBAR_HEIGHT; @@ -367,32 +376,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) CefBrowser::CreateBrowser(info, false, static_cast >(g_handler), "http://www.google.com"); - - // Start the timer that will be used to update child window state. The - // timer is also necessary in single-threaded message loop mode so that - // CefDoMessageLoopWork() is called frequently enough for things like - // smooth JavaScript animation. - SetTimer(hWnd, 1, USER_TIMER_MINIMUM, NULL); } return 0; - case WM_TIMER: - if(g_handler.get() && g_handler->GetBrowserHwnd()) - { - // Retrieve the current navigation state - bool isLoading, canGoBack, canGoForward; - g_handler->GetNavState(isLoading, canGoBack, canGoForward); - - // Update the status of child windows - EnableWindow(editWnd, TRUE); - EnableWindow(backWnd, canGoBack); - EnableWindow(forwardWnd, canGoForward); - EnableWindow(reloadWnd, !isLoading); - EnableWindow(stopWnd, isLoading); - } - return 0; - - case WM_COMMAND: + case WM_COMMAND: { CefRefPtr browser; if(g_handler.get()) @@ -514,6 +501,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) if(browser.get()) RunUIPluginTest(browser); return 0; + case ID_TESTS_OSRAPP: // Test the OSR app + if(browser.get()) + RunOSRPluginTest(browser); + return 0; case ID_TESTS_DOMACCESS: // Test DOM access if(browser.get()) RunDOMAccessTest(browser); @@ -613,15 +604,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { // Dont erase the background if the browser window has been loaded // (this avoids flashing) - return 0; + return 0; } break; - case WM_DESTROY: + case WM_DESTROY: // The frame window has exited - KillTimer(hWnd, 1); - PostQuitMessage(0); - return 0; + PostQuitMessage(0); + return 0; } return DefWindowProc(hWnd, message, wParam, lParam); @@ -725,6 +715,10 @@ CefHandler::RetVal ClientHandler::HandleBeforeResourceLoad( // Show the uiapp contents resourceStream = GetBinaryResourceReader(IDS_UIPLUGIN); mimeType = "text/html"; + } else if(url == "http://tests/osrapp") { + // Show the osrapp contents + resourceStream = GetBinaryResourceReader(IDS_OSRPLUGIN); + mimeType = "text/html"; } else if(url == "http://tests/localstorage") { // Show the localstorage contents resourceStream = GetBinaryResourceReader(IDS_LOCALSTORAGE); @@ -765,6 +759,20 @@ void ClientHandler::SendNotification(NotificationType type) PostMessage(m_MainHwnd, WM_COMMAND, id, 0); } +void ClientHandler::SetLoading(bool isLoading) +{ + ASSERT(m_EditHwnd != NULL && m_ReloadHwnd != NULL && m_StopHwnd != NULL); + EnableWindow(m_EditHwnd, TRUE); + EnableWindow(m_ReloadHwnd, !isLoading); + EnableWindow(m_StopHwnd, isLoading); +} + +void ClientHandler::SetNavState(bool canGoBack, bool canGoForward) +{ + ASSERT(m_BackHwnd != NULL && m_ForwardHwnd != NULL); + EnableWindow(m_BackHwnd, canGoBack); + EnableWindow(m_ForwardHwnd, canGoForward); +} // Global functions diff --git a/tests/cefclient/clientplugin.cpp b/tests/cefclient/clientplugin.cpp index 44c8b6244..0713b2c26 100644 --- a/tests/cefclient/clientplugin.cpp +++ b/tests/cefclient/clientplugin.cpp @@ -135,31 +135,21 @@ void ClientPlugin::Shutdown() LRESULT ClientPlugin::OnPaint(UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { - static LPCWSTR text = L"Left click in the green area for a message box!"; - PAINTSTRUCT paint_struct; BeginPaint(&paint_struct); - - RECT client_rect; - GetClientRect(&client_rect); - - int old_mode = SetBkMode(paint_struct.hdc, TRANSPARENT); - COLORREF old_color = SetTextColor(paint_struct.hdc, RGB(0, 0, 255)); - - RECT text_rect = client_rect; - DrawText(paint_struct.hdc, text, -1, &text_rect, DT_CENTER | DT_CALCRECT); - - client_rect.top = ((client_rect.bottom - client_rect.top) - - (text_rect.bottom - text_rect.top)) / 2; - DrawText(paint_struct.hdc, text, -1, &client_rect, DT_CENTER); - - SetBkMode(paint_struct.hdc, old_mode); - SetTextColor(paint_struct.hdc, old_color); - + Paint(paint_struct.hdc); EndPaint(&paint_struct); return 0; } +// PrintClient is necessary to support off-screen rendering. +LRESULT ClientPlugin::OnPrintClient(UINT message, WPARAM wparam, LPARAM lparam, + BOOL& handled) +{ + Paint(reinterpret_cast(wparam)); + return 0; +} + LRESULT ClientPlugin::OnEraseBackGround(UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { @@ -187,4 +177,24 @@ void ClientPlugin::RefreshDisplay() { UpdateWindow(); } +void ClientPlugin::Paint(HDC hdc) { + static LPCWSTR text = L"Left click in the green area for a message box!"; + + RECT client_rect; + GetClientRect(&client_rect); + + int old_mode = SetBkMode(hdc, TRANSPARENT); + COLORREF old_color = SetTextColor(hdc, RGB(0, 0, 255)); + + RECT text_rect = client_rect; + DrawText(hdc, text, -1, &text_rect, DT_CENTER | DT_CALCRECT); + + client_rect.top = ((client_rect.bottom - client_rect.top) + - (text_rect.bottom - text_rect.top)) / 2; + DrawText(hdc, text, -1, &client_rect, DT_CENTER); + + SetBkMode(hdc, old_mode); + SetTextColor(hdc, old_color); +} + #endif // _WIN32 diff --git a/tests/cefclient/clientplugin.h b/tests/cefclient/clientplugin.h index b4e8d0959..71b95c59f 100644 --- a/tests/cefclient/clientplugin.h +++ b/tests/cefclient/clientplugin.h @@ -33,6 +33,7 @@ class ClientPlugin : public CWindowImpl { BEGIN_MSG_MAP(ClientPlugin) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackGround) MESSAGE_HANDLER(WM_PAINT, OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPrintClient) MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) END_MSG_MAP() @@ -74,6 +75,8 @@ class ClientPlugin : public CWindowImpl { protected: // Window message handlers. LRESULT OnPaint(UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled); + LRESULT OnPrintClient(UINT message, WPARAM wparam, LPARAM lparam, + BOOL& handled); LRESULT OnEraseBackGround(UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled); LRESULT OnLButtonDown(UINT message, WPARAM wparam, LPARAM lparam, @@ -83,6 +86,8 @@ class ClientPlugin : public CWindowImpl { // the plugin window. void RefreshDisplay(); + void Paint(HDC hdc); + private: // The plugins opaque instance handle NPP instance_; diff --git a/tests/cefclient/osrplugin.cpp b/tests/cefclient/osrplugin.cpp new file mode 100644 index 000000000..e3c6e42f4 --- /dev/null +++ b/tests/cefclient/osrplugin.cpp @@ -0,0 +1,706 @@ +// Copyright (c) 2011 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "osrplugin.h" +#include "cefclient.h" +#include "string_util.h" +#include +#include +#define _USE_MATH_DEFINES +#include +#include + +#ifdef _WIN32 + +// Initialized in NP_Initialize. +NPNetscapeFuncs* g_osrbrowser = NULL; + +namespace { + +GLuint g_textureID = -1; +float g_spinX = 0.0f; +float g_spinY = 0.0f; +int g_width = -1, g_height = -1; +CefRefPtr g_offscreenBrowser; + +// Class holding pointers for the client plugin window. +class ClientPlugin +{ +public: + ClientPlugin() + { + hWnd = NULL; + hDC = NULL; + hRC = NULL; + } + + HWND hWnd; + HDC hDC; + HGLRC hRC; +}; + +// Handler for off-screen rendering windows. +class ClientOSRHandler : public ClientHandler +{ +public: + ClientOSRHandler(ClientPlugin* plugin) + : plugin_(plugin), view_buffer_(NULL), view_buffer_size_(0), + popup_buffer_(NULL), popup_buffer_size_(0) + { + } + virtual ~ClientOSRHandler() + { + if (view_buffer_) + delete [] view_buffer_; + if (popup_buffer_) + delete [] popup_buffer_; + } + + virtual RetVal HandleBeforeCreated(CefRefPtr parentBrowser, + CefWindowInfo& createInfo, bool popup, + const CefPopupFeatures& popupFeatures, + CefRefPtr& handler, + CefString& url, + CefBrowserSettings& settings) + { + REQUIRE_UI_THREAD(); + + // Popups will be redirected to this browser window. + if(popup) { + createInfo.m_bWindowRenderingDisabled = TRUE; + handler = new ClientPopupHandler(g_offscreenBrowser); + } + + return RV_CONTINUE; + } + + virtual RetVal HandleAfterCreated(CefRefPtr browser) + { + REQUIRE_UI_THREAD(); + + // Set the view size to match the plugin window size. + browser->SetSize(PET_VIEW, g_width, g_height); + + g_offscreenBrowser = browser; + + return ClientHandler::HandleAfterCreated(browser); + } + + virtual RetVal HandleAddressChange(CefRefPtr browser, + CefRefPtr frame, + const CefString& url) + { + REQUIRE_UI_THREAD(); + + // Set the "url" value in the HTML. + std::stringstream ss; + std::string urlStr = url; + StringReplace(urlStr, "'", "\\'"); + ss << "document.getElementById('url').value = '" << urlStr.c_str() << "'"; + AppGetBrowser()->GetMainFrame()->ExecuteJavaScript(ss.str(), "", 0); + return RV_CONTINUE; + } + + virtual RetVal HandleTitleChange(CefRefPtr browser, + const CefString& title) + { + REQUIRE_UI_THREAD(); + + // Set the "title" value in the HTML. + std::stringstream ss; + std::string titleStr = title; + StringReplace(titleStr, "'", "\\'"); + ss << "document.getElementById('title').innerHTML = '" << + titleStr.c_str() << "'"; + AppGetBrowser()->GetMainFrame()->ExecuteJavaScript(ss.str(), "", 0); + return RV_CONTINUE; + } + + virtual RetVal HandleGetRect(CefRefPtr browser, bool screen, + CefRect& rect) + { + REQUIRE_UI_THREAD(); + + // The simulated screen and view rectangle are the same. This is necessary + // for popup menus to be located and sized inside the view. + rect.x = rect.y = 0; + rect.width = g_width; + rect.height = g_height; + return RV_CONTINUE; + } + + virtual RetVal HandleGetScreenPoint(CefRefPtr browser, + int viewX, int viewY, int& screenX, + int& screenY) + { + REQUIRE_UI_THREAD(); + + // Convert the point from view coordinates to actual screen coordinates. + POINT screen_pt = {viewX, viewY}; + MapWindowPoints(plugin_->hWnd, HWND_DESKTOP, &screen_pt, 1); + screenX = screen_pt.x; + screenY = screen_pt.y; + return RV_CONTINUE; + } + + virtual RetVal HandlePopupChange(CefRefPtr browser, bool show, + const CefRect& rect) + { + REQUIRE_UI_THREAD(); + + if (show && rect.width > 0) { + // Update the popup rectange. It will always be inside the view due to + // HandleGetRect(). + ASSERT(rect.x + rect.width < g_width && + rect.y + rect.height < g_height); + popup_rect_ = rect; + } else if(!show) { + // Clear the popup buffer. + popup_rect_.set(0,0,0,0); + if (popup_buffer_) { + delete [] popup_buffer_; + popup_buffer_ = NULL; + popup_buffer_size_ = 0; + } + } + return RV_CONTINUE; + } + + virtual RetVal HandlePaint(CefRefPtr browser, + PaintElementType type, const CefRect& dirtyRect, + const void* buffer) + { + REQUIRE_UI_THREAD(); + + wglMakeCurrent(plugin_->hDC, plugin_->hRC); + + glBindTexture(GL_TEXTURE_2D, g_textureID); + + if (type == PET_VIEW) { + // Paint the view. + SetRGB(buffer, g_width, g_height, true); + + // Update the whole texture. This is done for simplicity instead of + // updating just the dirty region. + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, g_width, g_height, GL_RGB, + GL_UNSIGNED_BYTE, view_buffer_); + } + + if(popup_rect_.width > 0) { + if (type == PET_POPUP) { + // Paint the popup. + SetRGB(buffer, popup_rect_.width, popup_rect_.height, false); + } + + if (popup_buffer_) { + // Update the popup region. + glTexSubImage2D(GL_TEXTURE_2D, 0, popup_rect_.x, + g_height-popup_rect_.y-popup_rect_.height, popup_rect_.width, + popup_rect_.height, GL_RGB, GL_UNSIGNED_BYTE, popup_buffer_); + } + } + + return RV_CONTINUE; + } + + virtual RetVal HandleCursorChange(CefRefPtr browser, + CefCursorHandle cursor) + { + REQUIRE_UI_THREAD(); + + // Change the plugin window's cursor. + SetClassLong(plugin_->hWnd, GCL_HCURSOR, + static_cast(reinterpret_cast(cursor))); + SetCursor(cursor); + return RV_CONTINUE; + } + +protected: + virtual void SetLoading(bool isLoading) + { + // Set the "stop" and "reload" button state in the HTML. + std::stringstream ss; + ss << "document.getElementById('stop').disabled = " + << (isLoading?"false":"true") << ";" + << "document.getElementById('reload').disabled = " + << (isLoading?"true":"false") << ";"; + AppGetBrowser()->GetMainFrame()->ExecuteJavaScript(ss.str(), "", 0); + } + + virtual void SetNavState(bool canGoBack, bool canGoForward) + { + // Set the "back" and "forward" button state in the HTML. + std::stringstream ss; + ss << "document.getElementById('back').disabled = " + << (canGoBack?"false":"true") << ";"; + ss << "document.getElementById('forward').disabled = " + << (canGoForward?"false":"true") << ";"; + AppGetBrowser()->GetMainFrame()->ExecuteJavaScript(ss.str(), "", 0); + } + + // Set the contents of the RGB buffer. + void SetRGB(const void* src, int width, int height, bool view) + { + SetBufferSize(width, height, view); + ConvertToRGB((unsigned char*)src, view?view_buffer_:popup_buffer_, width, + height); + } + + // Size the RGB buffer. + void SetBufferSize(int width, int height, bool view) + { + int dst_size = width * height * 3; + + // Allocate a new buffer if necesary. + if (view) { + if (dst_size > view_buffer_size_) { + if (view_buffer_) + delete [] view_buffer_; + view_buffer_ = new unsigned char[dst_size]; + view_buffer_size_ = dst_size; + } + } else { + if (dst_size > popup_buffer_size_) { + if (popup_buffer_) + delete [] popup_buffer_; + popup_buffer_ = new unsigned char[dst_size]; + popup_buffer_size_ = dst_size; + } + } + } + + // Convert from BGRA to RGB format and from upper-left to lower-left origin. + static void ConvertToRGB(const unsigned char* src, unsigned char* dst, + int width, int height) + { + int sp = 0, dp = (height-1) * width * 3; + for(int i = 0; i < height; i++) { + for(int j = 0; j < width; j++, dp += 3, sp += 4) { + dst[dp] = src[sp+2]; // R + dst[dp+1] = src[sp+1]; // G + dst[dp+2] = src[sp]; // B + } + dp -= width * 6; + } + } + +private: + ClientPlugin* plugin_; + unsigned char* view_buffer_; + int view_buffer_size_; + unsigned char* popup_buffer_; + int popup_buffer_size_; + CefRect popup_rect_; +}; + +// Forward declarations of functions included in this code module: +LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam, + LPARAM lParam); + +// Enable GL. +void EnableGL(HWND hWnd, HDC * hDC, HGLRC * hRC) +{ + PIXELFORMATDESCRIPTOR pfd; + int format; + + // Get the device context. + *hDC = GetDC(hWnd); + + // Set the pixel format for the DC. + ZeroMemory(&pfd, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 24; + pfd.cDepthBits = 16; + pfd.iLayerType = PFD_MAIN_PLANE; + format = ChoosePixelFormat(*hDC, &pfd); + SetPixelFormat(*hDC, format, &pfd); + + // Create and enable the render context. + *hRC = wglCreateContext(*hDC); + wglMakeCurrent(*hDC, *hRC); + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glEnable(GL_TEXTURE_2D); + + // Necessary for non-power-of-2 textures to render correctly. + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +} + +// Disable GL. +void DisableGL(HWND hWnd, HDC hDC, HGLRC hRC) +{ + // Delete the texture. + if(g_textureID != -1) + glDeleteTextures(1, &g_textureID); + + wglMakeCurrent(NULL, NULL); + wglDeleteContext(hRC); + ReleaseDC(hWnd, hDC); +} + +// Size the GL view. +void SizeGL(ClientPlugin* plugin, int width, int height) +{ + g_width = width; + g_height = height; + + wglMakeCurrent(plugin->hDC, plugin->hRC); + + // Match GL units to screen coordinates. + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, 0, width, height, 0.1, 100.0); + + // Delete the existing exture. + if(g_textureID != -1) + glDeleteTextures(1, &g_textureID); + + // Create a new texture. + glGenTextures(1, &g_textureID); + glBindTexture(GL_TEXTURE_2D, g_textureID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // Start with all white contents. + int size = width * height * 3; + unsigned char* buffer = new unsigned char[size]; + memset(buffer, 255, size); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, + GL_RGB, GL_UNSIGNED_BYTE, buffer); + + delete [] buffer; + + if(g_offscreenBrowser.get()) + g_offscreenBrowser->SetSize(PET_VIEW, width, height); +} + +// Render the view contents. +void RenderGL(ClientPlugin* plugin) +{ + wglMakeCurrent(plugin->hDC, plugin->hRC); + + struct { + float tu, tv; + float x, y, z; + } static vertices[] = { + {0.0f, 0.0f, -1.0f, -1.0f, 0.0f}, + {1.0f, 0.0f, 1.0f, -1.0f, 0.0f}, + {1.0f, 1.0f, 1.0f, 1.0f, 0.0f}, + {0.0f, 1.0f, -1.0f, 1.0f, 0.0f} + }; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + //glTranslatef(0.0f, 0.0f, -3.0f); + + // Rotate the view based on the mouse spin. + glRotatef(-g_spinX, 1.0f, 0.0f, 0.0f); + glRotatef(-g_spinY, 0.0f, 1.0f, 0.0f); + + // Enable alpha blending. + //glEnable(GL_BLEND); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // Draw the facets with the texture. + glBindTexture(GL_TEXTURE_2D, g_textureID); + glInterleavedArrays(GL_T2F_V3F, 0, vertices); + glDrawArrays(GL_QUADS, 0, 4); + + //glDisable(GL_BLEND); + + SwapBuffers(plugin->hDC); +} + +NPError NPP_NewImpl(NPMIMEType plugin_type, NPP instance, uint16 mode, + int16 argc, char* argn[], char* argv[], + NPSavedData* saved) { + if (instance == NULL) + return NPERR_INVALID_INSTANCE_ERROR; + + ClientPlugin *plugin = new ClientPlugin; + instance->pdata = reinterpret_cast(plugin); + + return NPERR_NO_ERROR; +} + +NPError NPP_DestroyImpl(NPP instance, NPSavedData** save) { + ClientPlugin *plugin = reinterpret_cast(instance->pdata); + + if (plugin) { + if(plugin->hWnd) { + DestroyWindow(plugin->hWnd); + DisableGL(plugin->hWnd, plugin->hDC, plugin->hRC); + } + delete plugin; + } + + return NPERR_NO_ERROR; +} + +NPError NPP_SetWindowImpl(NPP instance, NPWindow* window_info) { + if (instance == NULL) + return NPERR_INVALID_INSTANCE_ERROR; + + if (window_info == NULL) + return NPERR_GENERIC_ERROR; + + ClientPlugin *plugin = reinterpret_cast(instance->pdata); + HWND parent_hwnd = reinterpret_cast(window_info->window); + + if (plugin->hWnd == NULL) + { + WNDCLASS wc; + HINSTANCE hInstance = GetModuleHandle(NULL); + + // Register the window class. + wc.style = CS_OWNDC; + wc.lpfnWndProc = PluginWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = L"ClientOSRPlugin"; + RegisterClass(&wc); + + // Create the main window. + plugin->hWnd = CreateWindow(L"ClientOSRPlugin", L"Client OSR Plugin", + WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, 0, 0, 0, 0, parent_hwnd, NULL, + hInstance, NULL); + + SetWindowLongPtr(plugin->hWnd, GWLP_USERDATA, + reinterpret_cast(plugin)); + + // Enable GL drawing for the window. + EnableGL(plugin->hWnd, &(plugin->hDC), &(plugin->hRC)); + + // Create the off-screen rendering window. + CefWindowInfo windowInfo; + windowInfo.SetAsOffScreen(plugin->hWnd); + CefBrowser::CreateBrowser(windowInfo, false, + new ClientOSRHandler(plugin), "http://www.google.com"); + } + + // Position the plugin window and make sure it's visible. + RECT parent_rect; + GetClientRect(parent_hwnd, &parent_rect); + SetWindowPos(plugin->hWnd, NULL, parent_rect.left, parent_rect.top, + parent_rect.right - parent_rect.left, + parent_rect.bottom - parent_rect.top, SWP_SHOWWINDOW); + + UpdateWindow(plugin->hWnd); + ShowWindow(plugin->hWnd, SW_SHOW); + + return NPERR_NO_ERROR; +} + +// Plugin window procedure. +LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam, + LPARAM lParam) +{ + static POINT lastMousePos, curMousePos; + static bool mouseRotation = false; + static bool mouseTracking = false; + + ClientPlugin* plugin = + reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); + + switch(message) + { + case WM_CREATE: + // Start the timer that's used for redrawing. + SetTimer(hWnd, 1, USER_TIMER_MINIMUM, NULL); + return 0; + + case WM_DESTROY: + // Stop the timer that's used for redrawing. + KillTimer(hWnd, 1); + g_offscreenBrowser = NULL; + return 0; + + case WM_TIMER: + RenderGL(plugin); + break; + + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + SetCapture(hWnd); + SetFocus(hWnd); + if (wParam & MK_SHIFT) { + // Start rotation effect. + lastMousePos.x = curMousePos.x = LOWORD(lParam); + lastMousePos.y = curMousePos.y = HIWORD(lParam); + mouseRotation = true; + } else { + if (g_offscreenBrowser.get()) { + g_offscreenBrowser->SendMouseClickEvent(LOWORD(lParam), HIWORD(lParam), + (message==WM_LBUTTONDOWN?MBT_LEFT:MBT_RIGHT), false, 1); + } + } + break; + + case WM_LBUTTONUP: + case WM_RBUTTONUP: + if (GetCapture() == hWnd) + ReleaseCapture(); + if (mouseRotation) { + // End rotation effect. + mouseRotation = false; + g_spinX = 0; + g_spinY = 0; + } else { + if (g_offscreenBrowser.get()) { + g_offscreenBrowser->SendMouseClickEvent(LOWORD(lParam), HIWORD(lParam), + (message==WM_LBUTTONUP?MBT_LEFT:MBT_RIGHT), true, 1); + } + } + break; + + case WM_MOUSEMOVE: + if(mouseRotation) { + // Apply rotation effect. + curMousePos.x = LOWORD(lParam); + curMousePos.y = HIWORD(lParam); + g_spinX -= (curMousePos.x - lastMousePos.x); + g_spinY -= (curMousePos.y - lastMousePos.y); + lastMousePos.x = curMousePos.x; + lastMousePos.y = curMousePos.y; + } else { + if (!mouseTracking) { + // Start tracking mouse leave. Required for the WM_MOUSELEAVE event to + // be generated. + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(TRACKMOUSEEVENT); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = hWnd; + TrackMouseEvent(&tme); + mouseTracking = true; + } + if (g_offscreenBrowser.get()) { + g_offscreenBrowser->SendMouseMoveEvent(LOWORD(lParam), HIWORD(lParam), + false); + } + } + break; + + case WM_MOUSELEAVE: + if (mouseTracking) { + // Stop tracking mouse leave. + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(TRACKMOUSEEVENT); + tme.dwFlags = TME_LEAVE & TME_CANCEL; + tme.hwndTrack = hWnd; + TrackMouseEvent(&tme); + mouseTracking = false; + } + if (g_offscreenBrowser.get()) + g_offscreenBrowser->SendMouseMoveEvent(0, 0, true); + break; + + case WM_MOUSEWHEEL: + if (g_offscreenBrowser.get()) { + g_offscreenBrowser->SendMouseWheelEvent(LOWORD(lParam), HIWORD(lParam), + GET_WHEEL_DELTA_WPARAM(wParam)); + } + break; + + case WM_SIZE: { + int width = LOWORD(lParam); + int height = HIWORD(lParam); + if(width > 0 && height > 0) + SizeGL(plugin, width, height); + } break; + + case WM_SETFOCUS: + case WM_KILLFOCUS: + if (g_offscreenBrowser.get()) + g_offscreenBrowser->SendFocusEvent(message==WM_SETFOCUS); + break; + + case WM_CAPTURECHANGED: + case WM_CANCELMODE: + if(!mouseRotation) { + if (g_offscreenBrowser.get()) + g_offscreenBrowser->SendCaptureLostEvent(); + } + break; + + case WM_KEYDOWN: + case WM_KEYUP: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + case WM_CHAR: + case WM_SYSCHAR: + case WM_IME_CHAR: + if (g_offscreenBrowser.get()) { + CefBrowser::KeyType type = KT_CHAR; + bool sysChar = false, imeChar = false; + + if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN) + type = KT_KEYDOWN; + else if (message == WM_KEYUP || message == WM_SYSKEYUP) + type = KT_KEYUP; + + if (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP || + message == WM_SYSCHAR) + sysChar = true; + + if (message == WM_IME_CHAR) + imeChar = true; + + g_offscreenBrowser->SendKeyEvent(type, wParam, lParam, sysChar, imeChar); + } + break; + + case WM_PAINT: { + PAINTSTRUCT ps; + BeginPaint(hWnd, &ps); + EndPaint(hWnd, &ps); + } return 0; + + case WM_ERASEBKGND: + return 0; + } + + return DefWindowProc(hWnd, message, wParam, lParam); +} + +} // namespace + +NPError API_CALL NP_OSRGetEntryPoints(NPPluginFuncs* pFuncs) +{ + pFuncs->newp = NPP_NewImpl; + pFuncs->destroy = NPP_DestroyImpl; + pFuncs->setwindow = NPP_SetWindowImpl; + return NPERR_NO_ERROR; +} + +NPError API_CALL NP_OSRInitialize(NPNetscapeFuncs* pFuncs) +{ + g_osrbrowser = pFuncs; + return NPERR_NO_ERROR; +} + +NPError API_CALL NP_OSRShutdown(void) +{ + g_osrbrowser = NULL; + return NPERR_NO_ERROR; +} + +CefRefPtr GetOffScreenBrowser() +{ + return g_offscreenBrowser; +} + +#endif // _WIN32 diff --git a/tests/cefclient/osrplugin.h b/tests/cefclient/osrplugin.h new file mode 100644 index 000000000..9a6337d42 --- /dev/null +++ b/tests/cefclient/osrplugin.h @@ -0,0 +1,27 @@ +// Copyright (c) 2011 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Portions of this implementation are borrowed from webkit\default_plugin\ +// plugin_impl.h + +#ifndef _CEFCLIENT_OSRPLUGIN_H +#define _CEFCLIENT_OSRPLUGIN_H + +#include "include/cef.h" +#include "include/cef_nplugin.h" + +#ifdef _WIN32 + +extern NPNetscapeFuncs* g_osrbrowser; + +NPError API_CALL NP_OSRGetEntryPoints(NPPluginFuncs* pFuncs); +NPError API_CALL NP_OSRInitialize(NPNetscapeFuncs* pFuncs); +NPError API_CALL NP_OSRShutdown(void); + +CefRefPtr GetOffScreenBrowser(); + +#endif // _WIN32 + +#endif // _CEFCLIENT_OSRPLUGIN_H diff --git a/tests/cefclient/osrplugin_test.cpp b/tests/cefclient/osrplugin_test.cpp new file mode 100644 index 000000000..5df3d80ec --- /dev/null +++ b/tests/cefclient/osrplugin_test.cpp @@ -0,0 +1,123 @@ +// Copyright (c) 2011 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 "osrplugin_test.h" +#include "osrplugin.h" +#include "cefclient.h" +#include "plugin_test.h" + +void InitOSRPluginTest() +{ + // Structure providing information about the client plugin. + CefPluginInfo plugin_info; + CefString(&plugin_info.display_name).FromASCII("Client OSR Plugin"); + CefString(&plugin_info.unique_name).FromASCII("client_osr_plugin"); + CefString(&plugin_info.description).FromASCII("My Example Client OSR Plugin"); + CefString(&plugin_info.mime_type).FromASCII( + "application/x-client-osr-plugin"); + + plugin_info.np_getentrypoints = NP_OSRGetEntryPoints; + plugin_info.np_initialize = NP_OSRInitialize; + plugin_info.np_shutdown = NP_OSRShutdown; + + // Register the internal client plugin + CefRegisterPlugin(plugin_info); +} + +void RunOSRPluginTest(CefRefPtr browser) +{ + class Listener : public CefThreadSafeBase + { + public: + Listener() {} + virtual void HandleEvent(CefRefPtr event) + { + CefRefPtr browser = GetOffScreenBrowser(); + + CefRefPtr element = event->GetTarget(); + ASSERT(element.get()); + std::string elementId = element->GetElementAttribute("id"); + + if (elementId == "back") { + browser->GoBack(); + } else if(elementId == "forward") { + browser->GoForward(); + } else if(elementId == "stop") { + browser->Reload(); + } else if(elementId == "reload") { + browser->StopLoad(); + } else if (elementId == "go") { + // Retrieve the value of the "url" field and load it in the off-screen + // browser window. + CefRefPtr document = event->GetDocument(); + ASSERT(document.get()); + CefRefPtr url = document->GetElementById("url"); + ASSERT(url.get()); + CefString value = url->GetValue(); + if (!value.empty()) + browser->GetMainFrame()->LoadURL(value); + } else if(elementId == "testWindowedPlugin") { + // Run the windowed plugin test. + RunPluginTest(browser); + } else if(elementId == "testWindowlessPlugin") { + // Load flash, which is a windowless plugin. + browser->GetMainFrame()->LoadURL( + "http://www.adobe.com/software/flash/about/"); + } else if(elementId == "viewSource") { + // View the page source for the host browser window. + AppGetBrowser()->GetMainFrame()->ViewSource(); + } else { + // Not reached. + ASSERT(false); + } + } + }; + + class Visitor : public CefThreadSafeBase + { + public: + Visitor() {} + + void RegisterClickListener(CefRefPtr document, + CefRefPtr listener, + const std::string& elementId) + { + CefRefPtr element = document->GetElementById(elementId); + ASSERT(element.get()); + element->AddEventListener("click", listener, false); + } + + virtual void Visit(CefRefPtr document) + { + CefRefPtr listener(new Listener()); + + // Register click listeners for the various HTML elements. + RegisterClickListener(document, listener, "back"); + RegisterClickListener(document, listener, "forward"); + RegisterClickListener(document, listener, "stop"); + RegisterClickListener(document, listener, "reload"); + RegisterClickListener(document, listener, "go"); + RegisterClickListener(document, listener, "testWindowedPlugin"); + RegisterClickListener(document, listener, "testWindowlessPlugin"); + RegisterClickListener(document, listener, "viewSource"); + } + }; + + // Center the window on the screen. + int screenX = GetSystemMetrics(SM_CXFULLSCREEN); + int screenY = GetSystemMetrics(SM_CYFULLSCREEN); + int width = 1000, height = 760; + int x = (screenX - width) / 2; + int y = (screenY - height) / 2; + + SetWindowPos(AppGetMainHwnd(), NULL, x, y, width, height, + SWP_NOZORDER | SWP_SHOWWINDOW); + + // The DOM visitor will be called after the path is loaded. + CefRefPtr handler = browser->GetHandler(); + static_cast(handler.get())->AddDOMVisitor( + "http://tests/osrapp", new Visitor()); + + browser->GetMainFrame()->LoadURL("http://tests/osrapp"); +} diff --git a/tests/cefclient/osrplugin_test.h b/tests/cefclient/osrplugin_test.h new file mode 100644 index 000000000..25d289aca --- /dev/null +++ b/tests/cefclient/osrplugin_test.h @@ -0,0 +1,16 @@ +// Copyright (c) 2011 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 _CEFCLIENT_OSRPLUGIN_TEST_H +#define _CEFCLIENT_OSRPLUGIN_TEST_H + +#include "include/cef.h" + +// Register the internal client plugin and V8 extension. +void InitOSRPluginTest(); + +// Run the test. +void RunOSRPluginTest(CefRefPtr browser); + +#endif // _CEFCLIENT_OSRPLUGIN_TEST_H diff --git a/tests/cefclient/plugin_test.cpp b/tests/cefclient/plugin_test.cpp index 70af53514..560b5d225 100644 --- a/tests/cefclient/plugin_test.cpp +++ b/tests/cefclient/plugin_test.cpp @@ -24,10 +24,11 @@ void InitPluginTest() void RunPluginTest(CefRefPtr browser) { + // Add some extra space below the plugin to allow scrolling. std::string html = "Client Plugin:
" - "" + "" + "
 
" ""; browser->GetMainFrame()->LoadString(html, "about:blank"); } diff --git a/tests/cefclient/res/osrplugin.html b/tests/cefclient/res/osrplugin.html new file mode 100644 index 000000000..ed8f019ef --- /dev/null +++ b/tests/cefclient/res/osrplugin.html @@ -0,0 +1,51 @@ + + +Off-Screen Rendering App Example + + +
+ + + + +
+ + + + + + + + + + + + + + +
Off-Screen Rendering App Example
An embedded OpenGL plugin window that renders content from an off-screen browser window. + View Page Source
You can rotate the view! +
    +
  • Click and drag the view with the left mouse button while holding the shift key.
  • +
  • Enter a URL and click the "Go!" button to browse to a new Website.
  • +
  • Click here to test a windowed plugin. Windowed plugins must handle the WM_PRINTCLIENT message.
  • +
  • Click here to test a windowless plugin. Windowless plugins can be used without modification.
  • +
+
+ +
+   +
+ + + + + +
+
+ +
+
+
+ + diff --git a/tests/cefclient/resource.h b/tests/cefclient/resource.h index 1ca67825f..0c0f41ae4 100644 --- a/tests/cefclient/resource.h +++ b/tests/cefclient/resource.h @@ -50,6 +50,7 @@ #define ID_TESTS_WEBURLREQUEST 32790 #define ID_TESTS_DOMACCESS 32791 #define ID_TESTS_DRAGDROP 32792 +#define ID_TESTS_OSRAPP 32793 #define IDC_STATIC -1 #define IDS_LOGO 1000 #define IDS_UIPLUGIN 1001 @@ -57,6 +58,7 @@ #define IDS_LOCALSTORAGE 1003 #define IDS_XMLHTTPREQUEST 1004 #define IDS_DOMACCESS 1005 +#define IDS_OSRPLUGIN 1006 // Avoid files associated with MacOS #define _X86_ diff --git a/tests/cefclient/uiplugin.cpp b/tests/cefclient/uiplugin.cpp index 5845b63a4..5f6daefe6 100644 --- a/tests/cefclient/uiplugin.cpp +++ b/tests/cefclient/uiplugin.cpp @@ -13,6 +13,8 @@ // Initialized in NP_Initialize. NPNetscapeFuncs* g_uibrowser = NULL; +namespace { + // Global values. float g_rotationspeed = 0.0f; float g_theta = 0.0f; @@ -39,9 +41,9 @@ LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam, void EnableOpenGL(HWND hWnd, HDC * hDC, HGLRC * hRC); void DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC); -static -NPError NPP_New(NPMIMEType plugin_type, NPP instance, uint16 mode, int16 argc, - char* argn[], char* argv[], NPSavedData* saved) { +NPError NPP_NewImpl(NPMIMEType plugin_type, NPP instance, uint16 mode, + int16 argc, char* argn[], char* argv[], + NPSavedData* saved) { if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; @@ -51,8 +53,7 @@ NPError NPP_New(NPMIMEType plugin_type, NPP instance, uint16 mode, int16 argc, return NPERR_NO_ERROR; } -static -NPError NPP_Destroy(NPP instance, NPSavedData** save) { +NPError NPP_DestroyImpl(NPP instance, NPSavedData** save) { ClientPlugin *plugin = reinterpret_cast(instance->pdata); if (plugin) { @@ -68,8 +69,7 @@ NPError NPP_Destroy(NPP instance, NPSavedData** save) { return NPERR_NO_ERROR; } -static -NPError NPP_SetWindow(NPP instance, NPWindow* window_info) { +NPError NPP_SetWindowImpl(NPP instance, NPWindow* window_info) { if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; @@ -96,11 +96,14 @@ NPError NPP_SetWindow(NPP instance, NPWindow* window_info) { wc.lpszMenuName = NULL; wc.lpszClassName = L"ClientUIPlugin"; RegisterClass(&wc); - + // Create the main window. plugin->hWnd = CreateWindow(L"ClientUIPlugin", L"Client UI Plugin", WS_CHILD, 0, 0, 0, 0, parent_hwnd, NULL, hInstance, NULL); - + + SetWindowLongPtr(plugin->hWnd, GWLP_USERDATA, + reinterpret_cast(plugin)); + // Enable OpenGL drawing for the window. EnableOpenGL(plugin->hWnd, &(plugin->hDC), &(plugin->hRC)); } @@ -118,26 +121,6 @@ NPError NPP_SetWindow(NPP instance, NPWindow* window_info) { return NPERR_NO_ERROR; } -NPError API_CALL NP_UIGetEntryPoints(NPPluginFuncs* pFuncs) -{ - pFuncs->newp = NPP_New; - pFuncs->destroy = NPP_Destroy; - pFuncs->setwindow = NPP_SetWindow; - return NPERR_NO_ERROR; -} - -NPError API_CALL NP_UIInitialize(NPNetscapeFuncs* pFuncs) -{ - g_uibrowser = pFuncs; - return NPERR_NO_ERROR; -} - -NPError API_CALL NP_UIShutdown(void) -{ - g_uibrowser = NULL; - return NPERR_NO_ERROR; -} - // Send the notification to the browser as a JavaScript function call. static void NotifyNewRotation(float value) { @@ -147,18 +130,6 @@ static void NotifyNewRotation(float value) 0); } -void ModifyRotation(float value) -{ - g_rotationspeed += value; - NotifyNewRotation(g_rotationspeed); -} - -void ResetRotation() -{ - g_rotationspeed = 0.0; - NotifyNewRotation(g_rotationspeed); -} - // Nice little fly polygon borrowed from the OpenGL Red Book. const GLubyte fly[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -183,9 +154,9 @@ const GLubyte fly[] = { LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - HDC hDC; - int width, height; - + ClientPlugin* plugin = + reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); + switch(message) { case WM_CREATE: @@ -209,19 +180,23 @@ LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam, return 0; case WM_SIZE: - // Resize the OpenGL viewport to match the window size. - width = LOWORD(lParam); - height = HIWORD(lParam); - glViewport(0, 0, width, height); + if (plugin) { + // Resize the OpenGL viewport to match the window size. + int width = LOWORD(lParam); + int height = HIWORD(lParam); + + wglMakeCurrent(plugin->hDC, plugin->hRC); + glViewport(0, 0, width, height); + } break; case WM_ERASEBKGND: return 0; case WM_TIMER: + wglMakeCurrent(plugin->hDC, plugin->hRC); + // Adjust the theta value and redraw the display when the timer fires. - hDC = GetDC(hWnd); - glClearColor(1.0f, 1.0f, 1.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); @@ -240,8 +215,7 @@ LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam, glDisable(GL_POLYGON_STIPPLE); glPopMatrix(); - SwapBuffers(hDC); - ReleaseDC(hWnd, hDC); + SwapBuffers(plugin->hDC); g_theta -= g_rotationspeed; } @@ -272,7 +246,6 @@ void EnableOpenGL(HWND hWnd, HDC * hDC, HGLRC * hRC) // Create and enable the render contex. *hRC = wglCreateContext(*hDC); - wglMakeCurrent(*hDC, *hRC); } // Disable OpenGL. @@ -283,4 +256,38 @@ void DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC) ReleaseDC(hWnd, hDC); } +} // namespace + +NPError API_CALL NP_UIGetEntryPoints(NPPluginFuncs* pFuncs) +{ + pFuncs->newp = NPP_NewImpl; + pFuncs->destroy = NPP_DestroyImpl; + pFuncs->setwindow = NPP_SetWindowImpl; + return NPERR_NO_ERROR; +} + +NPError API_CALL NP_UIInitialize(NPNetscapeFuncs* pFuncs) +{ + g_uibrowser = pFuncs; + return NPERR_NO_ERROR; +} + +NPError API_CALL NP_UIShutdown(void) +{ + g_uibrowser = NULL; + return NPERR_NO_ERROR; +} + +void ModifyRotation(float value) +{ + g_rotationspeed += value; + NotifyNewRotation(g_rotationspeed); +} + +void ResetRotation() +{ + g_rotationspeed = 0.0; + NotifyNewRotation(g_rotationspeed); +} + #endif // _WIN32 diff --git a/tests/unittests/test_handler.h b/tests/unittests/test_handler.h index f08006497..4ad2206bb 100644 --- a/tests/unittests/test_handler.h +++ b/tests/unittests/test_handler.h @@ -65,6 +65,12 @@ public: return RV_CONTINUE; } + virtual RetVal HandleNavStateChange(CefRefPtr browser, + bool canGoBack, bool canGoForward) + { + return RV_CONTINUE; + } + virtual RetVal HandleTitleChange(CefRefPtr browser, const CefString& title) { @@ -284,6 +290,38 @@ public: return RV_CONTINUE; } + virtual RetVal HandleGetRect(CefRefPtr browser, bool screen, + CefRect& rect) + { + return RV_CONTINUE; + } + + virtual RetVal HandleGetScreenPoint(CefRefPtr browser, + int viewX, int viewY, int& screenX, + int& screenY) + { + return RV_CONTINUE; + } + + virtual RetVal HandlePopupChange(CefRefPtr browser, bool show, + const CefRect& rect) + { + return RV_CONTINUE; + } + + virtual RetVal HandlePaint(CefRefPtr browser, + PaintElementType type, const CefRect& dirtyRect, + const void* buffer) + { + return RV_CONTINUE; + } + + virtual RetVal HandleCursorChange(CefRefPtr browser, + CefCursorHandle cursor) + { + return RV_CONTINUE; + } + CefRefPtr GetBrowser() { return browser_; diff --git a/tools/cef_parser.py b/tools/cef_parser.py index 18f3a7e96..2b8f4df41 100644 --- a/tools/cef_parser.py +++ b/tools/cef_parser.py @@ -1065,6 +1065,7 @@ class obj_analysis: 'size_t' : 'size_t', 'time_t' : 'time_t', 'bool' : 'int', + 'CefCursorHandle' : 'cef_cursor_handle_t', 'CefWindowHandle' : 'cef_window_handle_t', 'CefRect' : 'cef_rect_t', 'CefThreadId' : 'cef_thread_id_t',