From 8786424901b6e262cd5c9d9ad085b1696f59106d Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 21 Apr 2026 18:10:43 +0200 Subject: [PATCH 01/15] Correctly store sub-pad in TImageDump Subpad has offset in coordinate system which can be calculated when new page is started --- graf2d/postscript/inc/TImageDump.h | 1 + graf2d/postscript/src/TImageDump.cxx | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/graf2d/postscript/inc/TImageDump.h b/graf2d/postscript/inc/TImageDump.h index 4f0d46d238796..51ff0759304cc 100644 --- a/graf2d/postscript/inc/TImageDump.h +++ b/graf2d/postscript/inc/TImageDump.h @@ -23,6 +23,7 @@ class TImageDump : public TVirtualPS { protected: TImage *fImage{nullptr}; ///< Image Int_t fType{0}; ///< PostScript workstation type + Int_t fX0{0}, fY0{0}; ///< offset of selected pad to canvas Int_t XtoPixel(Double_t x); Int_t YtoPixel(Double_t y); diff --git a/graf2d/postscript/src/TImageDump.cxx b/graf2d/postscript/src/TImageDump.cxx index c13bb0d465fde..07dc5769b0007 100644 --- a/graf2d/postscript/src/TImageDump.cxx +++ b/graf2d/postscript/src/TImageDump.cxx @@ -836,12 +836,18 @@ void TImageDump::DrawDashPolyLine(Int_t nn, TPoint *xy, UInt_t nDash, void TImageDump::NewPage() { + fX0 = fY0 = 0; if (gPad && fImage) { - UInt_t w = UInt_t(gPad->GetWw()*gPad->GetWNDC()) * gStyle->GetImageScaling(); - UInt_t h = UInt_t(gPad->GetWh()*gPad->GetHNDC()) * gStyle->GetImageScaling(); + UInt_t w = gPad->GetWw() * gStyle->GetImageScaling(); + UInt_t h = gPad->GetWh() * gStyle->GetImageScaling(); + if (gPad != gPad->GetMother()) { + fX0 = gPad->XtoAbsPixel(gPad->GetX1())* gStyle->GetImageScaling(); + fY0 = gPad->YtoAbsPixel(gPad->GetY2())* gStyle->GetImageScaling(); + w = w * gPad->GetAbsWNDC(); + h = h * gPad->GetAbsHNDC(); + } fImage->DrawRectangle(0, 0, w, h, "#ffffffff"); } - return; } //////////////////////////////////////////////////////////////////////////////// @@ -994,7 +1000,7 @@ void TImageDump::SetColor(Float_t /*r*/, Float_t /*g*/, Float_t /*b*/) Int_t TImageDump::XtoPixel(Double_t x) { - return gPad->XtoAbsPixel(x)*gStyle->GetImageScaling(); + return gPad->XtoAbsPixel(x)*gStyle->GetImageScaling() - fX0; } //////////////////////////////////////////////////////////////////////////////// @@ -1002,5 +1008,5 @@ Int_t TImageDump::XtoPixel(Double_t x) Int_t TImageDump::YtoPixel(Double_t y) { - return gPad->YtoAbsPixel(y)*gStyle->GetImageScaling(); + return gPad->YtoAbsPixel(y)*gStyle->GetImageScaling() - fY0; } From 5d9b5675712e64ba4c7e8e0165208590146acd81 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 22 Apr 2026 09:52:48 +0200 Subject: [PATCH 02/15] [timage] add DrawTextOnPad method Specify exactly pad which will be used for text painting It used to correctly scale text and to check clipping rules. Extra offset x/y needed when sub-pad is stored and graphical coordinates of pad differs from absolute pad coordinates in the canvas --- graf2d/graf/inc/TImage.h | 1 + graf2d/graf/src/TImage.cxx | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/graf2d/graf/inc/TImage.h b/graf2d/graf/inc/TImage.h index c23854b106da4..6d5fd14b30a47 100644 --- a/graf2d/graf/inc/TImage.h +++ b/graf2d/graf/inc/TImage.h @@ -201,6 +201,7 @@ friend TImage operator/(const TImage &i1, const TImage &s2); const char * /*color*/ = nullptr, const char * /*font*/ = "fixed", EText3DType /*type*/ = TImage::kPlain, const char * /*fore_file*/ = nullptr, Float_t /*angle*/ = 0) { } virtual void DrawText(TText * /*text*/, Int_t /*x*/ = 0, Int_t /*y*/ = 0) { } + virtual void DrawTextOnPad(TText * /*text*/, Int_t /*x*/ = 0, Int_t /*y*/ = 0, TVirtualPad * /* pad */ = nullptr, Int_t /* offx */ = 0, Int_t /* offy */ = 0); virtual void FillPolygon(UInt_t /*npt*/, TPoint * /*ppt*/, const char * /*col*/ = "#000000", const char * /*stipple*/ = nullptr, UInt_t /*w*/ = 16, UInt_t /*h*/ = 16) {} virtual void FillPolygon(UInt_t /*npt*/, TPoint * /*ppt*/, TImage * /*tile*/) {} diff --git a/graf2d/graf/src/TImage.cxx b/graf2d/graf/src/TImage.cxx index 632a37641de1b..1e6796183bd7a 100644 --- a/graf2d/graf/src/TImage.cxx +++ b/graf2d/graf/src/TImage.cxx @@ -187,5 +187,16 @@ TImage *TImage::Open(char **data) } +//////////////////////////////////////////////////////////////////////////////// +/// Draw text on specified pad, check pad clipping rules + +void TImage::DrawTextOnPad(TText *text, Int_t x, Int_t y, TVirtualPad *, Int_t, Int_t) +{ + // call simple DrawText to ensure minimal backward compatibility + + DrawText(text, x, y); +} + + TImage operator+(const TImage &i1, const TImage &i2) { TImage ret(i1); ret.Append(&i2, "+"); return ret; } TImage operator/(const TImage &i1, const TImage &i2) { TImage ret(i1); ret.Append(&i2, "/"); return ret; } From 943fa0e20f8dbba301fd48aed4558ada5255c4ea Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 22 Apr 2026 09:52:53 +0200 Subject: [PATCH 03/15] [asimage] implement DrawTextOnPad method Most crucial change is correct clipping rule check using provided offset. --- graf2d/asimage/inc/TASImage.h | 3 +- graf2d/asimage/src/TASImage.cxx | 49 ++++++++++++++++++++------------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/graf2d/asimage/inc/TASImage.h b/graf2d/asimage/inc/TASImage.h index 358b59a68e35b..9085b38773fb5 100644 --- a/graf2d/asimage/inc/TASImage.h +++ b/graf2d/asimage/inc/TASImage.h @@ -47,7 +47,7 @@ class TASImage : public TImage { inline Int_t Idx(Int_t idx); void FillRectangleInternal(UInt_t col, Int_t x, Int_t y, UInt_t width, UInt_t height); void DrawTextTTF(Int_t x, Int_t y, const char *text, Int_t size, UInt_t color, const char *font_name, Float_t angle); - void DrawGlyph(void *bitmap, UInt_t color, Int_t x, Int_t y); + void DrawGlyph(void *bitmap, UInt_t color, Int_t x, Int_t y, TVirtualPad *clippad = nullptr, Int_t offx = 0, Int_t offy = 0); void SetDefaults(); void CreateThumbnail(); void DestroyImage(); @@ -138,6 +138,7 @@ class TASImage : public TImage { const char *color = nullptr, const char *font = "fixed", EText3DType type = TImage::kPlain, const char *fore_file = nullptr, Float_t angle = 0) override; void DrawText(TText *text, Int_t x = 0, Int_t y = 0) override; + void DrawTextOnPad(TText *text, Int_t x = 0, Int_t y = 0, TVirtualPad *pad = nullptr, Int_t offx = 0, Int_t offy = 0) override; // Vector graphics void BeginPaint(Bool_t fast = kTRUE) override; diff --git a/graf2d/asimage/src/TASImage.cxx b/graf2d/asimage/src/TASImage.cxx index 01a937db61104..be4af4eb41b2b 100644 --- a/graf2d/asimage/src/TASImage.cxx +++ b/graf2d/asimage/src/TASImage.cxx @@ -5616,11 +5616,8 @@ void TASImage::DrawWideLine(UInt_t x1, UInt_t y1, UInt_t x2, UInt_t y2, //////////////////////////////////////////////////////////////////////////////// /// Draw glyph bitmap. -void TASImage::DrawGlyph(void *bitmap, UInt_t color, Int_t bx, Int_t by) +void TASImage::DrawGlyph(void *bitmap, UInt_t color, Int_t bx, Int_t by, TVirtualPad *clippad, Int_t offx, Int_t offy) { - if (!InitImage("DrawGlyph")) { - return; - } static UInt_t col[5]; Int_t x, y, yy, y0, xx; Bool_t has_alpha = (color & 0xff000000) != 0xff000000; @@ -5674,15 +5671,15 @@ void TASImage::DrawGlyph(void *bitmap, UInt_t color, Int_t bx, Int_t by) yy = y0; ARGB32 acolor; - Int_t clipx1=0, clipx2=0, clipy1=0, clipy2=0; + Int_t clipx1 = 0, clipx2 = 0, clipy1 = 0, clipy2 = 0; Bool_t noClip = kTRUE; - if (gPad) { + if (clippad) { Float_t is = gStyle->GetImageScaling(); - clipx1 = gPad->XtoAbsPixel(gPad->GetX1())*is; - clipx2 = gPad->XtoAbsPixel(gPad->GetX2())*is; - clipy1 = gPad->YtoAbsPixel(gPad->GetY1())*is; - clipy2 = gPad->YtoAbsPixel(gPad->GetY2())*is; + clipx1 = clippad->XtoAbsPixel(clippad->GetX1())*is - offx; + clipx2 = clippad->XtoAbsPixel(clippad->GetX2())*is - offx; + clipy1 = clippad->YtoAbsPixel(clippad->GetY1())*is - offy; + clipy2 = clippad->YtoAbsPixel(clippad->GetY2())*is - offy; noClip = kFALSE; } @@ -5719,27 +5716,38 @@ void TASImage::DrawGlyph(void *bitmap, UInt_t color, Int_t bx, Int_t by) void TASImage::DrawText(TText *text, Int_t x, Int_t y) { - if (!text) return; - if (!gPad) + if (gPad) + DrawTextOnPad(text, x, y, gPad, 0, 0); +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Draw text at the pixel position (x,y) checking clip on pad. + +void TASImage::DrawTextOnPad(TText *text, Int_t x, Int_t y, TVirtualPad *pad, Int_t offx, Int_t offy) +{ + if (!text) return; - if (!InitImage("DrawText")) { + if (!InitImage("DrawTextOnPad")) return; - } if (!TTF::IsInitialized()) TTF::Init(); // set text font TTF::SetTextFont(text->GetTextFont()); - Int_t wh = gPad->XtoPixel(gPad->GetX2()); - Int_t hh = gPad->YtoPixel(gPad->GetY1()); + Int_t wh = 100, hh = 100; + if (pad) { + wh = pad->XtoPixel(pad->GetX2()); + hh = pad->YtoPixel(pad->GetY1()); + } // set text size Float_t ttfsize; if (wh < hh) { - ttfsize = text->GetTextSize()*wh; + ttfsize = text->GetTextSize() * wh; } else { - ttfsize = text->GetTextSize()*hh; + ttfsize = text->GetTextSize() * hh; } TTF::SetTextSize(ttfsize*kScale); @@ -5847,7 +5855,7 @@ void TASImage::DrawText(TText *text, Int_t x, Int_t y) Int_t bx = x - ftal.x + bitmap->left; Int_t by = y + ftal.y - bitmap->top; - DrawGlyph(source, color, bx, by); + DrawGlyph(source, color, bx, by, pad, offx, offy); } } @@ -5857,6 +5865,9 @@ void TASImage::DrawText(TText *text, Int_t x, Int_t y) void TASImage::DrawTextTTF(Int_t x, Int_t y, const char *text, Int_t size, UInt_t color, const char *font_name, Float_t angle) { + if (!InitImage("DrawTextTTF")) + return; + if (!TTF::IsInitialized()) TTF::Init(); TTF::SetTextFont(font_name); From 13b1f4f91e9bd55fed8ffd25597275a40d139cf1 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 22 Apr 2026 09:55:26 +0200 Subject: [PATCH 04/15] Use DrawTextOnPad in TImageDump text drawing Important is providing offsets for pad --- graf2d/postscript/src/TImageDump.cxx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/graf2d/postscript/src/TImageDump.cxx b/graf2d/postscript/src/TImageDump.cxx index 07dc5769b0007..96ada4f9f9866 100644 --- a/graf2d/postscript/src/TImageDump.cxx +++ b/graf2d/postscript/src/TImageDump.cxx @@ -858,9 +858,8 @@ void TImageDump::NewPage() void TImageDump::Text(Double_t x, Double_t y, const char *chars) { - if (!gPad || !fImage) { + if (!gPad || !fImage) return; - } fImage->BeginPaint(); @@ -870,7 +869,7 @@ void TImageDump::Text(Double_t x, Double_t y, const char *chars) t.SetTextAlign(fTextAlign); t.SetTextAngle(fTextAngle); t.SetTextColor(fTextColor); - fImage->DrawText(&t, XtoPixel(x), YtoPixel(y)); + fImage->DrawTextOnPad(&t, XtoPixel(x), YtoPixel(y), gPad, fX0, fY0); } //////////////////////////////////////////////////////////////////////////////// @@ -881,9 +880,8 @@ void TImageDump::Text(Double_t x, Double_t y, const char *chars) void TImageDump::Text(Double_t x, Double_t y, const wchar_t *chars) { - if (!gPad || !fImage) { + if (!gPad || !fImage) return; - } fImage->BeginPaint(); @@ -893,7 +891,7 @@ void TImageDump::Text(Double_t x, Double_t y, const wchar_t *chars) t.SetTextAlign(fTextAlign); t.SetTextAngle(fTextAngle); t.SetTextColor(fTextColor); - fImage->DrawText(&t, XtoPixel(x), YtoPixel(y)); + fImage->DrawTextOnPad(&t, XtoPixel(x), YtoPixel(y), gPad, fX0, fY0); } //////////////////////////////////////////////////////////////////////////////// From c2587b05cdaa6eb035db86c886a900cfcce01d47 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 22 Apr 2026 15:37:41 +0200 Subject: [PATCH 05/15] [asimage] fix seg fault when negative coordinate specified Index was checked on max value, but not on negative value --- graf2d/asimage/src/TASImage.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graf2d/asimage/src/TASImage.cxx b/graf2d/asimage/src/TASImage.cxx index be4af4eb41b2b..cef7d1b40e2e5 100644 --- a/graf2d/asimage/src/TASImage.cxx +++ b/graf2d/asimage/src/TASImage.cxx @@ -6760,5 +6760,5 @@ Bool_t TASImage::SetJpegDpi(const char *name, UInt_t set) Int_t TASImage::Idx(Int_t idx) { // The size of arrays like fImage->alt.argb32 is fImage->width*fImage->height - return TMath::Min(idx,(Int_t)(fImage->width*fImage->height)); + return TMath::Max(0, TMath::Min(idx,(Int_t)(fImage->width*fImage->height))); } From 1171c875da94d7df550a5386ecbcfb33283de882 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 22 Apr 2026 14:00:17 +0200 Subject: [PATCH 06/15] [ttf] add CleanupGlyps method It ensure that temporary allocated data removed shortly after string rendering. Otherwise at the end some part can remain. Also use it internally in methods like TTF::GetTextExtent Made TTF::Init() reentrant --- graf2d/graf/inc/TTF.h | 1 + graf2d/graf/src/TTF.cxx | 45 +++++++++++++++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/graf2d/graf/inc/TTF.h b/graf2d/graf/inc/TTF.h index 864ce06b4f027..088d447c39e8a 100644 --- a/graf2d/graf/inc/TTF.h +++ b/graf2d/graf/inc/TTF.h @@ -97,6 +97,7 @@ TTF helper class containing glyphs description. static void PrepareString(const char *string); static void PrepareString(const wchar_t *string); static void SetRotationMatrix(Float_t angle); + static void CleanupGlyphs(); public: TTF() { } diff --git a/graf2d/graf/src/TTF.cxx b/graf2d/graf/src/TTF.cxx index 758bb98c192f0..b7158d7857170 100644 --- a/graf2d/graf/src/TTF.cxx +++ b/graf2d/graf/src/TTF.cxx @@ -63,6 +63,9 @@ TTF::~TTF() void TTF::Init() { + if (fgInit) + return; + fgInit = kTRUE; // initialize FTF library @@ -80,13 +83,21 @@ void TTF::Init() void TTF::Cleanup() { - if (!fgInit) return; + if (!fgInit) + return; + + CleanupGlyphs(); for (int i = 0; i < fgFontCount; i++) { delete [] fgFontName[i]; + fgFontName[i] = nullptr; + FT_Done_Face(fgFace[i]); } - if (fgRotMatrix) delete fgRotMatrix; + if (fgRotMatrix) { + delete fgRotMatrix; + fgRotMatrix = nullptr; + } FT_Done_FreeType(fgLibrary); fgInit = kFALSE; @@ -152,7 +163,7 @@ void TTF::ComputeTrailingBlanksWidth(Int_t n) void TTF::GetTextExtent(UInt_t &w, UInt_t &h, char *text) { - if (!fgInit) Init(); + Init(); SetRotationMatrix(0); PrepareString(text); @@ -161,6 +172,7 @@ void TTF::GetTextExtent(UInt_t &w, UInt_t &h, char *text) Int_t Yoff = 0; if (fgCBox.yMin < 0) Yoff = -fgCBox.yMin; w = fgCBox.xMax + Xoff + GetTrailingBlanksWidth(); h = fgCBox.yMax + Yoff; + CleanupGlyphs(); } //////////////////////////////////////////////////////////////////////////////// @@ -168,12 +180,13 @@ void TTF::GetTextExtent(UInt_t &w, UInt_t &h, char *text) void TTF::GetTextAdvance(UInt_t &a, char *text) { - if (!fgInit) Init(); + Init(); SetRotationMatrix(0); PrepareString(text); LayoutGlyphs(); - a = GetWidth()>>6; + a = GetWidth() >> 6; + CleanupGlyphs(); } //////////////////////////////////////////////////////////////////////////////// @@ -181,7 +194,7 @@ void TTF::GetTextAdvance(UInt_t &a, char *text) void TTF::GetTextExtent(UInt_t &w, UInt_t &h, wchar_t *text) { - if (!fgInit) Init(); + Init(); SetRotationMatrix(0); PrepareString(text); @@ -190,6 +203,7 @@ void TTF::GetTextExtent(UInt_t &w, UInt_t &h, wchar_t *text) Int_t Yoff = 0; if (fgCBox.yMin < 0) Yoff = -fgCBox.yMin; w = fgCBox.xMax + Xoff + GetTrailingBlanksWidth(); h = fgCBox.yMax + Yoff; + CleanupGlyphs(); } //////////////////////////////////////////////////////////////////////////////// @@ -265,6 +279,25 @@ void TTF::LayoutGlyphs() } } +//////////////////////////////////////////////////////////////////////////////// +/// Remove temporary data created by LayoutGlyphs + +void TTF::CleanupGlyphs() +{ + TTGlyph* glyph = fgGlyphs; + + for (int n = 0; n < fgNumGlyphs; n++, glyph++) { + // clear existing image if there is one + if (glyph->fImage) { + FT_Done_Glyph(glyph->fImage); + glyph->fImage = nullptr; + } + } + + fgNumGlyphs = 0; +} + + //////////////////////////////////////////////////////////////////////////////// /// Put the characters in "string" in the "glyphs" array. From 7735fdeaa708e25c17bbb004442fb97b8aa160ab Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 22 Apr 2026 15:10:26 +0200 Subject: [PATCH 07/15] Use TTF::CleanupGlyphs in TASimage Always call TTF::Init() while it is re-entrant now --- graf2d/asimage/src/TASImage.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/graf2d/asimage/src/TASImage.cxx b/graf2d/asimage/src/TASImage.cxx index cef7d1b40e2e5..85e5f631c3c32 100644 --- a/graf2d/asimage/src/TASImage.cxx +++ b/graf2d/asimage/src/TASImage.cxx @@ -5731,7 +5731,7 @@ void TASImage::DrawTextOnPad(TText *text, Int_t x, Int_t y, TVirtualPad *pad, In if (!InitImage("DrawTextOnPad")) return; - if (!TTF::IsInitialized()) TTF::Init(); + TTF::Init(); // set text font TTF::SetTextFont(text->GetTextFont()); @@ -5857,6 +5857,8 @@ void TASImage::DrawTextOnPad(TText *text, Int_t x, Int_t y, TVirtualPad *pad, In DrawGlyph(source, color, bx, by, pad, offx, offy); } + + TTF::CleanupGlyphs(); } //////////////////////////////////////////////////////////////////////////////// @@ -5868,7 +5870,7 @@ void TASImage::DrawTextTTF(Int_t x, Int_t y, const char *text, Int_t size, if (!InitImage("DrawTextTTF")) return; - if (!TTF::IsInitialized()) TTF::Init(); + TTF::Init(); TTF::SetTextFont(font_name); TTF::SetTextSize(size); From b6cdf729c72eeaef1e20654d9b53c52ed329e372 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 22 Apr 2026 15:10:38 +0200 Subject: [PATCH 08/15] Use TTF::CleanupGlyphs in TGX11 Always call TTF::Init(); --- graf2d/x11ttf/src/TGX11TTF.cxx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/graf2d/x11ttf/src/TGX11TTF.cxx b/graf2d/x11ttf/src/TGX11TTF.cxx index d7b0cd73938f7..cda8cc71ae51e 100644 --- a/graf2d/x11ttf/src/TGX11TTF.cxx +++ b/graf2d/x11ttf/src/TGX11TTF.cxx @@ -156,7 +156,7 @@ TGX11TTF::TGX11TTF(TGX11 &&org) : TGX11(std::move(org)) SetName("X11TTF"); SetTitle("ROOT interface to X11 with TrueType fonts"); - if (!TTF::fgInit) TTF::Init(); + TTF::Init(); fHasTTFonts = kTRUE; fHasXft = kFALSE; @@ -371,12 +371,13 @@ void TGX11TTF::DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Fl if (!fHasTTFonts) { TGX11::DrawTextW(wctxt, x, y, angle, mgn, text, mode); } else { - if (!TTF::fgInit) TTF::Init(); + TTF::Init(); TTF::SetRotationMatrix(angle); TTF::PrepareString(text); TTF::LayoutGlyphs(); Align(wctxt); RenderString(wctxt, x, y, mode); + TTF::CleanupGlyphs(); } } @@ -390,12 +391,13 @@ void TGX11TTF::DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Fl if (!fHasTTFonts) { TGX11::DrawTextW(wctxt, x, y, angle, mgn, text, mode); } else { - if (!TTF::fgInit) TTF::Init(); + TTF::Init(); TTF::SetRotationMatrix(angle); TTF::PrepareString(text); TTF::LayoutGlyphs(); Align(wctxt); RenderString(wctxt, x, y, mode); + TTF::CleanupGlyphs(); } } @@ -463,8 +465,6 @@ Bool_t TGX11TTF::IsVisible(WinContext_t wctxt, Int_t x, Int_t y, UInt_t w, UInt_ void TGX11TTF::RenderString(WinContext_t wctxt, Int_t x, Int_t y, ETextMode mode) { - TTF::TTGlyph* glyph = TTF::fgGlyphs; - // compute the size and position of the XImage that will contain the text Int_t Xoff = 0; if (TTF::GetBox().xMin < 0) Xoff = -TTF::GetBox().xMin; Int_t Yoff = 0; if (TTF::GetBox().yMin < 0) Yoff = -TTF::GetBox().yMin; @@ -526,8 +526,8 @@ void TGX11TTF::RenderString(WinContext_t wctxt, Int_t x, Int_t y, ETextMode mode } // paint the glyphs in the XImage - glyph = TTF::fgGlyphs; - for (int n = 0; n < TTF::fgNumGlyphs; n++, glyph++) { + TTF::TTGlyph *glyph = TTF::GetGlyphs(); + for (int n = 0; n < TTF::GetNumGlyphs(); n++, glyph++) { if (FT_Glyph_To_Bitmap(&glyph->fImage, TTF::fgSmoothing ? ft_render_mode_normal : ft_render_mode_mono, From d753d0c35487fbc9b4e36688157b18586b3ab701 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 22 Apr 2026 15:10:47 +0200 Subject: [PATCH 09/15] Use TTF::CleanupGlyphs in win32 Always call TTF::Init() --- graf2d/win32gdk/src/TGWin32.cxx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/graf2d/win32gdk/src/TGWin32.cxx b/graf2d/win32gdk/src/TGWin32.cxx index 24c5b47a0994e..b79d4e7e0eaa3 100644 --- a/graf2d/win32gdk/src/TGWin32.cxx +++ b/graf2d/win32gdk/src/TGWin32.cxx @@ -1052,7 +1052,7 @@ Int_t TGWin32::OpenDisplay(const char *dpyName) SetName("Win32TTF"); SetTitle("ROOT interface to Win32 with TrueType fonts"); - if (!TTF::IsInitialized()) TTF::Init(); + TTF::Init(); if (fDepth > 8) { TTF::SetSmoothing(kTRUE); @@ -1293,12 +1293,13 @@ void TGWin32::DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Flo { if (!wctxt) return; - if (!TTF::IsInitialized()) TTF::Init(); + TTF::Init(); TTF::SetRotationMatrix(angle); TTF::PrepareString(text); TTF::LayoutGlyphs(); Align(wctxt); RenderString(wctxt, x, y, mode); + TTF::CleanupGlyphs(); } //////////////////////////////////////////////////////////////////////////////// @@ -1321,12 +1322,13 @@ void TGWin32::DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Flo { if (!wctxt) return; - if (!TTF::IsInitialized()) TTF::Init(); + TTF::Init(); TTF::SetRotationMatrix(angle); TTF::PrepareString(text); TTF::LayoutGlyphs(); Align(wctxt); RenderString(wctxt, x, y, mode); + TTF::CleanupGlyphs(); } //////////////////////////////////////////////////////////////////////////////// @@ -1386,7 +1388,6 @@ void TGWin32::RenderString(WinContext_t wctxt, Int_t x, Int_t y, ETextMode mode) { auto ctxt = (XWindow_t *) wctxt; - TTF::TTGlyph* glyph = TTF::GetGlyphs(); GdkGCValues gcvals; // compute the size and position of the XImage that will contain the text @@ -1465,7 +1466,7 @@ void TGWin32::RenderString(WinContext_t wctxt, Int_t x, Int_t y, ETextMode mode) } // paint the glyphs in the XImage - glyph = TTF::GetGlyphs(); + TTF::TTGlyph* glyph = TTF::GetGlyphs(); for (int n = 0; n < TTF::GetNumGlyphs(); n++, glyph++) { if (FT_Glyph_To_Bitmap(&glyph->fImage, TTF::GetSmoothing() ? ft_render_mode_normal From f6ae75639ade8d020d41820f29821e4b244f4686 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 22 Apr 2026 15:11:03 +0200 Subject: [PATCH 10/15] Use TTF::CleanupGlyphs in Cocoa Always call TTF::Init() - it is reentrant --- graf2d/cocoa/src/TGQuartz.mm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/graf2d/cocoa/src/TGQuartz.mm b/graf2d/cocoa/src/TGQuartz.mm index f60389eacbf52..bacea9a6fa4ef 100644 --- a/graf2d/cocoa/src/TGQuartz.mm +++ b/graf2d/cocoa/src/TGQuartz.mm @@ -79,9 +79,7 @@ void ConvertPointsROOTToCocoa(Int_t nPoints, const TPoint *xy, std::vector Date: Wed, 22 Apr 2026 18:05:33 +0200 Subject: [PATCH 11/15] Eliminate static variables usage in TImageDump Can be easily used in the future from multithreads --- graf2d/postscript/src/TImageDump.cxx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/graf2d/postscript/src/TImageDump.cxx b/graf2d/postscript/src/TImageDump.cxx index 96ada4f9f9866..b98c2f083fc6d 100644 --- a/graf2d/postscript/src/TImageDump.cxx +++ b/graf2d/postscript/src/TImageDump.cxx @@ -118,13 +118,12 @@ void TImageDump::Close(Option_t *) void TImageDump::DrawBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2) { - if (!gPad || !fImage) { + if (!gPad || !fImage) return; - } fImage->BeginPaint(); - static Double_t x[4], y[4]; + Double_t x[4], y[4]; Int_t ix1 = x1 < x2 ? XtoPixel(x1) : XtoPixel(x2); Int_t ix2 = x1 < x2 ? XtoPixel(x2) : XtoPixel(x1); Int_t iy1 = y1 < y2 ? YtoPixel(y1) : YtoPixel(y2); @@ -283,15 +282,14 @@ void TImageDump::DrawPolyMarker(Int_t, Float_t *, Float_t *) void TImageDump::DrawPolyMarker(Int_t n, Double_t *xw, Double_t *yw) { - if (!gPad || !fImage) { + if (!gPad || !fImage) return; - } fImage->BeginPaint(); fMarkerStyle = TMath::Abs(fMarkerStyle); Int_t ms = TAttMarker::GetMarkerStyleBase(fMarkerStyle); - static TPoint pt[20]; + TPoint pt[20]; if (ms == 4) ms = 24; @@ -640,9 +638,8 @@ void TImageDump::DrawPolyMarker(Int_t n, Double_t *xw, Double_t *yw) void TImageDump::DrawPS(Int_t nn, Double_t *x, Double_t *y) { - if (!gPad || !fImage || !nn) { + if (!gPad || !fImage || !nn) return; - } fImage->BeginPaint(); From 15909def8dc011920c663b210dfc5824a2f05dcc Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 23 Apr 2026 11:27:01 +0200 Subject: [PATCH 12/15] Use std::vector in TImageDump::DrawPS Instead of old style with lot of static variables just use std::vector for points arrays and dash array --- graf2d/postscript/src/TImageDump.cxx | 160 +++++++++------------------ 1 file changed, 53 insertions(+), 107 deletions(-) diff --git a/graf2d/postscript/src/TImageDump.cxx b/graf2d/postscript/src/TImageDump.cxx index b98c2f083fc6d..6f6f3b3892f0c 100644 --- a/graf2d/postscript/src/TImageDump.cxx +++ b/graf2d/postscript/src/TImageDump.cxx @@ -643,113 +643,73 @@ void TImageDump::DrawPS(Int_t nn, Double_t *x, Double_t *y) fImage->BeginPaint(); - TColor *col = nullptr; - Int_t fais = 0 , fasi = 0; Bool_t line = nn > 1; UInt_t n = TMath::Abs(nn); + Int_t fais = fFillStyle / 1000; + Int_t fasi = fFillStyle % 1000; - fais = fFillStyle/1000; - fasi = fFillStyle%1000; + // SetLineStyle + std::vector dashList; - Short_t px1, py1, px2, py2; - static const UInt_t gCachePtSize = 200; - static TPoint gPointCache[gCachePtSize]; + TColor *fcol = gROOT->GetColor(fFillColor); + if (!fcol) { // no color, set it white + fFillColor = 10; + fcol = gROOT->GetColor(fFillColor); + } - // SetLineStyle - Int_t ndashes = 0; - static char dashList[10]; - Int_t dashSize = 0; + TColor *lcol = gROOT->GetColor(fLineColor); + if (!lcol) { // no color, make it black + fLineColor = 1; + lcol = gROOT->GetColor(fLineColor); + } if (line) { - if (fLineWidth<=0) return; + if (fLineWidth <= 0) + return; // dash lines if (fLineStyle > 1) { TString st = gStyle->GetLineStyleString(fLineStyle); - TObjArray *tokens = st.Tokenize(" "); - ndashes = tokens->GetEntries(); - char *dash = new char[ndashes]; - - for (int j = 0; j < ndashes; j++) { - Int_t it; - sscanf(((TObjString*)tokens->At(j))->GetName(), "%d", &it); - dash[j] = (char)(it/4); - } - - dashSize = TMath::Min((int)sizeof(dashList), ndashes); - for (int i = 0; i < dashSize; i++ ) { - dashList[i] = dash[i]; - } - delete tokens; - delete [] dash; - } - - // SetLineColor - col = gROOT->GetColor(fLineColor); - if (!col) { // no color, make it black - fLineColor = 1; - col = gROOT->GetColor(fLineColor); - if (!col) return; + std::unique_ptr tokens(st.Tokenize(" ")); + + if (tokens) + for (int j = 0; j < tokens->GetEntries(); j++) { + Int_t it; + sscanf(tokens->At(j)->GetName(), "%d", &it); + dashList.emplace_back((char)(it/4)); + } } } if (n == 1) { // point - col = gROOT->GetColor(fFillColor); - if (!col) { // no color, make it black - fFillColor = 1; - col = gROOT->GetColor(fFillColor); - if (!col) return; - } - px1 = XtoPixel(x[0]); py1 = YtoPixel(y[0]); - fImage->PutPixel(px1, py1, col->AsHexString()); + auto px1 = XtoPixel(x[0]); + auto py1 = YtoPixel(y[0]); + if (fcol) + fImage->PutPixel(px1, py1, fcol->AsHexString()); return; } if (n == 2) { // line - px1 = XtoPixel(x[0]); py1 = YtoPixel(y[0]); - px2 = XtoPixel(x[1]); py2 = YtoPixel(y[1]); + auto px1 = XtoPixel(x[0]); + auto py1 = YtoPixel(y[0]); + auto px2 = XtoPixel(x[1]); + auto py2 = YtoPixel(y[1]); // SetLineColor - col = gROOT->GetColor(fLineColor); - if (!col) { // no color, make it black - fLineColor = 1; - col = gROOT->GetColor(fLineColor); - if (!col) return; - } - if (fLineStyle < 2) { - fImage->DrawLine(px1, py1, px2, py2, col->AsHexString(), fLineWidth); - } else { - fImage->DrawDashLine(px1, py1, px2, py2, dashSize, (const char*)dashList, - col->AsHexString(), fLineWidth); + if (lcol) { + if (fLineStyle < 2) { + fImage->DrawLine(px1, py1, px2, py2, lcol->AsHexString(), fLineWidth); + } else { + fImage->DrawDashLine(px1, py1, px2, py2, dashList.size(), dashList.data(), + lcol->AsHexString(), fLineWidth); + } } return; } - if (!line && ((fais == 3) || (fais == 2)) && (fasi > 100) ) { + if (!line && ((fais == 3) || (fais == 2)) && (fasi > 100)) return; - } - TPoint *pt = nullptr; - Bool_t del = kTRUE; - - if (n+1 < gCachePtSize) { - pt = (TPoint*)&gPointCache; - del = kFALSE; - } else { - pt = new TPoint[n+1]; - del = kTRUE; - } - - TColor *fcol = gROOT->GetColor(fFillColor); - if (!fcol) { // no color, set it white - fFillColor = 10; - fcol = gROOT->GetColor(fFillColor); - } - - TColor *lcol = gROOT->GetColor(fLineColor); - if (!lcol) { // no color, make it black - fLineColor = 1; - lcol = gROOT->GetColor(fLineColor); - } + std::vector pt(n+1); for (UInt_t i = 0; i < n; i++) { pt[i].fX = XtoPixel(x[i]); @@ -761,39 +721,27 @@ void TImageDump::DrawPS(Int_t nn, Double_t *x, Double_t *y) const char *stipple = (fais == 3) && (fasi > 0) && (fasi < 26) ? (const char*)gStipples[fasi] : nullptr; // filled polygon - if (!line && fFillStyle && (fFillStyle != 4000)) { - if (!fcol) { - if (del) delete [] pt; - return; - } - - if (n < 5) { // convex - fImage->FillPolygon(n, pt, fcol->AsHexString(), stipple); - } else { // non-convex fill area - fImage->DrawFillArea(n, pt, fcol->AsHexString(), stipple); - } + if (!line && fFillStyle && (fFillStyle != 4000) && fcol) { + if (n < 5) // convex + fImage->FillPolygon(n, pt.data(), fcol->AsHexString(), stipple); + else // non-convex fill area + fImage->DrawFillArea(n, pt.data(), fcol->AsHexString(), stipple); } // hollow polygon or polyline is drawn if (line || !fFillStyle || (fFillStyle == 4000)) { - if (!lcol) { - if (del) - delete [] pt; - return; - } if (!line) { - fImage->DrawPolyLine(n+1, pt, fcol->AsHexString(), 1); - } else { + if (fcol) + fImage->DrawPolyLine(n+1, pt.data(), fcol->AsHexString(), 1); + } else if (lcol) { if (fLineStyle < 2) { // solid - fImage->DrawPolyLine(n, pt, lcol->AsHexString(), fLineWidth); + fImage->DrawPolyLine(n, pt.data(), lcol->AsHexString(), fLineWidth); } else { // dashed - DrawDashPolyLine(n, pt, dashSize, (const char*)dashList, + DrawDashPolyLine(n, pt.data(), dashList.size(), dashList.data(), lcol->AsHexString(), fLineWidth); } } } - if (del) - delete [] pt; } //////////////////////////////////////////////////////////////////////////////// @@ -814,12 +762,10 @@ void TImageDump::DrawDashPolyLine(Int_t nn, TPoint *xy, UInt_t nDash, { Int_t x0 = xy[0].GetX(); Int_t y0 = xy[0].GetY(); - Int_t x = 0; - Int_t y = 0; for (Int_t i = 1; i < nn; i++) { - x = xy[i].GetX(); - y = xy[i].GetY(); + Int_t x = xy[i].GetX(); + Int_t y = xy[i].GetY(); fImage->DrawDashLine(x0, y0, x, y, nDash, pDash, col, thick); From 5bc516a1965caa3e0a2ddc8eed141bd75c293271 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 23 Apr 2026 12:27:38 +0200 Subject: [PATCH 13/15] Use members instead static for TImageDump::CellArray methods Replace static variables by members, use vector. --- graf2d/postscript/inc/TImageDump.h | 9 ++++ graf2d/postscript/src/TImageDump.cxx | 69 ++++++++++------------------ 2 files changed, 33 insertions(+), 45 deletions(-) diff --git a/graf2d/postscript/inc/TImageDump.h b/graf2d/postscript/inc/TImageDump.h index 51ff0759304cc..5ad5097ae9c92 100644 --- a/graf2d/postscript/inc/TImageDump.h +++ b/graf2d/postscript/inc/TImageDump.h @@ -25,6 +25,15 @@ class TImageDump : public TVirtualPS { Int_t fType{0}; ///< PostScript workstation type Int_t fX0{0}, fY0{0}; ///< offset of selected pad to canvas + std::vector fCellArrayColors; + Int_t fCellArrayW{0}; + Int_t fCellArrayH{0}; + Int_t fCellArrayX1{0}; + Int_t fCellArrayX2{0}; + Int_t fCellArrayY1{0}; + Int_t fCellArrayY2{0}; + UInt_t fCellArrayIdx{0}; + Int_t XtoPixel(Double_t x); Int_t YtoPixel(Double_t y); void DrawDashPolyLine(Int_t npoints, TPoint *pt, UInt_t nDash, diff --git a/graf2d/postscript/src/TImageDump.cxx b/graf2d/postscript/src/TImageDump.cxx index 6f6f3b3892f0c..a864d3f8133a7 100644 --- a/graf2d/postscript/src/TImageDump.cxx +++ b/graf2d/postscript/src/TImageDump.cxx @@ -846,44 +846,26 @@ void TImageDump::TextUrl(Double_t x, Double_t y, const char *chars, const char * Text(x, y, chars); } -////////////////////////// CellArray code //////////////////////////////////// -static UInt_t *gCellArrayColors = nullptr; -static Int_t gCellArrayN = 0; -static Int_t gCellArrayW = 0; -static Int_t gCellArrayH = 0; -static Int_t gCellArrayX1 = 0; -static Int_t gCellArrayX2 = 0; -static Int_t gCellArrayY1 = 0; -static Int_t gCellArrayY2 = 0; -static Int_t gCellArrayIdx = 0; - //////////////////////////////////////////////////////////////////////////////// ///cell array begin void TImageDump::CellArrayBegin(Int_t w, Int_t h, Double_t x1, Double_t x2, Double_t y1, Double_t y2) { - if (!gPad || !fImage || (w <= 0) || (h <= 0)) { + if (!gPad || !fImage || (w <= 0) || (h <= 0)) return; - } - - if (gCellArrayColors) { - delete [] gCellArrayColors; - } fImage->BeginPaint(); - gCellArrayN = w * h; - gCellArrayW = w; - gCellArrayH = h; - gCellArrayColors = new UInt_t[gCellArrayN]; + fCellArrayW = w; + fCellArrayH = h; + fCellArrayColors.resize(w * h); + fCellArrayIdx = 0; - gCellArrayX1 = x1 < x2 ? XtoPixel(x1) : XtoPixel(x2); - gCellArrayX2 = x1 > x2 ? XtoPixel(x2) : XtoPixel(x1); - gCellArrayY1 = y1 < y2 ? YtoPixel(y1) : YtoPixel(y2); - gCellArrayY2 = y1 < y2 ? YtoPixel(y2) : YtoPixel(y1); - - gCellArrayIdx = 0; + fCellArrayX1 = x1 < x2 ? XtoPixel(x1) : XtoPixel(x2); + fCellArrayX2 = x1 > x2 ? XtoPixel(x2) : XtoPixel(x1); + fCellArrayY1 = y1 < y2 ? YtoPixel(y1) : YtoPixel(y2); + fCellArrayY2 = y1 < y2 ? YtoPixel(y2) : YtoPixel(y1); } //////////////////////////////////////////////////////////////////////////////// @@ -891,12 +873,12 @@ void TImageDump::CellArrayBegin(Int_t w, Int_t h, Double_t x1, Double_t x2, void TImageDump::CellArrayFill(Int_t r, Int_t g, Int_t b) { - if (gCellArrayIdx >= gCellArrayN) return; + if (fCellArrayIdx >= fCellArrayColors.size()) + return; fImage->BeginPaint(); - gCellArrayColors[gCellArrayIdx] = ((r & 0xFF) << 16) + ((g & 0xFF) << 8) + (b & 0xFF); - gCellArrayIdx++; + fCellArrayColors[fCellArrayIdx++] = ((r & 0xFF) << 16) + ((g & 0xFF) << 8) + (b & 0xFF); } //////////////////////////////////////////////////////////////////////////////// @@ -904,25 +886,22 @@ void TImageDump::CellArrayFill(Int_t r, Int_t g, Int_t b) void TImageDump::CellArrayEnd() { - if (!fImage || !gCellArrayColors || !gCellArrayW || !gCellArrayH) { + if (!fImage || fCellArrayColors.empty() || !fCellArrayW || !fCellArrayH) return; - } fImage->BeginPaint(); - fImage->DrawCellArray(gCellArrayX1, gCellArrayX2, gCellArrayY1, gCellArrayY2, - gCellArrayW, gCellArrayH, gCellArrayColors); - - delete [] gCellArrayColors; - gCellArrayColors = nullptr; - gCellArrayN = 0; - gCellArrayW = 0; - gCellArrayH = 0; - gCellArrayX1 = 0; - gCellArrayX2 = 0; - gCellArrayY1 = 0; - gCellArrayY2 = 0; - gCellArrayIdx = 0; + fImage->DrawCellArray(fCellArrayX1, fCellArrayX2, fCellArrayY1, fCellArrayY2, + fCellArrayW, fCellArrayH, fCellArrayColors.data()); + + fCellArrayColors.clear(); + fCellArrayIdx = 0; + fCellArrayW = 0; + fCellArrayH = 0; + fCellArrayX1 = 0; + fCellArrayX2 = 0; + fCellArrayY1 = 0; + fCellArrayY2 = 0; } //////////////////////////////////////////////////////////////////////////////// From ab21d6d2ee121a52f12a1b26a73cd684cfbeddb6 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 23 Apr 2026 13:14:37 +0200 Subject: [PATCH 14/15] [virtualps] add methods to open/close output stream Base class holds fStream pointer which used for file output in derived classes. Provide methods to open and close this file stream. For special usecase (PDF) binary stream output need to be configured for Windows. --- core/base/inc/TVirtualPS.h | 3 +++ core/base/src/TVirtualPS.cxx | 39 +++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/core/base/inc/TVirtualPS.h b/core/base/inc/TVirtualPS.h index 25192ce15f057..2f3f72c4459f0 100644 --- a/core/base/inc/TVirtualPS.h +++ b/core/base/inc/TVirtualPS.h @@ -42,6 +42,9 @@ class TVirtualPS : public TNamed, public TAttLine, public TAttFill, public TAttM char *fBuffer{nullptr}; // File buffer const char *fImplicitCREsc{nullptr}; // Escape symbol before enforced new line + Bool_t OpenStream(const char *fname, Bool_t binary = kFALSE); + void CloseStream(); + public: TVirtualPS(); TVirtualPS(const char *filename, Int_t type=-111); diff --git a/core/base/src/TVirtualPS.cxx b/core/base/src/TVirtualPS.cxx index fca7d4e633a36..fa8195db4fb7e 100644 --- a/core/base/src/TVirtualPS.cxx +++ b/core/base/src/TVirtualPS.cxx @@ -62,9 +62,46 @@ TVirtualPS::TVirtualPS(const char *name, Int_t) TVirtualPS::~TVirtualPS() { - if (fBuffer) delete [] fBuffer; + if (fBuffer) + delete [] fBuffer; } +//////////////////////////////////////////////////////////////////////////////// +/// Open output stream + +Bool_t TVirtualPS::OpenStream(const char *fname, Bool_t binary) +{ + CloseStream(); + + auto flags = std::ofstream::out; +#ifdef R__WIN32 + if (binary) + flags = flags | std::ofstream::binary; +#else + (void) binary; +#endif + + fStream = new std::ofstream(fname, flags); + if (!fStream || !fStream->good()) { + delete fStream; + fStream = nullptr; + return kFALSE; + } + + return kTRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Close existing stream + +void TVirtualPS::CloseStream() +{ + if (fStream) { + fStream->close(); + delete fStream; + fStream = nullptr; + } +} //////////////////////////////////////////////////////////////////////////////// /// Output the string str in the output buffer From 6589bf3a91b8a73518c9fb645de1fdcf9618469c Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 23 Apr 2026 13:17:27 +0200 Subject: [PATCH 15/15] [ps] use OpenStream/CloseStream in all derived classes Do not initialize fStream member in constructors - it belongs to base classes. Use everywhere `Error()` method to report errors Small other adjustments --- graf2d/postscript/src/TImageDump.cxx | 2 -- graf2d/postscript/src/TPDF.cxx | 35 +++++++++++---------------- graf2d/postscript/src/TPostScript.cxx | 24 +++++++++--------- graf2d/postscript/src/TSVG.cxx | 20 +++++++-------- graf2d/postscript/src/TTeXDump.cxx | 16 ++++++------ 5 files changed, 42 insertions(+), 55 deletions(-) diff --git a/graf2d/postscript/src/TImageDump.cxx b/graf2d/postscript/src/TImageDump.cxx index a864d3f8133a7..4effffceb63c0 100644 --- a/graf2d/postscript/src/TImageDump.cxx +++ b/graf2d/postscript/src/TImageDump.cxx @@ -51,7 +51,6 @@ TImageDump can be used in any mode (batch, interactive) as follows TImageDump::TImageDump() : TVirtualPS() { - fStream = nullptr; fImage = nullptr; gVirtualPS = this; fType = 0; @@ -80,7 +79,6 @@ TImageDump::TImageDump(const char *fname, Int_t wtype) : TVirtualPS(fname, wtype void TImageDump::Open(const char *fname, Int_t type) { - fStream = nullptr; fImage = TImage::Create(); fType = type; SetName(fname); diff --git a/graf2d/postscript/src/TPDF.cxx b/graf2d/postscript/src/TPDF.cxx index 6fca833451c8c..b6d079182e815 100644 --- a/graf2d/postscript/src/TPDF.cxx +++ b/graf2d/postscript/src/TPDF.cxx @@ -103,7 +103,6 @@ Int_t TPDF::fgLineCap = 0; TPDF::TPDF() : TVirtualPS() { - fStream = nullptr; fCompress = kFALSE; fPageNotEmpty = kFALSE; fObjectIsOpen = kFALSE; @@ -144,7 +143,6 @@ TPDF::TPDF() : TVirtualPS() TPDF::TPDF(const char *fname, Int_t wtype) : TVirtualPS(fname, wtype) { - fStream = nullptr; fCompress = kFALSE; fPageNotEmpty = kFALSE; fObjectIsOpen = kFALSE; @@ -214,11 +212,11 @@ void TPDF::CellArrayEnd() void TPDF::Close(Option_t *) { - Int_t i; + if (!gVirtualPS || !fStream) + return; - if (!gVirtualPS) return; - if (!fStream) return; - if (gPad) gPad->Update(); + if (gPad) + gPad->Update(); // Close the currently opened page WriteCompressedBuffer(); @@ -306,7 +304,7 @@ void TPDF::Close(Option_t *) WriteInteger(fNbPage); PrintStr("@"); PrintStr("/Kids ["); - for (i = 0; i < (int)fPageObjects.size(); i++) { + for (std::size_t i = 0; i < fPageObjects.size(); i++) { WriteInteger(fPageObjects[i]); PrintStr(" 0 R"); } @@ -331,14 +329,15 @@ void TPDF::Close(Option_t *) // List of transparencies NewObject(kObjTransList); PrintStr("<<@"); - for (i=0; i<(int)fAlphas.size(); i++) { + for (std::size_t i = 0; i < fAlphas.size(); i++) { PrintStr( - Form("/ca%3.2f << /Type /ExtGState /ca %3.2f >> /CA%3.2f << /Type /ExtGState /CA %3.2f >>@", + TString::Format("/ca%3.2f << /Type /ExtGState /ca %3.2f >> /CA%3.2f << /Type /ExtGState /CA %3.2f >>@", fAlphas[i],fAlphas[i],fAlphas[i],fAlphas[i])); } PrintStr(">>@"); EndObject(); - if (!fAlphas.empty()) fAlphas.clear(); + if (!fAlphas.empty()) + fAlphas.clear(); // Cross-Reference Table Int_t refInd = fNByte; @@ -348,7 +347,7 @@ void TPDF::Close(Option_t *) PrintStr("@"); PrintStr("0000000000 65535 f @"); char str[21]; - for (i=0; iclose(); delete fStream; fStream = nullptr;} + CloseStream(); gVirtualPS = nullptr; } @@ -1748,15 +1747,9 @@ void TPDF::Open(const char *fname, Int_t wtype) } // Open OS file - fStream = new std::ofstream(); -#ifdef R__WIN32 - fStream->open(fname, std::ofstream::out | std::ofstream::binary); -#else - fStream->open(fname, std::ofstream::out); -#endif - if (!fStream || !fStream->good()) { - printf("ERROR in TPDF::Open: Cannot open file:%s\n",fname); - if (!fStream) return; + if (!OpenStream(fname, kTRUE)) { + Error("Open", "Cannot open file: %s", fname); + return; } gVirtualPS = this; diff --git a/graf2d/postscript/src/TPostScript.cxx b/graf2d/postscript/src/TPostScript.cxx index 8d4343736d18c..f738381e5c784 100644 --- a/graf2d/postscript/src/TPostScript.cxx +++ b/graf2d/postscript/src/TPostScript.cxx @@ -400,8 +400,7 @@ void TPostScript::Open(const char *fname, Int_t wtype) // Open OS file fFileName = fname; - fStream = new std::ofstream(fFileName.Data(),std::ios::out); - if (!fStream || gSystem->AccessPathName(fFileName.Data(),kWritePermission)) { + if (!OpenStream(fFileName.Data()) || gSystem->AccessPathName(fFileName.Data(), kWritePermission)) { Error("Open", "Cannot open file: %s", fFileName.Data()); return; } @@ -440,10 +439,11 @@ TPostScript::~TPostScript() void TPostScript::Close(Option_t *) { - if (!gVirtualPS) return; - if (!fStream) return; - if (gPad) gPad->Update(); - if( fMode != 3) { + if (!gVirtualPS ||!fStream) + return; + if (gPad) + gPad->Update(); + if(fMode != 3) { SaveRestore(-1); if( fPrinted ) { PrintStr("showpage@"); SaveRestore(-1);} PrintStr("@"); @@ -466,19 +466,17 @@ void TPostScript::Close(Option_t *) // Close the file fFileName if (fStream) { PrintStr("@"); - fStream->close(); delete fStream; fStream = nullptr; + CloseStream(); } // Rename the file fFileName TString tmpname = TString::Format("%s_tmp_%d",fFileName.Data(),gSystem->GetPid()); - if (gSystem->Rename( fFileName.Data() , tmpname.Data())) { + if (gSystem->Rename(fFileName.Data(), tmpname.Data())) { Error("Close", "Cannot open temporary file: %s", tmpname.Data()); return; } - // Reopen the file fFileName - fStream = new std::ofstream(fFileName.Data(),std::ios::out); - if (!fStream || gSystem->AccessPathName(fFileName.Data(),kWritePermission)) { + if (!OpenStream(fFileName.Data()) || gSystem->AccessPathName(fFileName.Data(), kWritePermission)) { Error("Close", "Cannot open file: %s", fFileName.Data()); return; } @@ -506,7 +504,7 @@ void TPostScript::Close(Option_t *) // Close file stream - if (fStream) { fStream->close(); delete fStream; fStream = nullptr;} + CloseStream(); gVirtualPS = nullptr; } @@ -2534,7 +2532,7 @@ void TPostScript::SetStyle(Style_t linestyle) if (linestyle == fStyle) return; fStyle = linestyle; - + const char *st = gStyle->GetLineStyleString(fStyle); PrintFast(1,"["); Int_t nch = strlen(st); diff --git a/graf2d/postscript/src/TSVG.cxx b/graf2d/postscript/src/TSVG.cxx index 64c9f67ee1d34..b58d4bd4db09e 100644 --- a/graf2d/postscript/src/TSVG.cxx +++ b/graf2d/postscript/src/TSVG.cxx @@ -82,7 +82,6 @@ using the file extension `.svgz`. TSVG::TSVG() : TVirtualPS() { - fStream = nullptr; fType = 0; fCompact = kFALSE; gVirtualPS = this; @@ -105,7 +104,6 @@ TSVG::TSVG() : TVirtualPS() TSVG::TSVG(const char *fname, Int_t wtype, Bool_t compact) : TVirtualPS(fname, wtype) { - fStream = nullptr; SetTitle("SVG"); fCompact = compact; Open(fname, wtype); @@ -141,10 +139,9 @@ void TSVG::Open(const char *fname, Int_t wtype) } // Open OS file - fStream = new std::ofstream(fname,std::ios::out); - if (!fStream || !fStream->good()) { - printf("ERROR in TSVG::Open: Cannot open file:%s\n",fname); - if (!fStream) return; + if (!OpenStream(fname)) { + Error("Open", "Cannot open file: %s", fname); + return; } gVirtualPS = this; @@ -174,13 +171,14 @@ TSVG::~TSVG() void TSVG::Close(Option_t *) { - if (!gVirtualPS) return; - if (!fStream) return; - if (gPad) gPad->Update(); + if (!gVirtualPS || !fStream) + return; + if (gPad) + gPad->Update(); PrintStr("@"); // Close file stream - if (fStream) { fStream->close(); delete fStream; fStream = nullptr;} + CloseStream(); gVirtualPS = nullptr; } @@ -214,7 +212,7 @@ void TSVG::Off() void TSVG::DrawBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2) { - static Double_t x[4], y[4]; + Double_t x[4], y[4]; Double_t ix1 = XtoSVG(TMath::Min(x1,x2)); Double_t ix2 = XtoSVG(TMath::Max(x1,x2)); Double_t iy1 = YtoSVG(TMath::Min(y1,y2)); diff --git a/graf2d/postscript/src/TTeXDump.cxx b/graf2d/postscript/src/TTeXDump.cxx index 29d41e48a6aab..319e2bb184345 100644 --- a/graf2d/postscript/src/TTeXDump.cxx +++ b/graf2d/postscript/src/TTeXDump.cxx @@ -154,10 +154,9 @@ void TTeXDump::Open(const char *fname, Int_t wtype) } // Open OS file - fStream = new std::ofstream(fname,std::ios::out); - if (!fStream || !fStream->good()) { - printf("ERROR in TTeXDump::Open: Cannot open file:%s\n",fname); - if (!fStream) return; + if (!OpenStream(fname)) { + Error("Open", "Cannot open file:%s", fname); + return; } gVirtualPS = this; @@ -200,9 +199,10 @@ TTeXDump::~TTeXDump() void TTeXDump::Close(Option_t *) { - if (!gVirtualPS) return; - if (!fStream) return; - if (gPad) gPad->Update(); + if (!gVirtualPS || !fStream) + return; + if (gPad) + gPad->Update(); PrintStr("@"); PrintStr("\\end{tikzpicture}@"); if (fStandalone) { @@ -212,7 +212,7 @@ void TTeXDump::Close(Option_t *) } // Close file stream - if (fStream) { fStream->close(); delete fStream; fStream = nullptr;} + CloseStream(); gVirtualPS = nullptr; }