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
4/*************************************************************************
5 * Copyright (C) 1995-2023, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12
13#if !defined(_MSC_VER)
14#pragma GCC diagnostic ignored "-Wunused-parameter"
15#pragma GCC diagnostic ignored "-Wshadow"
16#endif
17
18
20
21#include "TTimer.h"
22#include "TROOT.h"
23#include "TSystem.h"
24#include "TEnv.h"
25#include "TApplication.h"
26
27#include "include/base/cef_build.h"
28
29#include <ROOT/RLogger.hxx>
30
31#include <memory>
32
33
34class TCefTimer : public TTimer {
35public:
37 void Timeout() override
38 {
39 // just let run loop
41 }
42};
43
44
46
48
49public:
50
52
53 ~FrameSourceVisitor() override = default;
54
55 void Visit(const CefString &str) override
56 {
57 if (fHandle && fHandle->IsValid())
58 fHandle->SetContent(str.ToString());
59 }
60
61private:
62 // Include the default reference counting implementation.
65};
66
67
69 bool *fFlag{nullptr};
70public:
72 ~HeadlessPrintCallback() override = default;
73
74 void OnPdfPrintFinished(const CefString&, bool ok) override
75 {
76 if (fFlag) *fFlag = true;
77 }
78private:
79 // Include the default reference counting implementation.
82};
83
84std::unique_ptr<ROOT::RWebDisplayHandle> RCefWebDisplayHandle::CefCreator::Display(const ROOT::RWebDisplayArgs &args)
85{
86
87 auto handle = std::make_unique<RCefWebDisplayHandle>(args.GetFullUrl());
88 if (!args.IsStandalone())
89 handle->fCloseBrowser = false;
90
91 Int_t wait_tmout = args.IsHeadless() ? gEnv->GetValue("WebGui.CefHeadlessTimeout", 30) : -1;
92
93 if (fCefApp) {
94 fCefApp->SetNextHandle(handle.get(), args.IsHeadless());
95
96 CefRect rect((args.GetX() > 0) ? args.GetX() : 0, (args.GetY() > 0) ? args.GetY() : 0,
97 (args.GetWidth() > 0) ? args.GetWidth() : 800, (args.GetHeight() > 0) ? args.GetHeight() : 600);
98
99 fCefApp->StartWindow(args.GetHttpServer(), args.GetFullUrl(), args.GetPageContent(), rect, args.IsHeadless());
100
101 if (args.IsHeadless())
102 handle->WaitForContent(wait_tmout, args.GetExtraArgs());
103
104 return handle;
105 }
106
108 bool use_views = true;
109
110 TString env_use_views = gEnv->GetValue("WebGui.CefUseViews", "");
111 if ((env_use_views == "yes") || (env_use_views == "1"))
112 use_views = true;
113 else if ((env_use_views == "no") || (env_use_views == "0"))
114 use_views = false;
115
116 // Specify CEF global settings here.
118
119 TString ceflog = gEnv->GetValue("WebGui.CefLogSeveriry", "fatal");
120 if (ceflog == "fatal")
121 settings.log_severity = LOGSEVERITY_FATAL;
122 else if (ceflog == "verbose")
123 settings.log_severity = LOGSEVERITY_VERBOSE;
124 else if (ceflog == "info")
125 settings.log_severity = LOGSEVERITY_INFO;
126 else if (ceflog == "warning")
127 settings.log_severity = LOGSEVERITY_WARNING;
128 else if (ceflog == "error")
129 settings.log_severity = LOGSEVERITY_ERROR;
130 else if (ceflog == "disable")
131 settings.log_severity = LOGSEVERITY_DISABLE;
132 else
133 settings.log_severity = LOGSEVERITY_FATAL;
134
135 bool supress_log = (settings.log_severity == LOGSEVERITY_DISABLE) ||
136 (settings.log_severity == LOGSEVERITY_FATAL);
137
138
139#ifdef OS_WIN
140
141 // CefMainArgs main_args(args.IsHeadless() ? (HINSTANCE) 0 : GetModuleHandle(nullptr));
142
144
145#else
146
147 TApplication *root_app = gROOT->GetApplication();
148
149 std::vector<const char *> cef_argv = { root_app->Argv(0) };
150
151 if (supress_log) {
152 cef_argv.emplace_back("--disable-logging");
153 cef_argv.emplace_back("--enable-logging=none");
154 cef_argv.emplace_back("--v=-1");
155 }
156
157 cef_argv.emplace_back(nullptr);
158
159 CefMainArgs main_args(cef_argv.size() - 1, (char **) cef_argv.data());
160
161#endif
162
163 // CEF applications have multiple sub-processes (render, plugin, GPU, etc)
164 // that share the same executable. This function checks the command-line and,
165 // if this is a sub-process, executes the appropriate logic.
166
167 /* int exit_code = CefExecuteProcess(main_args, nullptr, nullptr);
168 if (exit_code >= 0) {
169 // The sub-process has completed so return here.
170 return exit_code;
171 }
172 */
173
174 // Install xlib error handlers so that the application won't be terminated
175 // on non-fatal errors.
176 // XSetErrorHandler(XErrorHandlerImpl);
177 // XSetIOErrorHandler(XIOErrorHandlerImpl);
178
179
180 TString cef_main = TROOT::GetBinDir() + "/cef_main";
181 cef_string_ascii_to_utf16(cef_main.Data(), cef_main.Length(), &settings.browser_subprocess_path);
182
183#ifdef OS_MACOSX
184 // on mac there is framework directory, where resources and libs are combined together
185 TString path = TROOT::GetDataDir() + "/Frameworks/Chromium Embedded Framework.framework";
186 cef_string_ascii_to_utf16(path.Data(), path.Length(), &settings.framework_dir_path);
187
188 // add CEF libraries to DYLD library path
189 TString dypath = gSystem->Getenv("DYLD_LIBRARY_PATH");
190 if (dypath.Length() > 0)
191 dypath.Append(":");
192 dypath.Append(path + "/Libraries/");
193 gSystem->Setenv("DYLD_LIBRARY_PATH", dypath);
194#endif
195
196#ifdef OS_WIN
198 cef_string_ascii_to_utf16(resource_dir.Data(), resource_dir.Length(), &settings.resources_dir_path);
199 TString locales_dir = TROOT::GetDataDir() + "/Frameworks/cef/locales";
200 cef_string_ascii_to_utf16(locales_dir.Data(), locales_dir.Length(), &settings.locales_dir_path);
201#endif
202
203#ifdef OS_LINUX
205 cef_string_ascii_to_utf16(resource_dir.Data(), resource_dir.Length(), &settings.resources_dir_path);
206 TString locales_dir = TROOT::GetDataDir() + "/Frameworks/cef/locales";
207 cef_string_ascii_to_utf16(locales_dir.Data(), locales_dir.Length(), &settings.locales_dir_path);
208#endif
209
210 settings.no_sandbox = true;
211 // if (gROOT->IsWebDisplayBatch()) settings.single_process = true;
212
213 if (args.IsHeadless())
214 settings.windowless_rendering_enabled = true;
215
216 // settings.external_message_pump = true;
217 // settings.multi_threaded_message_loop = false;
218
219 std::string plog = "cef.log";
220 cef_string_ascii_to_utf16(plog.c_str(), plog.length(), &settings.log_file);
221
222 // settings.uncaught_exception_stack_size = 100;
223 // settings.ignore_certificate_errors = true;
224
225 // settings.remote_debugging_port = 7890;
226
227 // SimpleApp implements application-level callbacks for the browser process.
228 // It will create the first browser instance in OnContextInitialized() after
229 // CEF has initialized.
231 args.GetHttpServer(), args.GetFullUrl(), args.GetPageContent(),
232 args.GetWidth() > 0 ? args.GetWidth() : 800,
233 args.GetHeight() > 0 ? args.GetHeight() : 600,
234 args.IsHeadless());
235
236 fCefApp->SetNextHandle(handle.get(), args.IsHeadless());
237
238 // Initialize CEF for the browser process.
239 CefInitialize(main_args, settings, fCefApp.get(), nullptr);
240
241 if (args.IsHeadless()) {
242 handle->WaitForContent(wait_tmout, args.GetExtraArgs());
243 } else {
244 // Create timer to let run CEF message loop together with ROOT event loop
245 Int_t interval = gEnv->GetValue("WebGui.CefTimer", 10);
246 TCefTimer *timer = new TCefTimer((interval > 0) ? interval : 10, kTRUE);
247 timer->TurnOn();
248 }
249
250 // window not yet exists here
251 return handle;
252}
253
254///////////////////////////////////////////////////////////////////////////////////////////////////
255/// Destructor
256/// Closes browser window if any
257
264
265///////////////////////////////////////////////////////////////////////////////////////////////////
266/// Closes associated browser window
267
269{
270 if (fBrowser && fCloseBrowser) {
271 auto host = fBrowser->GetHost();
272 if (host) host->CloseBrowser(true);
273 fBrowser = nullptr;
274 }
275}
276
277///////////////////////////////////////////////////////////////////////////////////////////////////
278/// Process system events until browser content is available
279/// Used in headless mode for batch production like chrome --dump-dom is doing
280
282{
283 int expired = tmout_sec * 100;
284 bool did_try = false, print_finished = false;
285 std::string pdffile;
286 if (!extra_args.empty() && (extra_args.find("--print-to-pdf=")==0))
287 pdffile = extra_args.substr(15);
288
289 while ((--expired > 0) && GetContent().empty() && !print_finished) {
290
291 if (gSystem->ProcessEvents()) break; // interrupted, has to return
292
294
295 if (fBrowser && !did_try && fBrowser->HasDocument() && !fBrowser->IsLoading() && fBrowser->GetMainFrame()) {
296 did_try = true;
297 if (pdffile.empty()) {
298 fBrowser->GetMainFrame()->GetSource(new FrameSourceVisitor(this));
299 } else {
301 fBrowser->GetHost()->PrintToPDF(pdffile, settings, new HeadlessPrintCallback(&print_finished));
302 }
303 }
304
305 gSystem->Sleep(10); // only 10 ms sleep
306 }
307
308 CloseBrowser();
309
310 // call it once here to complete browser window closing, timer is not installed in batch mode
312
313 return !GetContent().empty();
314}
315
316///////////////////////////////////////////////////////////////////////////////////////////////////
317/// Resize browser window
318
320{
321 if (!fBrowser)
322 return false;
324}
325
326///////////////////////////////////////////////////////////////////////////////////////////////////
327/// Add CEF creator
328
330{
331 auto &entry = FindCreator("cef");
332 if (!entry)
333 GetMap().emplace("cef", std::make_unique<CefCreator>());
334}
335
336///////////////////////////////////////////////////////////////////////////////////////////////////
337/// Helper struct to add creator
338
342
struct RCefCreatorReg newRCefCreatorReg
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:69
constexpr Bool_t kTRUE
Definition RtypesCore.h:108
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:427
const char * Data() const
Definition TString.h:386
virtual const char * Getenv(const char *env)
Get environment variable.
Definition TSystem.cxx:1680
virtual void Sleep(UInt_t milliSec)
Sleep milliSec milli seconds.
Definition TSystem.cxx:439
virtual void Setenv(const char *name, const char *value)
Set environment variable.
Definition TSystem.cxx:1664
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.