remote/handlers/RemoteRenderHandler.cpp (311 lines of code) (raw):

#include "RemoteRenderHandler.h" #include "RemoteClientHandler.h" #include "../CefUtils.h" #include "../Utils.h" #include "../browser/RemoteBrowser.h" #include "../log/Log.h" using namespace boost::interprocess; // TODO: Optimize RemoteRenderHandler. // Need to perform all calculations on server. Client should regularly update data on server. const bool doTrace = getBoolEnv("CEF_SERVER_TRACE_RemoteRenderHandler"); RemoteRenderHandler::RemoteRenderHandler(std::shared_ptr<RpcExecutor> service): myService(service) {} bool RemoteRenderHandler::GetRootScreenRect(CefRefPtr<CefBrowser> browser, CefRect& rect) { GetViewRect(browser, rect); return rect.width > 1; } void fillDummy(CefRect& rect) { rect.x = 0; rect.y = 0; rect.width = 300; rect.height = 200; } void RemoteRenderHandler::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) { fillDummy(rect); thrift_codegen::Rect result; result.w = -1; // invalidate FIND_BID_OR_RETURN(); myService->exec([&](const JavaService& s){ s->RenderHandler_GetViewRect(result, bid); }); if (result.w < 0) { if (doTrace) Log::trace("RemoteRenderHandler::GetViewRect: bid=%d, result.w = %d", bid, result.w); return; } rect.x = result.x; rect.y = result.y; rect.width = result.w; rect.height = result.h; if (rect.width < 1 || rect.height < 1) { Log::trace("RemoteRenderHandler::GetViewRect: bid=%d, small size %d %d", bid, rect.width, rect.height); fillDummy(rect); } if (doTrace) Log::trace("RemoteRenderHandler::GetViewRect: bid=%d, result: %d %d %d %d", bid, rect.x, rect.y, rect.width, rect.height); } void fillDummy(CefScreenInfo& screen_info) { screen_info.device_scale_factor = 2; screen_info.depth = 1; screen_info.depth_per_component = 1; screen_info.is_monochrome = false; screen_info.rect.x = 0; screen_info.rect.y = 0; screen_info.rect.width = 500; screen_info.rect.height = 700; screen_info.available_rect.x = 0; screen_info.available_rect.y = 0; screen_info.available_rect.width = 500; screen_info.available_rect.height = 700; } /// // Called to allow the client to fill in the CefScreenInfo object with // appropriate values. Return true if the |screen_info| structure has been // modified. // // If the screen info rectangle is left empty the rectangle from GetViewRect // will be used. If the rectangle is still empty or invalid popups may not be // drawn correctly. /// /*--cef()--*/ bool RemoteRenderHandler::GetScreenInfo(CefRefPtr<CefBrowser> browser, CefScreenInfo& screen_info) { fillDummy(screen_info); thrift_codegen::ScreenInfo result; result.depth = -1;// invalidate FIND_BID_OR_RETURN_VAL(false); myService->exec([&](const JavaService& s){ s->RenderHandler_GetScreenInfo(result, bid); }); if (result.depth == -1) { if (doTrace) Log::trace("RemoteRenderHandler::GetScreenInfo: bid=%d, result.depth == -1", bid); return false; } screen_info.device_scale_factor = static_cast<float>(result.device_scale_factor); screen_info.depth = result.depth; screen_info.depth_per_component = result.depth_per_component; screen_info.is_monochrome = result.is_monochrome; screen_info.rect.x = result.rect.x; screen_info.rect.y = result.rect.y; screen_info.rect.width = result.rect.w; screen_info.rect.height = result.rect.h; screen_info.available_rect.x = result.available_rect.x; screen_info.available_rect.y = result.available_rect.y; screen_info.available_rect.width = result.available_rect.w; screen_info.available_rect.height = result.available_rect.h; if (doTrace) Log::trace("RemoteRenderHandler::GetScreenInfo: bid=%d, result: rc %d %d %d %d, avail %d %d %d %d", bid, result.rect.x, result.rect.y, result.rect.w, result.rect.h, result.available_rect.x, result.available_rect.y, result.available_rect.w, result.available_rect.w); return true; } bool RemoteRenderHandler::GetScreenPoint(CefRefPtr<CefBrowser> browser, int viewX, int viewY, int& screenX, int& screenY) { thrift_codegen::Point result; result.x = INT32_MIN;// invalidate FIND_BID_OR_RETURN_VAL(false); myService->exec([&](const JavaService& s){ s->RenderHandler_GetScreenPoint(result, bid, viewX, viewY); }); if (result.x == INT32_MIN) { if (doTrace) Log::trace("RemoteRenderHandler::GetScreenPoint: bid=%d, result.x == INT32_MIN", bid); return false; } screenX = result.x; screenY = result.y; if (doTrace) Log::trace("RemoteRenderHandler::GetScreenPoint: bid=%d, result: %d %d", result.x, result.y, bid); return true; } void RemoteRenderHandler::OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) { FIND_BID_OR_RETURN(); if (doTrace) Log::trace("RemoteRenderHandler::OnPopupShow: bid=%d, show=%d", bid, show ? 1 : 0); myService->exec([&](const JavaService& s){ s->RenderHandler_OnPopupShow(bid, show); }); } void RemoteRenderHandler::OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) { FIND_BID_OR_RETURN(); if (doTrace) Log::trace("RemoteRenderHandler::OnPopupSize: bid=%d, x=%d y=%d w=%d h=%d)", bid, rect.x, rect.y, rect.width, rect.height); myService->exec([&](const JavaService& s) { thrift_codegen::Rect size; size.x = rect.x; size.y = rect.y; size.w = rect.width; size.h = rect.height; s->RenderHandler_OnPopupSize(bid, size); }); } // // Debug methods // inline void fillRect(unsigned char * dst, int stride, int y, int x, int dx, int dy, int r, int g, int b, int a, int width, int height) { if (y >= height) return; if (x >= width) return; if (y < 0) { dy += y; y = 0; } if (y + dy >= height) dy = height - y; if (x < 0) { dx += x; x = 0; } if (x + dx >= width) dx = width - x; for (int yy = y, yEnd = y + dy; yy < yEnd; ++yy) { const int offset = yy*stride; for (int xx = x, xEnd = x + dx; xx < xEnd; ++xx) { dst[offset + xx*4] = a; // alpha dst[offset + xx*4 + 1] = r; // red dst[offset + xx*4 + 2] = g; // green dst[offset + xx*4 + 3] = b; // blue } } } inline void drawLineX(unsigned char * dst, int stride, int y, int x, int dx, int r, int g, int b, int a, int width, int height) { if (y < 0) return; if (y >= height) return; if (x >= width) return; if (x < 0) { dx += x; x = 0; } if (x + dx >= width) dx = width - x; const int offset = y*stride; for (int xx = x, xEnd = x + dx; xx < xEnd; ++xx) { dst[offset + xx*4] = a; // alpha dst[offset + xx*4 + 1] = r; // red dst[offset + xx*4 + 2] = g; // green dst[offset + xx*4 + 3] = b; // blue } } inline void drawLineY(unsigned char * dst, int stride, int y, int x, int dy, int r, int g, int b, int a, int width, int height) { if (x < 0) return; if (y >= height) return; if (x >= width) return; if (y < 0) { dy += y; y = 0; } if (y + dy >= height) dy = height - y; for (int yy = y, yEnd = y + dy; yy < yEnd; ++yy) { const int offset = yy*stride; dst[offset + x*4] = a; // alpha dst[offset + x*4 + 1] = r; // red dst[offset + x*4 + 2] = g; // green dst[offset + x*4 + 3] = b; // blue } } inline void drawRect(unsigned char * dst, int stride, int y, int x, int width, int height, int r, int g, int b, int a, int totalWidth, int totalHeight) { const int thickness = 50; fillRect(dst, stride, y - thickness/2, x, width, thickness, r, g, b, a, totalWidth, totalHeight); fillRect(dst, stride, y, x + width - thickness/2, thickness, height, r, g, b, a, totalWidth, totalHeight); fillRect(dst, stride, y + height - thickness/2, x, width, thickness, r, g, b, a, totalWidth, totalHeight); fillRect(dst, stride, y, x - thickness/2, thickness, height, r, g, b, a, totalWidth, totalHeight); } inline void semifillRect(unsigned char * dst, int stride, int y, int x, int width, int height, int r, int g, int b, int a, int totalWidth, int totalHeight) { for (int xEnd = x + width; x < xEnd; x += 2) drawLineY(dst, stride, y, x, height, r, g, b, a, totalWidth, totalHeight); } void RemoteRenderHandler::OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList& dirtyRects, const void* buffer, int width, int height) { FIND_BID_OR_RETURN(); if (doTrace) Log::trace("RemoteRenderHandler::OnPaint: bid=%d, width=%d height=%d, dirty rects count %d", bid, width, height, dirtyRects.size()); const int rasterPixCount = width * height; const size_t extendedRectsCount = dirtyRects.size() < 10 ? 10 : dirtyRects.size(); SharedBufferManager& bufferManager = type == PET_POPUP ? rb->popup() : rb->page(); SharedBuffer* buff = bufferManager.getLockedBuffer( rasterPixCount * 4 + 4 * 4 * extendedRectsCount); if (buff == nullptr) return; // NOTE: error was logged in getLockedBuffer() if (buff->ptr() == nullptr) { Log::error("SharedBuffer is empty."); return; } ::memcpy((char*)buff->ptr(), (char*)buffer, rasterPixCount*4); int32_t * sharedRects = (int32_t *)buff->ptr() + rasterPixCount; for (const CefRect& r : dirtyRects) { *(sharedRects++) = r.x; *(sharedRects++) = r.y; *(sharedRects++) = r.width; *(sharedRects++) = r.height; } { // Draw debug static int drawDebug = -1; if (drawDebug < 0) drawDebug = getBoolEnv("CEF_SERVER_DRAW_DEBUG") ? 1 : 0; if (drawDebug > 0) { const int stride = width*4; const int th = 30; fillRect((unsigned char *)buff->ptr(), stride, 0, 0, th, th, 255, 0, 0, 255, width, height); fillRect((unsigned char *)buff->ptr(), stride, 0, width - th, th, th, 0, 255, 0, 255, width, height); fillRect((unsigned char *)buff->ptr(), stride, height - th, width - th, th, th, 0, 0, 255, 255, width, height); fillRect((unsigned char *)buff->ptr(), stride, height - th, 0, th, th, 255, 0, 255, 255, width, height); } } buff->unlock(); myService->exec([&](const JavaService& s){ s->RenderHandler_OnPaint(bid, type != PET_VIEW, static_cast<int>(dirtyRects.size()), buff->uid(), buff->handle(), width, height); }); } bool RemoteRenderHandler::StartDragging(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDragData> drag_data, DragOperationsMask allowed_ops, int x, int y) { Log::error("Unimplemented."); return false; } void RemoteRenderHandler::UpdateDragCursor(CefRefPtr<CefBrowser> browser, DragOperation operation) { Log::error("Unimplemented."); } void RemoteRenderHandler::OnImeCompositionRangeChanged( CefRefPtr<CefBrowser> browser, const CefRange& cef_selected_range, const RectList& cef_character_bounds) { FIND_BID_OR_RETURN(); if (doTrace) Log::trace("RemoteRenderHandler::OnImeCompositionRangeChanged: bid=%d, cef_character_bounds.size=%d", bid, cef_character_bounds.size()); myService->exec([&](const JavaService& s) { thrift_codegen::Range selected_range; selected_range.from = cef_selected_range.from; selected_range.to = cef_selected_range.to; std::vector<thrift_codegen::Rect> character_bounds; for (const auto& r : cef_character_bounds) { character_bounds.emplace_back(); character_bounds.back().x = r.x; character_bounds.back().y = r.y; character_bounds.back().w = r.width; character_bounds.back().h = r.height; } s->RenderHandler_OnImeCompositionRangeChanged(bid, selected_range, character_bounds); }); } void RemoteRenderHandler::OnTextSelectionChanged( CefRefPtr<CefBrowser> browser, const CefString& selected_text, const CefRange& cef_selected_range) { FIND_BID_OR_RETURN(); if (doTrace) Log::trace("RemoteRenderHandler::OnTextSelectionChanged: bid=%d", bid); thrift_codegen::Range selected_range; selected_range.from = cef_selected_range.from; selected_range.to = cef_selected_range.to; myService->exec([&](const JavaService& s) { s->RenderHandler_OnTextSelectionChanged(bid, selected_text.ToString(), selected_range); }); }