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