Logo ROOT  
Reference Guide
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-2020, 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
44
46
48
49public:
50
52
53 virtual ~FrameSourceVisitor() = 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 virtual ~HeadlessPrintCallback() = 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::Experimental::RWebDisplayHandle> RCefWebDisplayHandle::CefCreator::Display(const ROOT::Experimental::RWebDisplayArgs &args)
85{
86
87 auto handle = std::make_unique<RCefWebDisplayHandle>(args.GetFullUrl());
88
89 if (fCefApp) {
90 fCefApp->SetNextHandle(handle.get());
91
92 CefRect rect((args.GetX() > 0) ? args.GetX() : 0, (args.GetY() > 0) ? args.GetY() : 0,
93 (args.GetWidth() > 0) ? args.GetWidth() : 800, (args.GetHeight() > 0) ? args.GetHeight() : 600);
94
95 fCefApp->StartWindow(args.GetHttpServer(), args.GetFullUrl(), args.GetPageContent(), rect);
96
97 if (args.IsHeadless())
98 handle->WaitForContent(30, args.GetExtraArgs()); // 30 seconds
99
100 return handle;
101 }
102
103 bool use_views = GuiHandler::PlatformInit();
104
105#ifdef OS_WIN
106 CefMainArgs main_args(GetModuleHandle(nullptr));
107#else
108 TApplication *root_app = gROOT->GetApplication();
109
110 int cef_argc = 1;
111 const char *arg2 = nullptr, *arg3 = nullptr;
112 if (args.IsHeadless()) {
113 // arg2 = "--allow-file-access-from-files";
114 arg2 = "--disable-web-security";
115 cef_argc++;
116 if (use_views) {
117 arg3 = "--ozone-platform=headless";
118 cef_argc++;
119 }
120 }
121 char *cef_argv[] = {root_app->Argv(0), (char *) arg2, (char *) arg3, nullptr};
122
123 CefMainArgs main_args(cef_argc, cef_argv);
124#endif
125
126 // CEF applications have multiple sub-processes (render, plugin, GPU, etc)
127 // that share the same executable. This function checks the command-line and,
128 // if this is a sub-process, executes the appropriate logic.
129
130 /* int exit_code = CefExecuteProcess(main_args, nullptr, nullptr);
131 if (exit_code >= 0) {
132 // The sub-process has completed so return here.
133 return exit_code;
134 }
135 */
136
137 // Install xlib error handlers so that the application won't be terminated
138 // on non-fatal errors.
139 // XSetErrorHandler(XErrorHandlerImpl);
140 // XSetIOErrorHandler(XIOErrorHandlerImpl);
141
142 // Specify CEF global settings here.
143 CefSettings settings;
144
145 TString cef_main = TROOT::GetBinDir() + "/cef_main";
146 cef_string_ascii_to_utf16(cef_main.Data(), cef_main.Length(), &settings.browser_subprocess_path);
147
148#ifdef OS_LINUX
149 // on linux resource directory copied to lib/
150 TString path2 = TROOT::GetLibDir() + "/locales";
151 cef_string_ascii_to_utf16(path2.Data(), path2.Length(), &settings.locales_dir_path);
152 TString path3 = TROOT::GetLibDir();
153 cef_string_ascii_to_utf16(path3.Data(), path3.Length(), &settings.resources_dir_path);
154#endif
155
156#ifdef OS_WIN
157 // on windows resource directory copied to bin/
158 TString path2 = TROOT::GetBinDir() + "/locales";
159 cef_string_ascii_to_utf16(path2.Data(), path2.Length(), &settings.locales_dir_path);
160 TString path3 = TROOT::GetBinDir();
161 cef_string_ascii_to_utf16(path3.Data(), path3.Length(), &settings.resources_dir_path);
162#endif
163
164#ifdef OS_MACOSX
165 // on mac there is framework directory, where resources and libs are combined together
166 TString path = TROOT::GetDataDir() + "/Frameworks/Chromium Embedded Framework.framework";
167 cef_string_ascii_to_utf16(path.Data(), path.Length(), &settings.framework_dir_path);
168#endif
169
170 settings.no_sandbox = true;
171 // if (gROOT->IsWebDisplayBatch()) settings.single_process = true;
172
173 // if (batch_mode)
174 // settings.windowless_rendering_enabled = true;
175
176 // settings.external_message_pump = true;
177 // settings.multi_threaded_message_loop = false;
178
179 std::string plog = "cef.log";
180 cef_string_ascii_to_utf16(plog.c_str(), plog.length(), &settings.log_file);
181
182 settings.log_severity = LOGSEVERITY_ERROR; // LOGSEVERITY_VERBOSE, LOGSEVERITY_INFO, LOGSEVERITY_WARNING,
183 // LOGSEVERITY_ERROR, LOGSEVERITY_DISABLE
184 // settings.uncaught_exception_stack_size = 100;
185 // settings.ignore_certificate_errors = true;
186
187 // settings.remote_debugging_port = 7890;
188
189 // SimpleApp implements application-level callbacks for the browser process.
190 // It will create the first browser instance in OnContextInitialized() after
191 // CEF has initialized.
192 fCefApp = new SimpleApp(use_views, args.GetHttpServer(), args.GetFullUrl(), args.GetPageContent(),
193 args.GetWidth() > 0 ? args.GetWidth() : 800,
194 args.GetHeight() > 0 ? args.GetHeight() : 600,
195 args.IsHeadless());
196
197 fCefApp->SetNextHandle(handle.get());
198
199 // Initialize CEF for the browser process.
200 CefInitialize(main_args, settings, fCefApp.get(), nullptr);
201
202 if (args.IsHeadless()) {
203 handle->WaitForContent(30, args.GetExtraArgs()); // 30 seconds
204 } else {
205 // Create timer to let run CEF message loop together with ROOT event loop
206 Int_t interval = gEnv->GetValue("WebGui.CefTimer", 10);
207 TCefTimer *timer = new TCefTimer((interval > 0) ? interval : 10, kTRUE);
208 timer->TurnOn();
209 }
210
211 // window not yet exists here
212 return handle;
213}
214
215///////////////////////////////////////////////////////////////////////////////////////////////////
216/// Destructor
217/// Closes browser window if any
218
220{
222
223 CloseBrowser();
224}
225
226///////////////////////////////////////////////////////////////////////////////////////////////////
227/// Closes associated browser window
228
229
231{
232 if (fBrowser) {
233 auto host = fBrowser->GetHost();
234 if (host) host->CloseBrowser(true);
235 fBrowser = nullptr;
236 }
237}
238
239
240
241///////////////////////////////////////////////////////////////////////////////////////////////////
242/// Process system events until browser content is available
243/// Used in headless mode for batch production like chrome --dump-dom is doing
244
245bool RCefWebDisplayHandle::WaitForContent(int tmout_sec, const std::string &extra_args)
246{
247 int expired = tmout_sec * 100;
248 bool did_try = false, print_finished = false;
249 std::string pdffile;
250 if (!extra_args.empty() && (extra_args.find("--print-to-pdf=")==0))
251 pdffile = extra_args.substr(15);
252
253 while ((--expired > 0) && GetContent().empty() && !print_finished) {
254
255 if (gSystem->ProcessEvents()) break; // interrupted, has to return
256
257 CefDoMessageLoopWork();
258
259 if (fBrowser && !did_try && fBrowser->HasDocument() && !fBrowser->IsLoading() && fBrowser->GetMainFrame()) {
260 did_try = true;
261 if (pdffile.empty()) {
262 fBrowser->GetMainFrame()->GetSource(new FrameSourceVisitor(this));
263 } else {
264 CefPdfPrintSettings settings;
265 fBrowser->GetHost()->PrintToPDF(pdffile, settings, new HeadlessPrintCallback(&print_finished));
266 }
267 }
268
269 gSystem->Sleep(10); // only 10 ms sleep
270 }
271
272 CloseBrowser();
273
274 // call it once here to complete browser window closing, timer is not installed in batch mode
275 CefDoMessageLoopWork();
276
277 return !GetContent().empty();
278}
279
280
282{
283 auto &entry = FindCreator("cef");
284 if (!entry)
285 GetMap().emplace("cef", std::make_unique<CefCreator>());
286}
287
288
292
struct RCefCreatorReg newRCefCreatorReg
long Long_t
Definition: RtypesCore.h:54
const Bool_t kTRUE
Definition: RtypesCore.h:100
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
#define gROOT
Definition: TROOT.h:404
R__EXTERN TSystem * gSystem
Definition: TSystem.h:559
DISALLOW_COPY_AND_ASSIGN(FrameSourceVisitor)
void Visit(const CefString &str) override
FrameSourceVisitor(RCefWebDisplayHandle *handle)
IMPLEMENT_REFCOUNTING(FrameSourceVisitor)
RCefWebDisplayHandle * fHandle
virtual ~FrameSourceVisitor()=default
static bool PlatformInit()
void OnPdfPrintFinished(const CefString &, bool ok) override
virtual ~HeadlessPrintCallback()=default
IMPLEMENT_REFCOUNTING(HeadlessPrintCallback)
DISALLOW_COPY_AND_ASSIGN(HeadlessPrintCallback)
std::unique_ptr< ROOT::Experimental::RWebDisplayHandle > Display(const ROOT::Experimental::RWebDisplayArgs &args) override
CefRefPtr< CefBrowser > fBrowser
associated browser
void CloseBrowser()
Closes associated browser window.
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
virtual ~RCefWebDisplayHandle()
Destructor Closes browser window if any.
Holds different arguments for starting browser with RWebDisplayHandle::Display() method.
bool IsHeadless() const
returns headless mode
int GetHeight() const
returns preferable web window height
const std::string & GetExtraArgs() const
get extra command line arguments for starting web browser command
std::string GetFullUrl() const
returns window url with append options
THttpServer * GetHttpServer() const
returns http server instance, used for window display
const std::string & GetPageContent() const
returns window url
int GetY() const
set preferable web window y position
int GetX() const
set preferable web window x position
int GetWidth() const
returns preferable web window width
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
const std::string & GetContent() const
get 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...
Definition: TApplication.h:39
char ** Argv() const
Definition: TApplication.h:136
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:2905
static const TString & GetLibDir()
Get the library directory in the installation. Static utility function.
Definition: TROOT.cxx:2926
static const TString & GetDataDir()
Get the data directory in the installation. Static utility function.
Definition: TROOT.cxx:2967
Basic string class.
Definition: TString.h:136
Ssiz_t Length() const
Definition: TString.h:410
const char * Data() const
Definition: TString.h:369
virtual void Sleep(UInt_t milliSec)
Sleep milliSec milli seconds.
Definition: TSystem.cxx:440
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition: TSystem.cxx:419
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