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-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
230{
231 if (fBrowser) {
232 auto host = fBrowser->GetHost();
233 if (host) host->CloseBrowser(true);
234 fBrowser = nullptr;
235 }
236}
237
238///////////////////////////////////////////////////////////////////////////////////////////////////
239/// Process system events until browser content is available
240/// Used in headless mode for batch production like chrome --dump-dom is doing
241
242bool RCefWebDisplayHandle::WaitForContent(int tmout_sec, const std::string &extra_args)
243{
244 int expired = tmout_sec * 100;
245 bool did_try = false, print_finished = false;
246 std::string pdffile;
247 if (!extra_args.empty() && (extra_args.find("--print-to-pdf=")==0))
248 pdffile = extra_args.substr(15);
249
250 while ((--expired > 0) && GetContent().empty() && !print_finished) {
251
252 if (gSystem->ProcessEvents()) break; // interrupted, has to return
253
254 CefDoMessageLoopWork();
255
256 if (fBrowser && !did_try && fBrowser->HasDocument() && !fBrowser->IsLoading() && fBrowser->GetMainFrame()) {
257 did_try = true;
258 if (pdffile.empty()) {
259 fBrowser->GetMainFrame()->GetSource(new FrameSourceVisitor(this));
260 } else {
261 CefPdfPrintSettings settings;
262 fBrowser->GetHost()->PrintToPDF(pdffile, settings, new HeadlessPrintCallback(&print_finished));
263 }
264 }
265
266 gSystem->Sleep(10); // only 10 ms sleep
267 }
268
269 CloseBrowser();
270
271 // call it once here to complete browser window closing, timer is not installed in batch mode
272 CefDoMessageLoopWork();
273
274 return !GetContent().empty();
275}
276
277///////////////////////////////////////////////////////////////////////////////////////////////////
278/// Resize browser window
279
281{
282 if (!fBrowser)
283 return false;
285}
286
287///////////////////////////////////////////////////////////////////////////////////////////////////
288/// Add CEF creator
289
291{
292 auto &entry = FindCreator("cef");
293 if (!entry)
294 GetMap().emplace("cef", std::make_unique<CefCreator>());
295}
296
297///////////////////////////////////////////////////////////////////////////////////////////////////
298/// Helper struct to add creator
299
303
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
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:560
DISALLOW_COPY_AND_ASSIGN(FrameSourceVisitor)
void Visit(const CefString &str) override
FrameSourceVisitor(RCefWebDisplayHandle *handle)
IMPLEMENT_REFCOUNTING(FrameSourceVisitor)
RCefWebDisplayHandle * fHandle
virtual ~FrameSourceVisitor()=default
static bool PlatformResize(CefRefPtr< CefBrowser > browser, int width, int height)
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.
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
bool Resize(int, int) override
Resize browser window.
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...
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:2917
static const TString & GetLibDir()
Get the library directory in the installation. Static utility function.
Definition TROOT.cxx:2938
static const TString & GetDataDir()
Get the data directory in the installation. Static utility function.
Definition TROOT.cxx:2990
Basic string class.
Definition TString.h:139
Ssiz_t Length() const
Definition TString.h:421
const char * Data() const
Definition TString.h:380
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
Helper struct to add creator.