Skip to content

Commit e5d5a89

Browse files
committed
Merged OSR (off-screen rendering) support in CEF Python 3, originally
created by Dominique Burnand. There were some fixes and enhancements made. This development effort was sponsored by Rentouch GmbH. Tested on Ubuntu 12.04 64-bit with Kivy 1.7.2 stable. The code should also work on Windows, but was not yet tested and may require some minor fixes.
1 parent 15f2ec2 commit e5d5a89

24 files changed

Lines changed: 1615 additions & 357 deletions

cefpython/AUTHORS.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ Contributors (in order of first commit):
1010
Rokas Stupuras <roxaz911@@gmail.com>
1111
Greg Kacy <grkacy@@gmail.com>
1212
Thomas Dähling <thomas@@ccpgames.com>
13+
Dominique Burnand <dominique.burnand@@rentouch.ch>

cefpython/browser.pyx

Lines changed: 97 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,17 @@ IF CEF_VERSION == 1:
77
KEYTYPE_KEYUP = cef_types.KT_KEYUP
88
KEYTYPE_KEYDOWN = cef_types.KT_KEYDOWN
99
KEYTYPE_CHAR = cef_types.KT_CHAR
10+
ELIF CEF_VERSION == 3:
11+
# cef_key_type_t, SendKeyEvent().
12+
KEYTYPE_KEYUP = cef_types.KEYEVENT_RAWKEYDOWN
13+
KEYTYPE_KEYDOWN = cef_types.KEYEVENT_KEYDOWN
14+
KEYTYPE_CHAR = cef_types.KEYEVENT_CHAR
1015

11-
# cef_mouse_button_type_t, SendMouseClickEvent().
12-
MOUSEBUTTON_LEFT = cef_types.MBT_LEFT
13-
MOUSEBUTTON_MIDDLE = cef_types.MBT_MIDDLE
14-
MOUSEBUTTON_RIGHT = cef_types.MBT_RIGHT
16+
# Both CEF 1 and CEF 3.
17+
# cef_mouse_button_type_t, SendMouseClickEvent().
18+
MOUSEBUTTON_LEFT = cef_types.MBT_LEFT
19+
MOUSEBUTTON_MIDDLE = cef_types.MBT_MIDDLE
20+
MOUSEBUTTON_RIGHT = cef_types.MBT_RIGHT
1521

1622
# If you try to keep PyBrowser() objects inside cpp_vector you will
1723
# get segmentation faults, as they will be garbage collected.
@@ -192,23 +198,28 @@ cdef class PyBrowser:
192198
cpdef py_void SetClientCallback_CEF3(self,
193199
py_string name, object callback):
194200
if not self.allowedClientCallbacks:
195-
# CefDisplayHandler
201+
# DisplayHandler
196202
self.allowedClientCallbacks += ["OnLoadingStateChange",
197203
"OnAddressChange", "OnTitleChange", "OnTooltip",
198204
"OnStatusMessage", "OnConsoleMessage"]
199-
# CefKeyboardHandler
205+
# KeyboardHandler
200206
self.allowedClientCallbacks += ["OnPreKeyEvent", "OnKeyEvent"];
201-
# CefRequestHandler
207+
# RequestHandler
202208
# Note: "OnCertificateError" and "OnBeforePluginLoad" must be
203209
# set using cefpython.SetGlobalClientCallback()
204210
self.allowedClientCallbacks += ["OnBeforeResourceLoad",
205211
"OnResourceRedirect", "GetAuthCredentials",
206212
"OnQuotaRequest", "GetCookieManager",
207213
"OnProtocolExecution"]
208-
# CefLoadHandler
214+
# LoadHandler
209215
self.allowedClientCallbacks += ["OnLoadStart", "OnLoadEnd",
210216
"OnLoadError", "OnRendererProcessTerminated",
211217
"OnPluginCrashed"]
218+
# RenderHandler
219+
self.allowedClientCallbacks += ["GetRootScreenRect",
220+
"GetViewRect", "GetScreenPoint", "GetScreenInfo",
221+
"OnPopupShow", "OnPopupSize", "OnPaint", "OnCursorChange",
222+
"OnScrollOffsetChanged"]
212223
if name not in self.allowedClientCallbacks:
213224
raise Exception("Browser.SetClientCallback() failed: unknown "
214225
"callback: %s" % name)
@@ -560,7 +571,6 @@ cdef class PyBrowser:
560571
self.GetCefBrowser().get().Invalidate(cefRect)
561572

