Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[webcanvas] Improving usability with stressGraphics tests #17072

Merged
merged 12 commits into from
Nov 27, 2024
3 changes: 2 additions & 1 deletion graf2d/gpad/src/TCanvas.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -2710,7 +2710,8 @@ Bool_t TCanvas::SaveAll(const std::vector<TPad *> &pads, const char *filename, O
return (Bool_t) gROOT->ProcessLine(cmd);
}

::Warning("TCanvas::SaveAll", "TWebCanvas does not support image format %s - use normal ROOT functionality", fname.Data());
if ((ext != "root") && (ext != "xml"))
::Warning("TCanvas::SaveAll", "TWebCanvas does not support image format %s - using normal ROOT functionality", fname.Data());
}

// store all pads into single PDF/PS files
Expand Down
55 changes: 31 additions & 24 deletions gui/webdisplay/src/RWebDisplayHandle.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

#include "RConfigure.h"
#include "TSystem.h"
#include "TRandom.h"
#include "TRandom3.h"
#include "TString.h"
#include "TObjArray.h"
#include "THttpServer.h"
Expand Down Expand Up @@ -563,7 +563,8 @@ std::string RWebDisplayHandle::ChromeCreator::MakeProfile(std::string &exec, boo
if (chrome_profile && *chrome_profile) {
profile_arg = chrome_profile;
} else {
gRandom->SetSeed(0);
TRandom3 rnd;
rnd.SetSeed(0);
profile_arg = gSystem->TempDirectory();
#ifdef _MSC_VER
char slash = '\\';
Expand All @@ -572,7 +573,7 @@ std::string RWebDisplayHandle::ChromeCreator::MakeProfile(std::string &exec, boo
#endif
if (!profile_arg.empty() && (profile_arg[profile_arg.length()-1] != slash))
profile_arg += slash;
profile_arg += "root_chrome_profile_"s + std::to_string(gRandom->Integer(0x100000));
profile_arg += "root_chrome_profile_"s + std::to_string(rnd.Integer(0x100000));

rmdir = profile_arg;
}
Expand Down Expand Up @@ -644,8 +645,8 @@ std::string RWebDisplayHandle::FirefoxCreator::MakeProfile(std::string &exec, bo
} else if (ff_profilepath && *ff_profilepath) {
profile_arg = "-profile "s + ff_profilepath;
} else if (ff_randomprofile > 0) {

gRandom->SetSeed(0);
TRandom3 rnd;
rnd.SetSeed(0);
std::string profile_dir = gSystem->TempDirectory();

#ifdef _MSC_VER
Expand All @@ -655,7 +656,7 @@ std::string RWebDisplayHandle::FirefoxCreator::MakeProfile(std::string &exec, bo
#endif
if (!profile_dir.empty() && (profile_dir[profile_dir.length()-1] != slash))
profile_dir += slash;
profile_dir += "root_ff_profile_"s + std::to_string(gRandom->Integer(0x100000));
profile_dir += "root_ff_profile_"s + std::to_string(rnd.Integer(0x100000));

profile_arg = "-profile "s + profile_dir;

Expand Down Expand Up @@ -1199,9 +1200,11 @@ bool RWebDisplayHandle::ProduceImages(const std::vector<std::string> &fnames, co
if (chrome_tmp_workaround) {
std::string homedir = gSystem->GetHomeDirectory();
auto pos = html_name.Last('/');
if (pos == kNPOS)
html_name = TString::Format("/random%d.html", gRandom->Integer(1000000));
else
if (pos == kNPOS) {
TRandom3 rnd;
rnd.SetSeed(0);
html_name = TString::Format("/random%d.html", rnd.Integer(1000000));
} else
html_name.Remove(0, pos);
html_name = homedir + html_name.Data();
gSystem->Unlink(html_name.Data());
Expand Down Expand Up @@ -1294,7 +1297,6 @@ bool RWebDisplayHandle::ProduceImages(const std::vector<std::string> &fnames, co
// chrome creates dummy html file with mostly no content
// problem running chrome from /tmp directory, lets try work from home directory

printf("Handle chrome workaround\n");
chrome_tmp_workaround = true;
goto try_again;
}
Expand All @@ -1315,29 +1317,34 @@ bool RWebDisplayHandle::ProduceImages(const std::vector<std::string> &fnames, co
p = p2 + 6;
std::ofstream ofs(fnames[n]);
if ((p1 != std::string::npos) && (p2 != std::string::npos) && (p1 < p2)) {
ofs << dumpcont.substr(p1, p2-p1+6);
::Info("ProduceImages", "SVG file %s size %d bytes has been created", fnames[n].c_str(), (int) (p2-p1+6));
if (p2 - p1 > 10) {
ofs << dumpcont.substr(p1, p2 - p1 + 6);
::Info("ProduceImages", "SVG file %s size %d bytes has been created", fnames[n].c_str(), (int) (p2 - p1 + 6));
} else {
::Error("ProduceImages", "Failure producing %s", fnames[n].c_str());
}
} else {
R__LOG_ERROR(WebGUILog()) << "Fail to extract SVG from HTML dump " << dump_name;
ofs << "Failure!!!\n" << dumpcont;
::Error("ProduceImages", "Fail to extract %s from HTML dump", fnames[n].c_str());
return false;
}
} else {
auto p1 = dumpcont.find(";base64,", p);
auto p0 = dumpcont.find("<img src=", p);
auto p1 = dumpcont.find(";base64,", p0 + 8);
auto p2 = dumpcont.find("></div>", p1 + 4);
p = p2 + 5;

if ((p1 != std::string::npos) && (p2 != std::string::npos) && (p1 < p2)) {
if ((p0 != std::string::npos) && (p1 != std::string::npos) && (p2 != std::string::npos) && (p1 < p2)) {
auto base64 = dumpcont.substr(p1+8, p2-p1-9);
auto binary = TBase64::Decode(base64.c_str());

std::ofstream ofs(fnames[n], std::ios::binary);
ofs.write(binary.Data(), binary.Length());

::Info("ProduceImages", "Image file %s size %d bytes has been created", fnames[n].c_str(), (int) binary.Length());
if ((base64 == "failure") || (base64.length() < 10)) {
::Error("ProduceImages", "Failure producing %s", fnames[n].c_str());
} else {
auto binary = TBase64::Decode(base64.c_str());
std::ofstream ofs(fnames[n], std::ios::binary);
ofs.write(binary.Data(), binary.Length());
::Info("ProduceImages", "Image file %s size %d bytes has been created", fnames[n].c_str(), (int) binary.Length());
}
} else {
R__LOG_ERROR(WebGUILog()) << "Fail to extract image from dump HTML code " << dump_name;

::Error("ProduceImages", "Fail to extract %s from HTML dump", fnames[n].c_str());
return false;
}
}
Expand Down
10 changes: 5 additions & 5 deletions gui/webdisplay/src/RWebWindowsManager.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#include "TString.h"
#include "TApplication.h"
#include "TTimer.h"
#include "TRandom.h"
#include "TRandom3.h"
#include "TError.h"
#include "TROOT.h"
#include "TEnv.h"
Expand Down Expand Up @@ -534,13 +534,13 @@ bool RWebWindowsManager::CreateServer(bool with_http)
if ((http_timer > 0) && !IsUseHttpThread())
fServer->SetTimer(http_timer);

TRandom3 rnd;

if (http_port < 0) {
ntry = 0;
} else {

if (http_port == 0)
gRandom->SetSeed(0);

rnd.SetSeed(0);
if (http_max - http_min < ntry)
ntry = http_max - http_min;
}
Expand All @@ -558,7 +558,7 @@ bool RWebWindowsManager::CreateServer(bool with_http)
return false;
}

http_port = (int)(http_min + (http_max - http_min) * gRandom->Rndm(1));
http_port = (int)(http_min + (http_max - http_min) * rnd.Rndm(1));
}

TString engine, url;
Expand Down
55 changes: 44 additions & 11 deletions gui/webgui6/src/TWebCanvas.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
#include "TEnv.h"
#include "TError.h"
#include "TGraph.h"
#include "TGraphPolar.h"
#include "TGraphPolargram.h"
#include "TGraph2D.h"
#include "TGaxis.h"
#include "TScatter.h"
Expand Down Expand Up @@ -672,7 +674,7 @@ void TWebCanvas::CreatePadSnapshot(TPadWebSnapshot &paddata, TPad *pad, Long64_t
TObject *obj = nullptr;
TFrame *frame = nullptr;
TPaveText *title = nullptr;
bool need_frame = false, has_histo = false, need_palette = false;
bool need_frame = false, has_histo = false, has_polar = false, need_palette = false;
std::string need_title;

auto checkNeedPalette = [](TH1* hist, const TString &opt) {
Expand Down Expand Up @@ -728,10 +730,14 @@ void TWebCanvas::CreatePadSnapshot(TPadWebSnapshot &paddata, TPad *pad, Long64_t
need_title = obj->GetTitle();
if (checkNeedPalette(static_cast<TH1*>(obj), opt))
need_palette = true;
} else if (obj->InheritsFrom(TGraphPolar::Class())) {
if (!has_polar)
need_title = obj->GetTitle();
has_polar = true;
} else if (obj->InheritsFrom(TGraph::Class())) {
if (opt.Contains("A")) {
need_frame = true;
if (!has_histo && (strlen(obj->GetTitle()) > 0))
if (!has_histo && (strlen(obj->GetTitle()) > 0) && !obj->TestBit(TH1::kNoTitle))
need_title = obj->GetTitle();
}
} else if (obj->InheritsFrom(TGraph2D::Class())) {
Expand All @@ -742,9 +748,11 @@ void TWebCanvas::CreatePadSnapshot(TPadWebSnapshot &paddata, TPad *pad, Long64_t
if (strlen(obj->GetTitle()) > 0)
need_title = obj->GetTitle();
} else if (obj->InheritsFrom(TF1::Class())) {
need_frame = !obj->InheritsFrom(TF2::Class());
if (!has_histo && (strlen(obj->GetTitle()) > 0))
need_title = obj->GetTitle();
if (!opt.Contains("SAME")) {
need_frame = !obj->InheritsFrom(TF2::Class());
if (!has_histo && (strlen(obj->GetTitle()) > 0))
need_title = obj->GetTitle();
}
} else if (obj->InheritsFrom(TPaveText::Class())) {
if (strcmp(obj->GetName(), "title") == 0)
title = static_cast<TPaveText *>(obj);
Expand Down Expand Up @@ -820,7 +828,7 @@ void TWebCanvas::CreatePadSnapshot(TPadWebSnapshot &paddata, TPad *pad, Long64_t

auto create_stats = [&]() {
TPaveStats *stats = nullptr;
if ((gStyle->GetOptStat() > 0) && CanCreateObject("TPaveStats")) {
if (CanCreateObject("TPaveStats")) {
stats = new TPaveStats(
gStyle->GetStatX() - gStyle->GetStatW(),
gStyle->GetStatY() - gStyle->GetStatH(),
Expand Down Expand Up @@ -869,9 +877,11 @@ void TWebCanvas::CreatePadSnapshot(TPadWebSnapshot &paddata, TPad *pad, Long64_t
}
}

if (!stats && has_tf1 && gr && !gr->TestBit(TGraph::kNoStats)) {
if (!stats && has_tf1 && gr && !gr->TestBit(TGraph::kNoStats) && (gStyle->GetOptFit() > 0)) {
stats = create_stats();
if (stats) {
stats->SetOptStat(0);
stats->SetOptFit(gStyle->GetOptFit());
stats->SetParent(funcs);
funcs->Add(stats);
}
Expand Down Expand Up @@ -935,7 +945,7 @@ void TWebCanvas::CreatePadSnapshot(TPadWebSnapshot &paddata, TPad *pad, Long64_t
TString o = hopt;
o.ToUpper();

if (!stats && (first_obj || o.Contains("SAMES"))) {
if (!stats && (first_obj || o.Contains("SAMES")) && (gStyle->GetOptStat() > 0)) {
stats = create_stats();
if (stats) {
stats->SetParent(hist);
Expand All @@ -956,6 +966,25 @@ void TWebCanvas::CreatePadSnapshot(TPadWebSnapshot &paddata, TPad *pad, Long64_t
if (hist->GetDimension() == 2)
check_cutg_in_options(iter.GetOption());

first_obj = false;
} else if (obj->InheritsFrom(TGraphPolar::Class())) {
flush_master();

TGraphPolar *polar = static_cast<TGraphPolar *>(obj);

check_graph_funcs(polar);

TString gropt = iter.GetOption();

if (!IsReadOnly() && (first_obj || (gropt.Index("A", 0, TString::kIgnoreCase) != kNPOS) || polar->GetOptionAxis()) && !polar->GetPolargram()) {
auto gram = new TGraphPolargram("Polargram",0, 10, 0, 2*TMath::Pi());
gram->SetBit(TGraphPolargram::kLabelOrtho, gropt.Index("O", 0, TString::kIgnoreCase) != kNPOS);
polar->SetPolargram(gram);
polar->SetOptionAxis(kFALSE);
}

paddata.NewPrimitive(obj, gropt.Data()).SetSnapshot(TWebSnapshot::kObject, obj);

first_obj = false;
} else if (obj->InheritsFrom(TGraph::Class())) {
flush_master();
Expand All @@ -968,7 +997,7 @@ void TWebCanvas::CreatePadSnapshot(TPadWebSnapshot &paddata, TPad *pad, Long64_t

// ensure histogram exists on server to draw it properly on clients side
if (!IsReadOnly() && (first_obj || gropt.Index("A", 0, TString::kIgnoreCase) != kNPOS ||
(gropt.Index("X+", 0, TString::kIgnoreCase) != kNPOS) || (gropt.Index("X+", 0, TString::kIgnoreCase) != kNPOS)))
(gropt.Index("X+", 0, TString::kIgnoreCase) != kNPOS) || (gropt.Index("Y+", 0, TString::kIgnoreCase) != kNPOS)))
gr->GetHistogram();

paddata.NewPrimitive(obj, gropt.Data()).SetSnapshot(TWebSnapshot::kObject, obj);
Expand All @@ -986,9 +1015,10 @@ void TWebCanvas::CreatePadSnapshot(TPadWebSnapshot &paddata, TPad *pad, Long64_t
TString gropt = iter.GetOption();
gropt.ToUpper();
Bool_t zscale = gropt.Contains("TRI1") || gropt.Contains("TRI2") || gropt.Contains("COL");
Bool_t real_draw = gropt.Contains("TRI") || gropt.Contains("LINE") || gropt.Contains("ERR") || gropt.Contains("P0");
Bool_t cont5_draw = gropt.Contains("CONT5");
Bool_t real_draw = gropt.Contains("TRI") || gropt.Contains("LINE") || gropt.Contains("ERR") || gropt.Contains("P") || cont5_draw;

TString hopt = !real_draw ? iter.GetOption() : (zscale ? "lego2z" : "lego2");
TString hopt = !real_draw ? iter.GetOption() : (cont5_draw ? "" : (zscale ? "lego2z" : "lego2"));
if (title) hopt.Append(";;use_pad_title");

// if gr2d not draw - let create histogram with correspondent content
Expand Down Expand Up @@ -2837,6 +2867,9 @@ TObject *TWebCanvas::FindPrimitive(const std::string &sid, int idcnt, TPad *pad,
obj = col->FindObject(funcname.c_str());
else
obj = col->At(std::stoi(funcname));
} else if (kind.compare("polargram") == 0) {
auto polar = dynamic_cast<TGraphPolar *>(obj);
obj = polar ? polar->GetPolargram() : nullptr;
} else if (kind.compare(0,7,"graphs_") == 0) {
TList *graphs = mg ? mg->GetListOfGraphs() : nullptr;
obj = graphs ? graphs->At(std::stoi(kind.substr(7))) : nullptr;
Expand Down
Loading
Loading