Skip to content

Commit

Permalink
Add RenderHandler.OnTextSelectionChanged and Browser.Invalidate (#403).
Browse files Browse the repository at this point in the history
Add tests for OnTextSelectionChanged.
Add on_load_end() helper func in unit tests.
  • Loading branch information
cztomczak committed Aug 18, 2018
1 parent 073f9d2 commit 1671a40
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 5 deletions.
17 changes: 17 additions & 0 deletions api/Browser.md
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,23 @@ machinery.
Returns true if a document has been loaded in the browser.


### Invalidate

| | |
| --- | --- |
| element_type | PaintElementType |
| __Return__ | void |

Description from upstream CEF:
> Invalidate the view. The browser will call CefRenderHandler::OnPaint
> asynchronously. This method is only used when window rendering is
> disabled.
`PaintElementType` enum values defined in cefpython module:
* PET_VIEW
* PET_POPUP


### IsFullscreen

| | |
Expand Down
19 changes: 19 additions & 0 deletions api/RenderHandler.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,25 @@ Called when the browser's cursor has changed. If |type| is CT_CUSTOM then
Called when the scroll offset has changed.


### OnTextSelectionChanged

| Parameter | Type |
| --- | --- |
| browser | [Browser](Browser.md) |
| selected_text | str |
| selected_range | list[x, y] |
| __Return__ | void |

Description from upstream CEF:
> Called when text selection has changed for the specified |browser|.
> |selected_text| is the currently selected text and |selected_range| is
> the character range.
NOTE: this callback seems to be called only when selecting text
with a mouse. When selecting text programmatically using javascript
code it doesn't get called.


### StartDragging

| Parameter | Type |
Expand Down
7 changes: 6 additions & 1 deletion src/browser.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,8 @@ cdef class PyBrowser:
"GetScreenRect",
"OnPopupShow", "OnPopupSize", "OnPaint", "OnCursorChange",
"OnScrollOffsetChanged",
"StartDragging", "UpdateDragCursor"]
"StartDragging", "UpdateDragCursor",
"OnTextSelectionChanged"]
# JavascriptDialogHandler
self.allowedClientCallbacks += ["OnJavascriptDialog",
"OnBeforeUnloadJavascriptDialog",
Expand Down Expand Up @@ -476,6 +477,10 @@ cdef class PyBrowser:
cpdef py_bool HasDocument(self):
return self.GetCefBrowser().get().HasDocument()

cpdef py_void Invalidate(self,
cef_types.cef_paint_element_type_t element_type):
return self.GetCefBrowserHost().get().Invalidate(element_type)

cpdef py_bool IsFullscreen(self):
return bool(self.isFullscreen)

Expand Down
5 changes: 3 additions & 2 deletions src/cef_v59..v66_changes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ NEW FEATURES
------------

+ unittests/osr_test.py - new test for off-screen rendering mode
+ cefpython.SetGlobalClientHandler
+ Browser.Invalidate

internal/cef_types.h
+ cef_log_severity_t: new key LOGSEVERITY_DEBUG (no need to expose,
Expand All @@ -85,10 +87,9 @@ internal/cef_types.h
cef_accessibility_handler.h
+ CefAccessibilityHandler
+ CefRenderHandler::GetAccessibilityHandler
+ cefpython.SetGlobalClientHandler

cef_render_handler.h
- OnTextSelectionChanged
+ OnTextSelectionChanged

cef_browser.h
+ SetAccessibilityState
Expand Down
8 changes: 8 additions & 0 deletions src/client_handler/render_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,11 @@ void RenderHandler::UpdateDragCursor(CefRefPtr<CefBrowser> browser,
REQUIRE_UI_THREAD();
RenderHandler_UpdateDragCursor(browser, operation);
}

void RenderHandler::OnTextSelectionChanged(CefRefPtr<CefBrowser> browser,
const CefString& selected_text,
const CefRange& selected_range) {
REQUIRE_UI_THREAD();
RenderHandler_OnTextSelectionChanged(browser, selected_text,
selected_range);
}
4 changes: 4 additions & 0 deletions src/client_handler/render_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ class RenderHandler : public CefRenderHandler,
void UpdateDragCursor(CefRefPtr<CefBrowser> browser,
cef_drag_operations_mask_t operation) override;

void OnTextSelectionChanged(CefRefPtr<CefBrowser> browser,
const CefString& selected_text,
const CefRange& selected_range) override;

private:
IMPLEMENT_REFCOUNTING(RenderHandler);
};
3 changes: 2 additions & 1 deletion src/extern/cef/cef_browser.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ from libcpp cimport bool as cpp_bool
from libcpp.vector cimport vector as cpp_vector
from cef_frame cimport CefFrame
cimport cef_types
from cef_types cimport int64, cef_state_t
from cef_types cimport int64, cef_state_t, PaintElementType
from cef_types cimport CefBrowserSettings, CefPoint
from cef_drag_data cimport CefDragData
from cef_types cimport CefMouseEvent
Expand Down Expand Up @@ -87,6 +87,7 @@ cdef extern from "include/cef_browser.h":
void AddWordToDictionary(const CefString& word)

void SetAccessibilityState(cef_state_t accessibility_state)
void Invalidate(cef_types.cef_paint_element_type_t type)


cdef cppclass CefBrowser:
Expand Down
4 changes: 4 additions & 0 deletions src/extern/cef/cef_types.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -377,3 +377,7 @@ cdef extern from "include/internal/cef_types.h":
ctypedef enum cef_focus_source_t:
FOCUS_SOURCE_NAVIGATION,
FOCUS_SOURCE_SYSTEM,

cdef cppclass CefRange:
int from_val "from"
int to_val "to"
19 changes: 19 additions & 0 deletions src/handlers/render_handler.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

include "../cefpython.pyx"
include "../browser.pyx"
include "../string_utils.pyx"

cimport cef_types
from cef_types cimport CefRange

# cef_paint_element_type_t, PaintElementType
PET_VIEW = cef_types.PET_VIEW
Expand Down Expand Up @@ -288,3 +290,20 @@ cdef public void RenderHandler_UpdateDragCursor(
(exc_type, exc_value, exc_trace) = sys.exc_info()
sys.excepthook(exc_type, exc_value, exc_trace)

cdef public void RenderHandler_OnTextSelectionChanged(
CefRefPtr[CefBrowser] cef_browser,
const CefString& selected_text,
const CefRange& selected_range
) except * with gil:
cdef PyBrowser browser
try:
browser = GetPyBrowser(cef_browser, "OnTextSelectionChanged")
callback = browser.GetClientCallback("OnTextSelectionChanged")
if callback:
callback(browser=browser,
selected_text=CefToPyString(selected_text),
selected_range=[selected_range.from_val,
selected_range.to_val])
except:
(exc_type, exc_value, exc_trace) = sys.exc_info()
sys.excepthook(exc_type, exc_value, exc_trace)
12 changes: 12 additions & 0 deletions unittests/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

g_subtests_ran = 0
g_js_code_completed = False
g_on_load_end_callbacks = []


def subtest_message(message):
Expand Down Expand Up @@ -51,6 +52,11 @@ def do_message_loop_work(work_loops):
time.sleep(0.01)


def on_load_end(callback, *args):
global g_on_load_end_callbacks
g_on_load_end_callbacks.append([callback, args])


def js_code_completed():
"""Sometimes window.onload can execute before javascript bindings
are ready if the document loads very fast. When setting javascript
Expand Down Expand Up @@ -154,6 +160,12 @@ def OnLoadEnd(self, browser, frame, http_code, **_):
frame.GetSource(self.frame_source_visitor)
browser.ExecuteJavascript("print('LoadHandler.OnLoadEnd() ok')")

subtest_message("Executing callbacks registered with on_load_end()")
global g_on_load_end_callbacks
for callback_data in g_on_load_end_callbacks:
callback_data[0](*callback_data[1])
del g_on_load_end_callbacks

def OnLoadingStateChange(self, browser, is_loading, can_go_back,
can_go_forward, **_):
if is_loading:
Expand Down
30 changes: 29 additions & 1 deletion unittests/osr_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
<!-- FrameSourceVisitor hash = 747ef3e6011b6a61e6b3c6e54bdd2dee -->
<h1>Off-screen rendering test</h1>
<div id="console"></div>
<div id="OnTextSelectionChanged">Test selection.</div>
</body>
</html>
"""
Expand Down Expand Up @@ -128,6 +129,9 @@ def test_osr(self):
browser.SendFocusEvent(True)
browser.WasResized()

# Test selection
on_load_end(select_h1_text, browser)

# Message loop
run_message_loop()

Expand Down Expand Up @@ -188,6 +192,17 @@ def _OnAccessibilityLocationChange(self, **_):
self._OnAccessibilityLocationChange_True = True


def select_h1_text(browser):
browser.SendMouseClickEvent(0, 0, cef.MOUSEBUTTON_LEFT,
mouseUp=False, clickCount=1)
browser.SendMouseMoveEvent(400, 20, mouseLeave=False,
modifiers=cef.EVENTFLAG_LEFT_MOUSE_BUTTON)
browser.SendMouseClickEvent(400, 20, cef.MOUSEBUTTON_LEFT,
mouseUp=True, clickCount=1)
browser.Invalidate(cef.PET_VIEW)
subtest_message("select_h1_text() ok")


class RenderHandler(object):
def __init__(self, test_case):
self.test_case = test_case
Expand All @@ -198,6 +213,7 @@ def __init__(self, test_case):

self.GetViewRect_True = False
self.OnPaint_True = False
self.OnTextSelectionChanged_True = False

def GetViewRect(self, rect_out, **_):
"""Called to retrieve the view rectangle which is relative
Expand All @@ -208,7 +224,7 @@ def GetViewRect(self, rect_out, **_):
rect_out.extend([0, 0, 800, 600])
return True

def OnPaint(self, element_type, paint_buffer, **_):
def OnPaint(self, browser, element_type, paint_buffer, **_):
"""Called when an element should be painted."""
if element_type == cef.PET_VIEW:
self.test_case.assertEqual(paint_buffer.width, 800)
Expand All @@ -219,6 +235,18 @@ def OnPaint(self, element_type, paint_buffer, **_):
else:
raise Exception("Unsupported element_type in OnPaint")

def OnTextSelectionChanged(self, selected_text, selected_range, **_):
if not self.OnTextSelectionChanged_True:
self.OnTextSelectionChanged_True = True
# First call
self.test_case.assertEqual(selected_text, "")
self.test_case.assertEqual(selected_range, [0, 0])
else:
# Second call.
# <h1> tag should be selected.
self.test_case.assertEqual(selected_text,
"Off-screen rendering test")


if __name__ == "__main__":
_test_runner.main(os.path.basename(__file__))

0 comments on commit 1671a40

Please sign in to comment.