562573
IF CEF_VERSION == 1 and UNAME_SYSNAME == "Windows":
563-
564574
cpdef PaintBuffer GetImage(self, PaintElementType paintElementType,
565575
int width, int height):
566576
assert IsThread(TID_UI), (
@@ -587,9 +597,7 @@ cdef class PyBrowser:
587597
return None
588598

589599
# Sending mouse/key events.
590-
591600
IF CEF_VERSION == 1:
592-
593601
cpdef py_void SendKeyEvent(self, cef_types.cef_key_type_t keyType,
594602
tuple keyInfo, int modifiers):
595603
cdef CefKeyInfo cefKeyInfo
@@ -631,6 +639,84 @@ cdef class PyBrowser:
631639

632640
cpdef py_void SendCaptureLostEvent(self):
633641
self.GetCefBrowser().get().SendCaptureLostEvent()
642+
643+
ELIF CEF_VERSION == 3:
644+
cpdef py_void SendKeyEvent(self, dict pyEvent):
645+
cdef CefKeyEvent cefEvent
646+
if "type" in pyEvent:
647+
cefEvent.type = int(pyEvent["type"])
648+
if "modifiers" in pyEvent:
649+
cefEvent.modifiers = long(pyEvent["modifiers"])
650+
if ("windows_key_code" in pyEvent) and UNAME_SYSNAME == "Windows":
651+
cefEvent.windows_key_code = int(pyEvent["windows_key_code"])
652+
if "native_key_code" in pyEvent:
653+
cefEvent.native_key_code = int(pyEvent["native_key_code"])
654+
if "is_system_key" in pyEvent:
655+
cefEvent.is_system_key = bool(pyEvent["is_system_key"])
656+
if "character" in pyEvent:
657+
cefEvent.character = int(pyEvent["character"])
658+
if "unmodified_character" in pyEvent:
659+
cefEvent.unmodified_character = \
660+
int(pyEvent["unmodified_character"])
661+
if "focus_on_editable_field" in pyEvent:
662+
cefEvent.focus_on_editable_field = \
663+
bool(pyEvent["focus_on_editable_field"])
664+
self.GetCefBrowserHost().get().SendKeyEvent(cefEvent)
665+
666+
cpdef py_void SendMouseClickEvent(self, x, y,
667+
cef_types.cef_mouse_button_type_t mouseButtonType,
668+
py_bool mouseUp, int clickCount):
669+
cdef CefMouseEvent mouseEvent
670+
mouseEvent.x = x
671+
mouseEvent.y = y
672+
"""
673+
TODO: allow to pass modifiers which represents
674+
bit flags describing any pressed modifier keys.
675+
See cef_event_flags_t for values.
676+
enum cef_event_flags_t {
677+
EVENTFLAG_NONE = 0,
678+
EVENTFLAG_CAPS_LOCK_ON = 1 << 0,
679+
EVENTFLAG_SHIFT_DOWN = 1 << 1,
680+
EVENTFLAG_CONTROL_DOWN = 1 << 2,
681+
EVENTFLAG_ALT_DOWN = 1 << 3,
682+
EVENTFLAG_LEFT_MOUSE_BUTTON = 1 << 4,
683+
EVENTFLAG_MIDDLE_MOUSE_BUTTON = 1 << 5,
684+
EVENTFLAG_RIGHT_MOUSE_BUTTON = 1 << 6,
685+
// Mac OS-X command key.
686+
EVENTFLAG_COMMAND_DOWN = 1 << 7,
687+
EVENTFLAG_NUM_LOCK_ON = 1 << 8,
688+
EVENTFLAG_IS_KEY_PAD = 1 << 9,
689+
EVENTFLAG_IS_LEFT = 1 << 10,
690+
EVENTFLAG_IS_RIGHT = 1 << 11,
691+
"""
692+
mouseEvent.modifiers = 0
693+
self.GetCefBrowserHost().get().SendMouseClickEvent(mouseEvent,
694+
mouseButtonType, bool(mouseUp), clickCount)
695+
696+
cpdef py_void SendMouseMoveEvent(self, int x, int y,
697+
py_bool mouseLeave):
698+
cdef CefMouseEvent mouseEvent
699+
mouseEvent.x = x
700+
mouseEvent.y = y
701+
mouseEvent.modifiers = 0
702+
self.GetCefBrowserHost().get().SendMouseMoveEvent(mouseEvent,
703+
bool(mouseLeave))
704+
705+
cpdef py_void SendMouseWheelEvent(self, int x, int y,
706+
int deltaX, int deltaY):
707+
cdef CefMouseEvent mouseEvent
708+
mouseEvent.x = x
709+
mouseEvent.y = y
710+
mouseEvent.modifiers = 0
711+
self.GetCefBrowserHost().get().SendMouseWheelEvent(mouseEvent,
712+
deltaX, deltaY)
713+
714+
cpdef py_void SendFocusEvent(self, py_bool setFocus):
715+
self.GetCefBrowserHost().get().SendFocusEvent(bool(setFocus))
716+
717+
cpdef py_void SendCaptureLostEvent(self):
718+
self.GetCefBrowserHost().get().SendCaptureLostEvent()
719+
# ENDIF CEF_VERSION == 3 / Sending mouse/key events.
634720

635721
IF CEF_VERSION == 3:
636722
cpdef py_void StartDownload(self, py_string url):

cefpython/cef3/client_handler/client_handler.cpp

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,3 +575,123 @@ void ClientHandler::OnPluginCrashed(CefRefPtr<CefBrowser> browser,
575575
REQUIRE_UI_THREAD();
576576
LoadHandler_OnPluginCrashed(browser, plugin_path);
577577
}
578+
579+
// ----------------------------------------------------------------------------
580+
// CefRenderHandler
581+
// ----------------------------------------------------------------------------
582+
583+
///
584+
// Implement this interface to handle events when window rendering is disabled.
585+
// The methods of this class will be called on the UI thread.
586+
///
587+
588+
///
589+
// Called to retrieve the root window rectangle in screen coordinates. Return
590+
// true if the rectangle was provided.
591+
///
592+
/*--cef()--*/
593+
bool ClientHandler::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
594+
CefRect& rect) {
595+
REQUIRE_UI_THREAD();
596+
return RenderHandler_GetRootScreenRect(browser, rect);
597+
}
598+
599+
///
600+
// Called to retrieve the view rectangle which is relative to screen
601+
// coordinates. Return true if the rectangle was provided.
602+
///
603+
/*--cef()--*/
604+
bool ClientHandler::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) {
605+
REQUIRE_UI_THREAD();
606+
return RenderHandler_GetViewRect(browser, rect);
607+
}
608+
609+
///
610+
// Called to retrieve the translation from view coordinates to actual screen
611+
// coordinates. Return true if the screen coordinates were provided.
612+
///
613+
/*--cef()--*/
614+
bool ClientHandler::GetScreenPoint(CefRefPtr<CefBrowser> browser,
615+
int viewX,
616+
int viewY,
617+
int& screenX,
618+
int& screenY) {
619+
REQUIRE_UI_THREAD();
620+
return RenderHandler_GetScreenPoint(browser, viewX, viewY, screenX,
621+
screenY);
622+
}
623+
624+
///
625+
// Called to allow the client to fill in the CefScreenInfo object with
626+
// appropriate values. Return true if the |screen_info| structure has been
627+
// modified.
628+
//
629+
// If the screen info rectangle is left empty the rectangle from GetViewRect
630+
// will be used. If the rectangle is still empty or invalid popups may not be
631+
// drawn correctly.
632+
///
633+
/*--cef()--*/
634+
bool ClientHandler::GetScreenInfo(CefRefPtr<CefBrowser> browser,
635+
CefScreenInfo& screen_info) {
636+
REQUIRE_UI_THREAD();
637+
return RenderHandler_GetScreenInfo(browser, screen_info);
638+
}
639+
640+
///
641+
// Called when the browser wants to show or hide the popup widget. The popup
642+
// should be shown if |show| is true and hidden if |show| is false.
643+
///
644+
/*--cef()--*/
645+
void ClientHandler::OnPopupShow(CefRefPtr<CefBrowser> browser,
646+
bool show) {
647+
REQUIRE_UI_THREAD();
648+
RenderHandler_OnPopupShow(browser, show);
649+
}
650+
651+
///
652+
// Called when the browser wants to move or resize the popup widget. |rect|
653+
// contains the new location and size.
654+
///
655+
/*--cef()--*/
656+
void ClientHandler::OnPopupSize(CefRefPtr<CefBrowser> browser,
657+
const CefRect& rect) {
658+
REQUIRE_UI_THREAD();
659+
RenderHandler_OnPopupSize(browser, rect);
660+
}
661+
662+
///
663+
// Called when an element should be painted. |type| indicates whether the
664+
// element is the view or the popup widget. |buffer| contains the pixel data
665+
// for the whole image. |dirtyRects| contains the set of rectangles that need
666+
// to be repainted. On Windows |buffer| will be |width|*|height|*4 bytes
667+
// in size and represents a BGRA image with an upper-left origin.
668+
///
669+
/*--cef()--*/
670+
void ClientHandler::OnPaint(CefRefPtr<CefBrowser> browser,
671+
PaintElementType type,
672+
const RectList& dirtyRects,
673+
const void* buffer,
674+
int width, int height) {
675+
REQUIRE_UI_THREAD();
676+
RenderHandler_OnPaint(browser, type, const_cast<RectList&>(dirtyRects), \
677+
buffer, width, height);
678+
};
679+
680+
///
681+
// Called when the browser window's cursor has changed.
682+
///
683+
/*--cef()--*/
684+
void ClientHandler::OnCursorChange(CefRefPtr<CefBrowser> browser,
685+
CefCursorHandle cursor) {
686+
REQUIRE_UI_THREAD();
687+
RenderHandler_OnCursorChange(browser, cursor);
688+
}
689+
690+
///
691+
// Called when the scroll offset has changed.
692+
///
693+
/*--cef()--*/
694+
void ClientHandler::OnScrollOffsetChanged(CefRefPtr<CefBrowser> browser) {
695+
REQUIRE_UI_THREAD();
696+
RenderHandler_OnScrollOffsetChanged(browser);
697+
}

0 commit comments

Comments
 (0)