18#include "RConfigure.h"
41using namespace std::string_literals;
48 static std::map<std::string, std::unique_ptr<RWebDisplayHandle::Creator>> sMap;
61 auto search =
m.find(
name);
62 if (search ==
m.end()) {
64 if (libname ==
"ChromeCreator") {
65 m.emplace(
name, std::make_unique<ChromeCreator>());
66 }
else if (libname ==
"FirefoxCreator") {
67 m.emplace(
name, std::make_unique<FirefoxCreator>());
68 }
else if (libname ==
"BrowserCreator") {
69 m.emplace(
name, std::make_unique<BrowserCreator>(
false));
70 }
else if (!libname.empty()) {
74 search =
m.find(
name);
77 if (search !=
m.end())
78 return search->second;
80 static std::unique_ptr<RWebDisplayHandle::Creator> dummy;
85namespace Experimental {
94 typedef int browser_process_id;
96 typedef pid_t browser_process_id;
100 browser_process_id fPid;
103 RWebBrowserHandle(
const std::string &url,
const std::string &tmpdir,
const std::string &dump) :
RWebDisplayHandle(url), fTmpDir(tmpdir)
108 RWebBrowserHandle(
const std::string &url,
const std::string &tmpdir, browser_process_id pid)
113 virtual ~RWebBrowserHandle()
117 gSystem->
Exec((
"taskkill /F /PID "s + std::to_string(fPid) +
" >NUL 2>NUL").c_str());
118 std::string rmdir =
"rmdir /S /Q ";
122 std::string rmdir =
"rm -rf ";
124 if (!fTmpDir.empty())
141 if (exec.find(
"$url") == std::string::npos) {
144 fExec = exec +
" $url";
146 fExec = exec +
" $url &";
150 auto pos = exec.find(
" ");
151 if (pos != std::string::npos)
152 fProg = exec.substr(0, pos);
155 fExec =
"open \'$url\'";
157 fExec =
"start $url";
159 fExec =
"xdg-open \'$url\' &";
168 if (nexttry.empty() || !fProg.empty())
173 fProg = std::regex_replace(nexttry, std::regex(
"%20"),
" ");
180 if (!check_std_paths)
185 auto pos = ProgramFiles.find(
" (x86)");
186 if (pos != std::string::npos)
187 ProgramFiles.erase(pos, 6);
188 std::string ProgramFilesx86 =
gSystem->
Getenv(
"ProgramFiles(x86)");
190 if (!ProgramFiles.empty())
191 TestProg(ProgramFiles + nexttry,
false);
192 if (!ProgramFilesx86.empty())
193 TestProg(ProgramFilesx86 + nexttry,
false);
200std::unique_ptr<RWebDisplayHandle>
213 exec =
"$prog $url &";
218 std::string swidth = std::to_string(args.
GetWidth() > 0 ? args.
GetWidth() : 800),
220 sposx = std::to_string(args.
GetX() >= 0 ? args.
GetX() : 0),
221 sposy = std::to_string(args.
GetY() >= 0 ? args.
GetY() : 0);
223 ProcessGeometry(exec, args);
225 std::string rmdir = MakeProfile(exec, args.
IsHeadless());
227 exec = std::regex_replace(exec, std::regex(
"\\$url"), url);
228 exec = std::regex_replace(exec, std::regex(
"\\$width"), swidth);
229 exec = std::regex_replace(exec, std::regex(
"\\$height"), sheight);
230 exec = std::regex_replace(exec, std::regex(
"\\$posx"), sposx);
231 exec = std::regex_replace(exec, std::regex(
"\\$posy"), sposy);
233 if (exec.compare(0,5,
"fork:") == 0) {
244 if (!fargs || (fargs->GetLast()<=0)) {
249 std::vector<char *> argv;
250 argv.push_back((
char *) fProg.c_str());
251 for (
Int_t n = 0;
n <= fargs->GetLast(); ++
n)
252 argv.push_back((
char *)fargs->At(
n)->GetName());
253 argv.push_back(
nullptr);
255 R__LOG_DEBUG(0,
WebGUILog()) <<
"Show web window in browser with posix_spawn:\n" << fProg <<
" " << exec;
258 int status = posix_spawn(&pid, argv[0],
nullptr,
nullptr, argv.data(),
nullptr);
266 return std::make_unique<RWebBrowserHandle>(url, rmdir, pid);
276 exec =
"wmic process call create '"s +
gSystem->
UnixPathName(fProg.c_str()) + exec +
"' | find \"ProcessId\" "s;
278 std::stringstream ss(process_id);
282 ss >> tmp >>
c >> pid;
290 return std::make_unique<RWebBrowserHandle>(url, rmdir, pid);
296 if (exec.rfind(
"&") == exec.length() - 1) {
299 exec.resize(exec.length() - 1);
301 std::vector<char *> argv;
302 std::string firstarg = fProg;
303 auto slashpos = firstarg.find_last_of(
"/\\");
304 if (slashpos != std::string::npos)
305 firstarg.erase(0, slashpos + 1);
306 argv.push_back((
char *)firstarg.c_str());
309 for (
Int_t n = 1;
n <= fargs->GetLast(); ++
n)
310 argv.push_back((
char *)fargs->At(
n)->GetName());
311 argv.push_back(
nullptr);
315 _spawnv(_P_NOWAIT, fProg.c_str(), argv.data());
317 return std::make_unique<RWebBrowserHandle>(url, rmdir,
""s);
325 std::string prog = std::regex_replace(fProg, std::regex(
" "),
"\\ ");
327 std::string prog = fProg;
332 exec = std::regex_replace(exec, std::regex(
"\\$prog"), prog);
336 if (!redirect.empty()) {
337 auto p = exec.length();
338 if (exec.rfind(
"&") == p-1) --p;
339 exec.insert(p,
" >"s + redirect +
" "s);
347 if (!redirect.empty()) {
354 return std::make_unique<RWebBrowserHandle>(url, rmdir, dump_content);
365 TestProg(
"\\Google\\Chrome\\Application\\chrome.exe",
true);
368 TestProg(
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome");
372 TestProg(
"/usr/bin/chromium-browser");
373 TestProg(
"/usr/bin/chrome-browser");
380 fExec =
gEnv->
GetValue(
"WebGui.ChromeInteractive",
"$prog $geometry --no-first-run --app=$url &");
383 fExec =
gEnv->
GetValue(
"WebGui.ChromeInteractive",
"$prog $geometry --no-first-run --incognito --app=\'$url\' &");
402 geometry.append(
"--window-position="s + std::to_string(args.
GetX() >= 0 ? args.
GetX() : 0) +
","s +
403 std::to_string(args.
GetY() >= 0 ? args.
GetY() : 0));
411 exec = std::regex_replace(exec, std::regex(
"\\$geometry"),
geometry);
420 std::string rmdir, profile_arg;
422 if (exec.find(
"$profile") == std::string::npos)
425 const char *chrome_profile =
gEnv->
GetValue(
"WebGui.ChromeProfile",
"");
426 if (chrome_profile && *chrome_profile) {
427 profile_arg = chrome_profile;
433 exec = std::regex_replace(exec, std::regex(
"\\$profile"), profile_arg);
447 TestProg(
"\\Mozilla Firefox\\firefox.exe",
true);
450 TestProg(
"/Applications/Firefox.app/Contents/MacOS/firefox");
460 fExec =
gEnv->
GetValue(
"WebGui.FirefoxInteractive",
"$prog -no-remote $profile $url &");
463 fExec =
gEnv->
GetValue(
"WebGui.FirefoxInteractive",
"$prog --private-window \'$url\' &");
472 std::string rmdir, profile_arg;
474 if (exec.find(
"$profile") == std::string::npos)
477 const char *ff_profile =
gEnv->
GetValue(
"WebGui.FirefoxProfile",
"");
478 const char *ff_profilepath =
gEnv->
GetValue(
"WebGui.FirefoxProfilePath",
"");
480 if (ff_profile && *ff_profile) {
481 profile_arg =
"-P "s + ff_profile;
482 }
else if (ff_profilepath && *ff_profilepath) {
483 profile_arg =
"-profile "s + ff_profilepath;
484 }
else if ((ff_randomprofile > 0) || (batch_mode && (ff_randomprofile >= 0))) {
487 std::string rnd_profile =
"root_ff_profile_"s + std::to_string(
gRandom->
Integer(0x100000));
490 profile_arg =
"-profile "s + profile_dir;
499 exec = std::regex_replace(exec, std::regex(
"\\$profile"), profile_arg);
512 std::unique_ptr<RWebDisplayHandle> handle;
514 auto try_creator = [&](std::unique_ptr<Creator> &creator) {
515 if (!creator || !creator->IsActive())
517 handle = creator->Display(args);
518 return handle ? true :
false;
522 if (try_creator(
FindCreator(
"cef",
"libROOTCefDisplay")))
527 if (try_creator(
FindCreator(
"qt5",
"libROOTQt5WebDisplay")))
537 if (try_creator(
FindCreator(
"chrome",
"ChromeCreator")))
542 if (try_creator(
FindCreator(
"firefox",
"FirefoxCreator")))
552 std::unique_ptr<Creator> creator = std::make_unique<BrowserCreator>(
false, args.
GetCustomExec());
553 try_creator(creator);
555 try_creator(
FindCreator(
"browser",
"BrowserCreator"));
595 std::string _fname = fname;
596 std::transform(_fname.begin(), _fname.end(), _fname.begin(), ::tolower);
598 auto EndsWith = [_fname](
const std::string &suffix) {
599 return (_fname.length() > suffix.length()) ? (0 == _fname.compare (_fname.length() - suffix.length(), suffix.length(), suffix)) :
false;
602 if (EndsWith(
".json")) {
603 std::ofstream ofs(fname);
616 jsrootsys = jsrootsysdflt.
Data();
623 std::string draw_kind;
625 if (EndsWith(
".pdf"))
627 else if (EndsWith(
"shot.png"))
629 else if (EndsWith(
".svg"))
631 else if (EndsWith(
".png"))
633 else if (EndsWith(
".jpg") || EndsWith(
".jpeg"))
635 else if (EndsWith(
".webp"))
647 if (filecont.empty()) {
652 filecont = std::regex_replace(filecont, std::regex(
"\\$draw_width"), std::to_string(
width));
653 filecont = std::regex_replace(filecont, std::regex(
"\\$draw_height"), std::to_string(height));
655 if (strstr(jsrootsys,
"http://") || strstr(jsrootsys,
"https://") || strstr(jsrootsys,
"file://"))
656 filecont = std::regex_replace(filecont, std::regex(
"\\$jsrootsys"), jsrootsys);
658 filecont = std::regex_replace(filecont, std::regex(
"\\$jsrootsys"),
"file://"s + jsrootsys);
660 filecont = std::regex_replace(filecont, std::regex(
"\\$draw_kind"), draw_kind);
662 filecont = std::regex_replace(filecont, std::regex(
"\\$draw_object"), json);
666 dump_name =
"canvasdump";
672 fputs(
"placeholder", df);
678 static bool chrome_tmp_workaround =
false;
691 R__LOG_DEBUG(0,
WebGUILog()) <<
"Using file content_len " << filecont.length() <<
" to produce batch image " << fname;
694 tmp_name =
"canvasbody";
700 fputs(filecont.c_str(), hf);
703 html_name = tmp_name +
".html";
705 if (chrome_tmp_workaround) {
707 auto pos = html_name.
Last(
'/');
712 html_name = homedir + html_name.
Data();
716 std::ofstream ofs(html_name.
Data(), std::ofstream::out);
729 R__LOG_DEBUG(0,
WebGUILog()) <<
"Using " << html_name <<
" content_len " << filecont.length() <<
" to produce batch image " << fname;
732 TString tgtfilename = fname.c_str();
742 if (draw_kind ==
"draw") {
744 wait_file_name = tgtfilename;
746 if (EndsWith(
".pdf"))
772 if (html_name.
Length() > 0)
780 if (draw_kind !=
"draw") {
782 auto dumpcont = handle->GetContent();
787 chrome_tmp_workaround =
true;
791 if (dumpcont.length() < 100) {
796 if (draw_kind ==
"svg") {
797 auto p1 = dumpcont.find(
"<svg");
798 auto p2 = dumpcont.rfind(
"</svg>");
800 std::ofstream ofs(tgtfilename);
801 if ((p1 != std::string::npos) && (p2 != std::string::npos) && (p1 < p2)) {
802 ofs << dumpcont.substr(p1,p2-p1+6);
805 ofs <<
"Failure!!!\n" << dumpcont;
810 auto p1 = dumpcont.rfind(
";base64,");
811 auto p2 = dumpcont.rfind(
"></div>");
813 if ((p1 != std::string::npos) && (p2 != std::string::npos) && (p1 < p2)) {
815 auto base64 = dumpcont.substr(p1+8, p2-p1-9);
818 std::ofstream ofs(tgtfilename, std::ios::binary);
819 ofs.write(binary.Data(), binary.Length());
#define R__LOG_ERROR(...)
#define R__LOG_DEBUG(DEBUGLEVEL,...)
include TDocParser_001 C image html pict1_TDocParser_001 png width
R__EXTERN TRandom * gRandom
R__EXTERN TSystem * gSystem
Holds different arguments for starting browser with RWebDisplayHandle::Display() method.
std::string GetBrowserName() const
Returns configured browser name.
bool IsHeadless() const
returns headless mode
RWebDisplayArgs & SetPageContent(const std::string &cont)
set window url
void SetExtraArgs(const std::string &args)
RWebDisplayArgs & SetUrl(const std::string &url)
set window url
int GetHeight() const
returns preferable web window height
void SetHeadless(bool on=true)
set headless mode
EBrowserKind GetBrowserKind() const
returns configured browser kind, see EBrowserKind for supported values
const std::string & GetExtraArgs() const
void SetStandalone(bool on=true)
Set standalone mode for running browser, default on When disabled, normal browser window (or just tab...
std::string GetFullUrl() const
returns window url with append options
RWebDisplayArgs & SetBrowserKind(const std::string &kind)
Set browser kind as string argument Recognized values: chrome - use Google Chrome web browser,...
std::string GetCustomExec() const
returns custom executable to start web browser
bool IsStandalone() const
Return true if browser should runs in standalone mode.
bool IsLocalDisplay() const
returns true if local display like CEF or Qt5 QWebEngine should be used
void SetRedirectOutput(const std::string &fname="")
@ kFirefox
Mozilla Firefox browser.
@ kCEF
Chromium Embedded Framework - local display with CEF libs.
@ kChrome
Google Chrome browser.
@ kCustom
custom web browser, execution string should be provided
@ kNative
either Chrome or Firefox - both support major functionality
@ kLocal
either CEF or Qt5 - both runs on local display without real http server
@ kQt5
QWebEngine libraries - Chrome code packed in qt5.
const std::string & GetRedirectOutput() const
RWebDisplayArgs & SetSize(int w, int h)
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
std::string fExec
standard execute line
std::unique_ptr< RWebDisplayHandle > Display(const RWebDisplayArgs &args) override
Display given URL in web browser.
std::string fBatchExec
batch execute line
std::string fProg
browser executable
void TestProg(const std::string &nexttry, bool check_std_paths=false)
Check if browser executable exists and can be used.
BrowserCreator(bool custom=true, const std::string &exec="")
Class to handle starting of web-browsers like Chrome or Firefox.
void ProcessGeometry(std::string &, const RWebDisplayArgs &args) override
Replace $geometry placeholder with geometry settings Also RWebDisplayArgs::GetExtraArgs() are appende...
ChromeCreator()
Constructor.
std::string MakeProfile(std::string &exec, bool) override
Handle profile argument.
FirefoxCreator()
Constructor.
std::string MakeProfile(std::string &exec, bool batch) override
Create Firefox profile to run independent browser window.
static std::map< std::string, std::unique_ptr< Creator > > & GetMap()
Static holder of registered creators of web displays.
static bool ProduceImage(const std::string &fname, const std::string &json, int width=800, int height=600)
Produce image file using JSON data as source Invokes JSROOT drawing functionality in headless browser...
static bool DisplayUrl(const std::string &url)
Display provided url in configured web browser.
static std::unique_ptr< RWebDisplayHandle > Display(const RWebDisplayArgs &args)
Create web display.
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.
static TString Decode(const char *data)
Decode a base64 string date into a generic TString.
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
static char * ReadFileContent(const char *filename, Int_t &len)
Reads content of file from the disk.
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
static const TString & GetDataDir()
Get the data directory in the installation. Static utility function.
virtual void SetSeed(ULong_t seed=0)
Set the random generator seed.
virtual UInt_t Integer(UInt_t imax)
Returns a random integer uniformly distributed on the interval [ 0, imax-1 ].
void Clear()
Clear string without changing its capacity.
const char * Data() const
Ssiz_t Last(char c) const
Find last occurrence of a character c.
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
TString & Remove(Ssiz_t pos)
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
virtual Bool_t ExpandPathName(TString &path)
Expand a pathname getting rid of special shell characters like ~.
virtual const char * Getenv(const char *env)
Get environment variable.
virtual int mkdir(const char *name, Bool_t recursive=kFALSE)
Make a file system directory.
virtual Int_t Exec(const char *shellcmd)
Execute a command.
virtual int Load(const char *module, const char *entry="", Bool_t system=kFALSE)
Load a shared library.
virtual const char * PrependPathName(const char *dir, TString &name)
Concatenate a directory and a file name.
virtual Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists)
Returns FALSE if one can access a file using the specified access mode.
virtual FILE * TempFileName(TString &base, const char *dir=nullptr)
Create a secure temporary file by appending a unique 6 letter string to base.
virtual std::string GetHomeDirectory(const char *userName=nullptr) const
Return the user's home directory.
virtual const char * UnixPathName(const char *unixpathname)
Convert from a local pathname to a Unix pathname.
virtual int Rename(const char *from, const char *to)
Rename a file.
virtual TString GetFromPipe(const char *command)
Execute command and return output in TString.
virtual Bool_t IsAbsoluteFileName(const char *dir)
Return true if dir is an absolute pathname.
virtual const char * WorkingDirectory()
Return working directory.
virtual int Unlink(const char *name)
Unlink, i.e.
virtual const char * TempDirectory() const
Return a user configured or systemwide directory to create temporary files in.
RLogChannel & WebGUILog()
Log channel for WebGUI diagnostics.
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...