Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RCefWebDisplayHandle.cxx
Go to the documentation of this file.
1// Author: Sergey Linev <S.Linev@gsi.de>
2// Date: 2020-08-21
3// Warning: This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome!
4
5/*************************************************************************
6 * Copyright (C) 1995-2023, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13
14#if !defined(_MSC_VER)
15#pragma GCC diagnostic ignored "-Wunused-parameter"
16#pragma GCC diagnostic ignored "-Wshadow"
17#endif
18
19
21
22#include "TTimer.h"
23#include "TROOT.h"
24#include "TSystem.h"
25#include "TEnv.h"
26#include "TApplication.h"
27
28#include <ROOT/RLogger.hxx>
29
30#include <memory>
31
32
33class TCefTimer : public TTimer {
34public:
35 TCefTimer(Long_t milliSec, Bool_t mode) : TTimer(milliSec, mode) {}
36 void Timeout() override
37 {
38 // just let run loop
39 CefDoMessageLoopWork();
40 }
41};
42
43
45
47
48public:
49
51
52 ~FrameSourceVisitor() override = default;
53
54 void Visit(const CefString &str) override
55 {
56 if (fHandle && fHandle->IsValid())
57 fHandle->SetContent(str.ToString());
58 }
59
60private:
61 // Include the default reference counting implementation.
64};
65
66
68 bool *fFlag{nullptr};
69public:
71 ~HeadlessPrintCallback() override = default;
72
73 void OnPdfPrintFinished(const CefString&, bool ok) override
74 {
75 if (fFlag) *fFlag = true;
76 }
77private:
78 // Include the default reference counting implementation.
81};
82
83std::unique_ptr<ROOT::RWebDisplayHandle> RCefWebDisplayHandle::CefCreator::Display(const ROOT::RWebDisplayArgs &args)
84{
85
86 auto handle = std::make_unique<RCefWebDisplayHandle>(args.GetFullUrl());
87
88 if (fCefApp) {
89 fCefApp->SetNextHandle(handle.get());
90
91 CefRect rect((args.GetX() > 0) ? args.GetX() : 0, (args.GetY() > 0) ? args.GetY() : 0,
92 (args.GetWidth() > 0) ? args.GetWidth() : 800, (args.GetHeight() > 0) ? args.GetHeight() : 600);
93
94 fCefApp->StartWindow(args.GetHttpServer(), args.GetFullUrl(), args.GetPageContent(), rect);
95
96 if (args.IsHeadless())
97 handle->WaitForContent(30, args.GetExtraArgs()); // 30 seconds
98
99 return handle;
100 }
101
102 bool use_views = GuiHandler::PlatformInit();
103
104#ifdef OS_WIN
105 CefMainArgs main_args(GetModuleHandle(nullptr));
106#else
107 TApplication *root_app = gROOT->GetApplication();
108
109 int cef_argc = 1;
110 const char *arg2 = nullptr, *arg3 = nullptr;
111 if (args.IsHeadless()) {
112 // arg2 = "--allow-file-access-from-files";
113 arg2 = "--disable-web-security";
114 cef_argc++;
115 if (use_views) {
116 arg3 = "--ozone-platform=headless";
117 cef_argc++;
118 }
119 }
120 char *cef_argv[] = {root_app->Argv(0), (char *) arg2, (char *) arg3, nullptr};
121
122 CefMainArgs main_args(cef_argc, cef_argv);
123#endif
124
125 // CEF applications have multiple sub-processes (render, plugin, GPU, etc)
126 // that share the same executable. This function checks the command-line and,
127 // if this is a sub-process, executes the appropriate logic.
128
129 /* int exit_code = CefExecuteProcess(main_args, nullptr, nullptr);
130 if (exit_code >= 0) {
131 // The sub-process has completed so return here.
132 return exit_code;
133 }
134 */
135
136 // Install xlib error handlers so that the application won't be terminated
137 // on non-fatal errors.
138 // XSetErrorHandler(XErrorHandlerImpl);
139 // XSetIOErrorHandler(XIOErrorHandlerImpl);
140
141 // Specify CEF global settings here.
142 CefSettings settings;
143
144 TString cef_main = TROOT::GetBinDir() + "/cef_main";
145 cef_string_ascii_to_utf16(cef_main.Data(), cef_main.Length(), &settings.browser_subprocess_path);
146
147#ifdef OS_LINUX
148 // on linux resource directory copied to lib/
149 TString path2 = TROOT::GetLibDir() + "/locales";
150 cef_string_ascii_to_utf16(path2.Data(), path2.Length(), &settings.locales_dir_path);
151 TString path3 = TROOT::GetLibDir();
152 cef_string_ascii_to_utf16(path3.Data(), path3.Length(), &settings.resources_dir_path);
153#endif
154
155#ifdef OS_WIN
156 // on windows resource directory copied to bin/
157 TString path2 = TROOT::GetBinDir() + "/locales";
158 cef_string_ascii_to_utf16(path2.Data(), path2.Length(), &settings.locales_dir_path);
159 TString path3 = TROOT::GetBinDir();
160 cef_string_ascii_to_utf16(path3.Data(), path3.Length(), &settings.resources_dir_path);
161#endif
162
163#ifdef OS_MACOSX
164 // on mac there is framework directory, where resources and libs are combined together
165 TString path = TROOT::GetDataDir() + "/Frameworks/Chromium Embedded Framework.framework";
166 cef_string_ascii_to_utf16(path.Data(), path.Length(), &settings.framework_dir_path);
167#endif
168
169 settings.no_sandbox = true;
170 // if (gROOT->IsWebDisplayBatch()) settings.single_process = true;
171
172 // if (batch_mode)
173 // settings.windowless_rendering_enabled = true;
174
175 // settings.external_message_pump = true;
176 // settings.multi_threaded_message_loop = false;
177
178 std::string plog = "cef.log";
179 cef_string_ascii_to_utf16(plog.c_str(), plog.length(), &settings.log_file);
180
181 settings.log_severity = LOGSEVERITY_ERROR; // LOGSEVERITY_VERBOSE, LOGSEVERITY_INFO, LOGSEVERITY_WARNING,
182 // LOGSEVERITY_ERROR, LOGSEVERITY_DISABLE
183 // settings.uncaught_exception_stack_size = 100;
184 // settings.ignore_certificate_errors = true;
185
186 // settings.remote_debugging_port = 7890;
187
188 // SimpleApp implements application-level callbacks for the browser process.
189 // It will create the first browser instance in OnContextInitialized() after
190 // CEF has initialized.
191 fCefApp = new SimpleApp(use_views, args.GetHttpServer(), args.GetFullUrl(), args.GetPageContent(),
192 args.GetWidth() > 0 ? args.GetWidth() : 800,
193 args.GetHeight() > 0 ? args.GetHeight() : 600,
194 args.IsHeadless());
195
196 fCefApp->SetNextHandle(handle.get());
197
198 // Initialize CEF for the browser process.
199 CefInitialize(main_args, settings, fCefApp.get(), nullptr);
200
201 if (args.IsHeadless()) {
202 handle->WaitForContent(30, args.GetExtraArgs()); // 30 seconds
203 } else {
204 // Create timer to let run CEF message loop together with ROOT event loop
205 Int_t interval = gEnv->GetValue("WebGui.CefTimer", 10);
206 TCefTimer *timer = new TCefTimer((interval > 0) ? interval : 10, kTRUE);
207 timer->TurnOn();
208 }
209
210 // window not yet exists here
211 return handle;
212}
213
214///////////////////////////////////////////////////////////////////////////////////////////////////
215/// Destructor
216/// Closes browser window if any
217
219{
221
222 CloseBrowser();
223}
224
225///////////////////////////////////////////////////////////////////////////////////////////////////
226/// Closes associated browser window
227
229{
230 if (fBrowser) {
231 auto host = fBrowser->GetHost();
232 if (host) host->CloseBrowser(true);
233 fBrowser = nullptr;
234 }
235}
236
237///////////////////////////////////////////////////////////////////////////////////////////////////
238/// Process system events until browser content is available
239/// Used in headless mode for batch production like chrome --dump-dom is doing
240
241bool RCefWebDisplayHandle::WaitForContent(int tmout_sec, const std::string &extra_args)
242{
243 int expired = tmout_sec * 100;
244 bool did_try = false, print_finished = false;
245 std::string pdffile;
246 if (!extra_args.empty() && (extra_args.find("--print-to-pdf=")==0))
247 pdffile = extra_args.substr(15);
248
249 while ((--expired > 0) && GetContent().empty() && !print_finished) {
250
251 if (gSystem->ProcessEvents()) break; // interrupted, has to return
252
253 CefDoMessageLoopWork();
254
255 if (fBrowser && !did_try && fBrowser->HasDocument() && !fBrowser->IsLoading() && fBrowser->GetMainFrame()) {
256 did_try = true;
257 if (pdffile.empty()) {
258 fBrowser->GetMainFrame()->GetSource(new FrameSourceVisitor(this));
259 } else {
260 CefPdfPrintSettings settings;
261 fBrowser->GetHost()->PrintToPDF(pdffile, settings, new HeadlessPrintCallback(&print_finished));
262 }
263 }
264
265 gSystem->Sleep(10); // only 10 ms sleep
266 }
267
268 CloseBrowser();
269
270 // call it once here to complete browser window closing, timer is not installed in batch mode
271 CefDoMessageLoopWork();
272
273 return !GetContent().empty();
274}
275
276///////////////////////////////////////////////////////////////////////////////////////////////////
277/// Resize browser window
278
280{
281 if (!fBrowser)
282 return false;
284}
285
286///////////////////////////////////////////////////////////////////////////////////////////////////
287/// Add CEF creator
288
290{
291 auto &entry = FindCreator("cef");
292 if (!entry)
293 GetMap().emplace("cef", std::make_unique<CefCreator>());
294}
295
296///////////////////////////////////////////////////////////////////////////////////////////////////
297/// Helper struct to add creator
298
302
struct RCefCreatorReg newRCefCreatorReg
long Long_t
Definition RtypesCore.h:54
constexpr Bool_t kTRUE
Definition RtypesCore.h:93
R__EXTERN TEnv * gEnv
Definition TEnv.h:170
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t rect
Option_t Option_t TPoint TPoint const char mode
Option_t Option_t width
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t height
#define gROOT
Definition TROOT.h:406
R__EXTERN TSystem * gSystem
Definition TSystem.h:561
DISALLOW_COPY_AND_ASSIGN(FrameSourceVisitor)
void Visit(const CefString &str) override
FrameSourceVisitor(RCefWebDisplayHandle *handle)
IMPLEMENT_REFCOUNTING(FrameSourceVisitor)
RCefWebDisplayHandle * fHandle
~FrameSourceVisitor() override=default
static bool PlatformResize(CefRefPtr< CefBrowser > browser, int width, int height)
static bool PlatformInit()
void OnPdfPrintFinished(const CefString &, bool ok) override
~HeadlessPrintCallback() override=default
IMPLEMENT_REFCOUNTING(HeadlessPrintCallback)
DISALLOW_COPY_AND_ASSIGN(HeadlessPrintCallback)
std::unique_ptr< ROOT::RWebDisplayHandle > Display(const ROOT::RWebDisplayArgs &args) override
CefRefPtr< CefBrowser > fBrowser
associated browser
void CloseBrowser()
Closes associated browser window.
static void AddCreator()
Add CEF creator.
bool WaitForContent(int tmout_sec, const std::string &extra_args)
Process system events until browser content is available Used in headless mode for batch production l...
unsigned fValid
used to verify if instance valid or not
~RCefWebDisplayHandle() override
Destructor Closes browser window if any.
bool Resize(int, int) override
Resize browser window.
Holds different arguments for starting browser with RWebDisplayHandle::Display() method.
THttpServer * GetHttpServer() const
returns http server instance, used for window display
int GetWidth() const
returns preferable web window width
int GetY() const
set preferable web window y position
std::string GetFullUrl() const
returns window url with append options
int GetHeight() const
returns preferable web window height
bool IsHeadless() const
returns headless mode
const std::string & GetExtraArgs() const
get extra command line arguments for starting web browser command
int GetX() const
set preferable web window x position
const std::string & GetPageContent() const
returns window url
const std::string & GetContent() const
get content
static std::map< std::string, std::unique_ptr< Creator > > & GetMap()
Static holder of registered creators of web displays.
void SetContent(const std::string &cont)
set content
static std::unique_ptr< Creator > & FindCreator(const std::string &name, const std::string &libname="")
Search for specific browser creator If not found, try to add one.
void SetNextHandle(RCefWebDisplayHandle *handle)
This class creates the ROOT Application Environment that interfaces to the windowing system eventloop...
char ** Argv() const
void Timeout() override
TCefTimer(Long_t milliSec, Bool_t mode)
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition TEnv.cxx:491
static const TString & GetBinDir()
Get the binary directory in the installation. Static utility function.
Definition TROOT.cxx:2993
static const TString & GetLibDir()
Get the library directory in the installation. Static utility function.
Definition TROOT.cxx:3014
static const TString & GetDataDir()
Get the data directory in the installation. Static utility function.
Definition TROOT.cxx:3066
Basic string class.
Definition TString.h:139
Ssiz_t Length() const
Definition TString.h:417
const char * Data() const
Definition TString.h:376
virtual void Sleep(UInt_t milliSec)
Sleep milliSec milli seconds.
Definition TSystem.cxx:437
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition TSystem.cxx:416
Handles synchronous and a-synchronous timer events.
Definition TTimer.h:51
virtual void TurnOn()
Add the timer to the system timer list.
Definition TTimer.cxx:243
Helper struct to add creator.