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:
36 void Timeout() override
37 {
38 // just let run loop
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 if (!args.IsStandalone())
88 handle->fCloseBrowser = false;
89
90 Int_t wait_tmout = args.IsHeadless() ? gEnv->GetValue("WebGui.CefHeadlessTimeout", 30) : -1;
91
92 if (fCefApp) {
93 fCefApp->SetNextHandle(handle.get(), args.IsHeadless());
94
95 CefRect rect((args.GetX() > 0) ? args.GetX() : 0, (args.GetY() > 0) ? args.GetY() : 0,
96 (args.GetWidth() > 0) ? args.GetWidth() : 800, (args.GetHeight() > 0) ? args.GetHeight() : 600);
97
98 fCefApp->StartWindow(args.GetHttpServer(), args.GetFullUrl(), args.GetPageContent(), rect);
99
100 if (args.IsHeadless())
101 handle->WaitForContent(wait_tmout, args.GetExtraArgs());
102
103 return handle;
104 }
105
107 bool use_views = true;
108
109 TString env_use_views = gEnv->GetValue("WebGui.CefUseViews", "");
110 if ((env_use_views == "yes") || (env_use_views == "1"))
111 use_views = true;
112 else if ((env_use_views == "no") || (env_use_views == "0"))
113 use_views = false;
114
115 // Specify CEF global settings here.
117
118 TString ceflog = gEnv->GetValue("WebGui.CefLogSeveriry", "fatal");
119 if (ceflog == "fatal")
120 settings.log_severity = LOGSEVERITY_FATAL;
121 else if (ceflog == "verbose")
122 settings.log_severity = LOGSEVERITY_VERBOSE;
123 else if (ceflog == "info")
124 settings.log_severity = LOGSEVERITY_INFO;
125 else if (ceflog == "warning")
126 settings.log_severity = LOGSEVERITY_WARNING;
127 else if (ceflog == "error")
128 settings.log_severity = LOGSEVERITY_ERROR;
129 else if (ceflog == "disable")
130 settings.log_severity = LOGSEVERITY_DISABLE;
131 else
132 settings.log_severity = LOGSEVERITY_FATAL;
133
134 bool supress_log = (settings.log_severity == LOGSEVERITY_DISABLE) ||
135 (settings.log_severity == LOGSEVERITY_FATAL);
136
137 TApplication *root_app = gROOT->GetApplication();
138
139 std::vector<const char *> cef_argv = { root_app->Argv(0) };
140
141#ifdef OS_WIN
142
144
145#else
146
147 if (args.IsHeadless()) {
148 cef_argv.emplace_back("--user-data-dir=.");
149 cef_argv.emplace_back("--allow-file-access-from-files");
150 cef_argv.emplace_back("--disable-web-security");
151 cef_argv.emplace_back("--disable-gpu");
152 cef_argv.emplace_back("--ignore-gpu-blocklist");
153#ifdef OS_LINUX
154 cef_argv.emplace_back("--use-gl=swiftshader");
155 cef_argv.emplace_back("--enable-unsafe-swiftshader");
156#endif
157 cef_argv.emplace_back("--off-screen-rendering-enabled");
158 if (use_views)
159 cef_argv.emplace_back("--ozone-platform=headless");
160 }
161
162 if (supress_log) {
163 cef_argv.emplace_back("--disable-logging");
164 cef_argv.emplace_back("--enable-logging=none");
165 cef_argv.emplace_back("--v=-1");
166 }
167
168 cef_argv.emplace_back(nullptr);
169
170 CefMainArgs main_args(cef_argv.size() - 1, (char **) cef_argv.data());
171
172#endif
173
174 // CEF applications have multiple sub-processes (render, plugin, GPU, etc)
175 // that share the same executable. This function checks the command-line and,
176 // if this is a sub-process, executes the appropriate logic.
177
178 /* int exit_code = CefExecuteProcess(main_args, nullptr, nullptr);
179 if (exit_code >= 0) {
180 // The sub-process has completed so return here.
181 return exit_code;
182 }
183 */
184
185 // Install xlib error handlers so that the application won't be terminated
186 // on non-fatal errors.
187 // XSetErrorHandler(XErrorHandlerImpl);
188 // XSetIOErrorHandler(XIOErrorHandlerImpl);
189
190
191 TString cef_main = TROOT::GetBinDir() + "/cef_main";
192 cef_string_ascii_to_utf16(cef_main.Data(), cef_main.Length(), &settings.browser_subprocess_path);
193
194#ifdef OS_LINUX
195 // on linux resource directory copied to lib/
196 TString path2 = TROOT::GetLibDir() + "/locales";
197 cef_string_ascii_to_utf16(path2.Data(), path2.Length(), &settings.locales_dir_path);
199 cef_string_ascii_to_utf16(path3.Data(), path3.Length(), &settings.resources_dir_path);
200#endif
201
202#ifdef OS_WIN
203 // on windows resource directory copied to bin/
204 TString path2 = TROOT::GetBinDir() + "/locales";
205 cef_string_ascii_to_utf16(path2.Data(), path2.Length(), &settings.locales_dir_path);
207 cef_string_ascii_to_utf16(path3.Data(), path3.Length(), &settings.resources_dir_path);
208#endif
209
210#ifdef OS_MACOSX
211 // on mac there is framework directory, where resources and libs are combined together
212 TString path = TROOT::GetDataDir() + "/Frameworks/Chromium Embedded Framework.framework";
213 cef_string_ascii_to_utf16(path.Data(), path.Length(), &settings.framework_dir_path);
214#endif
215
216 settings.no_sandbox = true;
217 // if (gROOT->IsWebDisplayBatch()) settings.single_process = true;
218
219 if (args.IsHeadless())
220 settings.windowless_rendering_enabled = true;
221
222 // settings.external_message_pump = true;
223 // settings.multi_threaded_message_loop = false;
224
225 std::string plog = "cef.log";
226 cef_string_ascii_to_utf16(plog.c_str(), plog.length(), &settings.log_file);
227
228 // settings.uncaught_exception_stack_size = 100;
229 // settings.ignore_certificate_errors = true;
230
231 // settings.remote_debugging_port = 7890;
232
233 // SimpleApp implements application-level callbacks for the browser process.
234 // It will create the first browser instance in OnContextInitialized() after
235 // CEF has initialized.
237 args.GetHttpServer(), args.GetFullUrl(), args.GetPageContent(),
238 args.GetWidth() > 0 ? args.GetWidth() : 800,
239 args.GetHeight() > 0 ? args.GetHeight() : 600,
240 args.IsHeadless());
241
242 fCefApp->SetNextHandle(handle.get(), args.IsHeadless());
243
244 // Initialize CEF for the browser process.
245 CefInitialize(main_args, settings, fCefApp.get(), nullptr);
246
247 if (args.IsHeadless()) {
248 handle->WaitForContent(wait_tmout, args.GetExtraArgs());
249 } else {
250 // Create timer to let run CEF message loop together with ROOT event loop
251 Int_t interval = gEnv->GetValue("WebGui.CefTimer", 10);
252 TCefTimer *timer = new TCefTimer((interval > 0) ? interval : 10, kTRUE);
253 timer->TurnOn();
254 }
255
256 // window not yet exists here
257 return handle;
258}
259
260///////////////////////////////////////////////////////////////////////////////////////////////////
261/// Destructor
262/// Closes browser window if any
263
270
271///////////////////////////////////////////////////////////////////////////////////////////////////
272/// Closes associated browser window
273
275{
276 if (fBrowser && fCloseBrowser) {
277 auto host = fBrowser->GetHost();
278 if (host) host->CloseBrowser(true);
279 fBrowser = nullptr;
280 }
281}
282
283///////////////////////////////////////////////////////////////////////////////////////////////////
284/// Process system events until browser content is available
285/// Used in headless mode for batch production like chrome --dump-dom is doing
286
288{
289 int expired = tmout_sec * 100;
290 bool did_try = false, print_finished = false;
291 std::string pdffile;
292 if (!extra_args.empty() && (extra_args.find("--print-to-pdf=")==0))
293 pdffile = extra_args.substr(15);
294
295 while ((--expired > 0) && GetContent().empty() && !print_finished) {
296
297 if (gSystem->ProcessEvents()) break; // interrupted, has to return
298
300
301 if (fBrowser && !did_try && fBrowser->HasDocument() && !fBrowser->IsLoading() && fBrowser->GetMainFrame()) {
302 did_try = true;
303 if (pdffile.empty()) {
304 fBrowser->GetMainFrame()->GetSource(new FrameSourceVisitor(this));
305 } else {
307 fBrowser->GetHost()->PrintToPDF(pdffile, settings, new HeadlessPrintCallback(&print_finished));
308 }
309 }
310
311 gSystem->Sleep(10); // only 10 ms sleep
312 }
313
314 CloseBrowser();
315
316 // call it once here to complete browser window closing, timer is not installed in batch mode
318
319 return !GetContent().empty();
320}
321
322///////////////////////////////////////////////////////////////////////////////////////////////////
323/// Resize browser window
324
326{
327 if (!fBrowser)
328 return false;
330}
331
332///////////////////////////////////////////////////////////////////////////////////////////////////
333/// Add CEF creator
334
336{
337 auto &entry = FindCreator("cef");
338 if (!entry)
339 GetMap().emplace("cef", std::make_unique<CefCreator>());
340}
341
342///////////////////////////////////////////////////////////////////////////////////////////////////
343/// Helper struct to add creator
344
348
struct RCefCreatorReg newRCefCreatorReg
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:68
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
R__EXTERN TEnv * gEnv
Definition TEnv.h:126
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:417
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
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 void 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
bool IsStandalone() const
Return true if browser should runs in standalone mode.
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.
This class creates the ROOT Application Environment that interfaces to the windowing system eventloop...
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:511
static const TString & GetBinDir()
Get the binary directory in the installation. Static utility function.
Definition TROOT.cxx:3150
static const TString & GetLibDir()
Get the library directory in the installation.
Definition TROOT.cxx:3178
static const TString & GetDataDir()
Get the data directory in the installation. Static utility function.
Definition TROOT.cxx:3391
Basic string class.
Definition TString.h:138
Ssiz_t Length() const
Definition TString.h:425
const char * Data() const
Definition TString.h:384
virtual void Sleep(UInt_t milliSec)
Sleep milliSec milli seconds.
Definition TSystem.cxx:439
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition TSystem.cxx:418
Handles synchronous and a-synchronous timer events.
Definition TTimer.h:51
Helper struct to add creator.