16 #include FT_FREETYPE_H
25 #include "../../../graf2d/mathtext/inc/mathtext.h"
26 #include "../../../graf2d/mathtext/inc/mathrender.h"
49 const Double_t kPI = TMath::Pi();
51 class TMathTextRenderer :
public TText,
public TAttFill,
52 public mathtext::math_text_renderer_t {
59 float _pad_pixel_transform[6];
63 float _pad_scale_x_relative;
64 float _pad_scale_y_relative;
65 float _current_font_size[mathtext::math_text_renderer_t::NFAMILY];
66 inline size_t root_face_number(
67 const unsigned int family,
const bool serif =
false)
const
69 static const int precision = 2;
71 if (family >= mathtext::math_text_renderer_t::
73 family <= mathtext::math_text_renderer_t::
75 const unsigned int offset = family -
76 mathtext::math_text_renderer_t::FAMILY_REGULAR;
78 ((offset == 0 ? 13 : offset) * 10 + precision) :
79 ((offset + 4) * 10 + precision);
80 }
else if (family >= mathtext::math_text_renderer_t::
81 FAMILY_STIX_REGULAR) {
82 const unsigned int offset = family -
83 mathtext::math_text_renderer_t::FAMILY_STIX_REGULAR;
84 return (offset + 16) * 10 + precision;
89 inline bool is_cyrillic_or_cjk(
const wchar_t c)
const
91 return mathtext::math_text_renderer_t::is_cyrillic(c) ||
92 mathtext::math_text_renderer_t::is_cjk(c);
94 inline size_t root_cjk_face_number(
95 const bool serif =
false)
const
97 return (serif ? 28 : 29) * 10 + 2;
100 inline mathtext::affine_transform_t
101 transform_logical_to_pixel(
void)
const
103 return mathtext::affine_transform_t::identity;
105 inline mathtext::affine_transform_t
106 transform_pixel_to_logical(
void)
const
108 return mathtext::affine_transform_t::identity;
111 inline TMathTextRenderer(TMathText *parent)
112 : TText(), TAttFill(0, 1001),
113 _parent(parent), _font_size(0), _angle_degree(0)
120 for (i = 0; i<6; i++) _pad_pixel_transform[i] = 0;
124 _pad_scale_x_relative = 0;
125 _pad_scale_y_relative = 0;
126 for (i = 0; i < mathtext::math_text_renderer_t::NFAMILY; i++) _current_font_size[i] = 0;
129 font_size(
const unsigned int family = FAMILY_PLAIN)
const
131 return _current_font_size[family];
134 point(
const float ,
const float )
138 set_font_size(
const float size,
const unsigned int family)
140 _current_font_size[family] = size;
143 set_font_size(
const float size)
146 std::fill(_current_font_size,
147 _current_font_size + NFAMILY, size);
150 reset_font_size(
const unsigned int )
154 set_parameter(
const float x,
const float y,
const float size,
155 const float angle_degree)
157 _x0 = gPad->XtoAbsPixel(x);
158 _y0 = gPad->YtoAbsPixel(y);
160 gPad->XtoPixel(gPad->GetX2()) -
161 gPad->XtoPixel(gPad->GetX1());
163 gPad->YtoPixel(gPad->GetY1()) -
164 gPad->YtoPixel(gPad->GetY2());
165 _pad_scale = std::min(_pad_scale_x, _pad_scale_y);
167 _angle_degree = angle_degree;
169 const float angle_radiant = _angle_degree * (kPI / 180.0);
172 _pad_pixel_transform[0] = _pad_scale * cosf(angle_radiant);
173 _pad_pixel_transform[1] = -_pad_scale * sinf(angle_radiant);
174 _pad_pixel_transform[2] = _x0;
175 _pad_pixel_transform[3] = _pad_pixel_transform[1];
176 _pad_pixel_transform[4] = -_pad_pixel_transform[0];
177 _pad_pixel_transform[5] = _y0;
180 SetTextAngle(_angle_degree);
181 SetTextColor(_parent->fTextColor);
184 transform_pad(
double &xt,
double &yt,
185 const float x,
const float y)
const
187 xt = gPad->AbsPixeltoX(Int_t(
188 x * _pad_pixel_transform[0] +
189 y * _pad_pixel_transform[1] + _pad_pixel_transform[2]));
190 yt = gPad->AbsPixeltoY(Int_t(
191 x * _pad_pixel_transform[3] +
192 y * _pad_pixel_transform[4] + _pad_pixel_transform[5]));
195 filled_rectangle(
const mathtext::bounding_box_t &bounding_box_0)
197 SetFillColor(_parent->fTextColor);
204 transform_pad(xt[0], yt[0],
205 bounding_box_0.left(),
206 bounding_box_0.bottom());
207 transform_pad(xt[1], yt[1],
208 bounding_box_0.right(),
209 bounding_box_0.bottom());
210 transform_pad(xt[2], yt[2],
211 bounding_box_0.right(),
212 bounding_box_0.top());
213 transform_pad(xt[3], yt[3],
214 bounding_box_0.left(),
215 bounding_box_0.top());
216 gPad->PaintFillArea(4, xt, yt);
219 rectangle(
const mathtext::bounding_box_t &)
222 inline mathtext::bounding_box_t
223 bounding_box(
const wchar_t character,
float ¤t_x,
224 const unsigned int family)
226 const size_t old_font_index = TTF::fgCurFontIdx;
227 const bool cyrillic_or_cjk = is_cyrillic_or_cjk(character);
229 if (cyrillic_or_cjk) {
230 TTF::SetTextFont((Font_t) root_cjk_face_number());
232 TTF::SetTextFont((Font_t) root_face_number(family));
235 TTF::fgFace[TTF::fgCurFontIdx],
237 TTF::fgFace[TTF::fgCurFontIdx], character),
240 const float scale = _current_font_size[family] /
241 TTF::fgFace[TTF::fgCurFontIdx]->units_per_EM;
242 const FT_Glyph_Metrics metrics =
243 TTF::fgFace[TTF::fgCurFontIdx]->glyph->metrics;
244 const float lower_left_x = metrics.horiBearingX;
245 const float lower_left_y =
246 metrics.horiBearingY - metrics.height;
247 const float upper_right_x =
248 metrics.horiBearingX + metrics.width;
249 const float upper_right_y = metrics.horiBearingY;
250 const float advance = metrics.horiAdvance;
251 const float margin = std::max(0.0F, lower_left_x);
252 const float italic_correction =
253 upper_right_x <= advance ? 0.0F :
254 std::max(0.0F, upper_right_x + margin - advance);
255 const mathtext::bounding_box_t ret =
256 mathtext::bounding_box_t(
257 lower_left_x, lower_left_y,
258 upper_right_x, upper_right_y,
259 advance, italic_correction) * scale;
261 current_x += ret.advance();
262 TTF::fgCurFontIdx = old_font_index;
266 inline mathtext::bounding_box_t
267 bounding_box(
const std::wstring
string,
268 const unsigned int family = FAMILY_PLAIN)
270 if (TTF::fgCurFontIdx<0)
return mathtext::bounding_box_t(0, 0, 0, 0, 0, 0);
271 if (
string.empty() || TTF::fgFace[TTF::fgCurFontIdx] == NULL ||
272 TTF::fgFace[TTF::fgCurFontIdx]->units_per_EM == 0) {
273 return mathtext::bounding_box_t(0, 0, 0, 0, 0, 0);
276 std::wstring::const_iterator iterator =
string.begin();
278 mathtext::bounding_box_t ret =
279 bounding_box(*iterator, current_x, family);
282 for (; iterator !=
string.end(); ++iterator) {
283 const mathtext::point_t position =
284 mathtext::point_t(current_x, 0);
285 const mathtext::bounding_box_t glyph_bounding_box =
286 bounding_box(*iterator, current_x, family);
287 ret = ret.merge(position + glyph_bounding_box);
293 text_raw(
const float x,
const float y,
294 const std::wstring
string,
295 const unsigned int family = FAMILY_PLAIN)
297 SetTextFont((Font_t) root_face_number(family));
298 SetTextSize(_current_font_size[family]);
305 for (std::wstring::const_iterator iterator =
string.begin(); iterator !=
string.end(); ++iterator) {
307 const bool cyrillic_or_cjk = is_cyrillic_or_cjk(buf[0]);
309 if (cyrillic_or_cjk) {
310 SetTextFont((Font_t) root_cjk_face_number());
314 const mathtext::bounding_box_t b =
315 bounding_box(buf, family);
319 transform_pad(xt, yt, x + advance, y);
320 gPad->PaintText(xt, yt, buf);
321 advance += b.advance();
322 if (cyrillic_or_cjk) {
323 SetTextFont((Font_t) root_face_number(family));
329 text_with_bounding_box(
const float ,
const float ,
334 using mathtext::math_text_renderer_t::bounding_box;
342 TMathText::TMathText(
void)
345 fRenderer =
new TMathTextRenderer(
this);
351 TMathText::TMathText(Double_t x, Double_t y,
const char *text)
352 : TText(x, y, text), TAttFill(0, 1001)
354 fRenderer =
new TMathTextRenderer(
this);
360 TMathText::~TMathText(
void)
367 TMathText::TMathText(
const TMathText &text)
368 : TText(text), TAttFill(text)
370 ((TMathText &)text).Copy(*
this);
371 fRenderer =
new TMathTextRenderer(
this);
377 TMathText &TMathText::operator=(
const TMathText &rhs)
380 TText::operator = (rhs);
381 TAttFill::operator = (rhs);
389 void TMathText::Copy(TObject &obj)
const
391 ((TMathText &)obj).fRenderer = fRenderer;
393 TAttFill::Copy((TAttFill &)obj);
400 Render(
const Double_t x,
const Double_t y,
const Double_t size,
401 const Double_t angle,
const Char_t *t,
const Int_t )
403 const mathtext::math_text_t math_text(t);
404 TMathTextRenderer *renderer = (TMathTextRenderer *)fRenderer;
406 renderer->set_parameter(x, y, size, angle);
407 renderer->text(0, 0, math_text);
414 GetSize(Double_t &x0, Double_t &y0, Double_t &x1, Double_t &y1,
415 const Double_t size,
const Double_t angle,
const Char_t *t,
418 const mathtext::math_text_t math_text(t);
419 TMathTextRenderer *renderer = (TMathTextRenderer *)fRenderer;
421 renderer->set_parameter(0, 0, size, angle);
423 const mathtext::bounding_box_t bounding_box =
424 renderer->bounding_box(math_text);
428 renderer->transform_pad(
429 x[0], y[0], bounding_box.left(), bounding_box.bottom());
430 renderer->transform_pad(
431 x[1], y[1], bounding_box.right(), bounding_box.bottom());
432 renderer->transform_pad(
433 x[2], y[2], bounding_box.right(), bounding_box.top());
434 renderer->transform_pad(
435 x[3], y[3], bounding_box.left(), bounding_box.top());
437 x0 = std::min(std::min(x[0], x[1]), std::min(x[2], x[3]));
438 y0 = std::min(std::min(y[0], y[1]), std::min(y[2], y[3]));
439 x1 = std::max(std::max(x[0], x[1]), std::max(x[2], x[3]));
440 y1 = std::max(std::max(y[0], y[1]), std::max(y[2], y[3]));
447 GetAlignPoint(Double_t &x0, Double_t &y0,
448 const Double_t size,
const Double_t angle,
449 const Char_t *t,
const Int_t ,
452 const mathtext::math_text_t math_text(t);
453 TMathTextRenderer *renderer = (TMathTextRenderer *)fRenderer;
455 renderer->set_parameter(0, 0, size, angle);
457 const mathtext::bounding_box_t bounding_box =
458 renderer->bounding_box(math_text);
462 Short_t halign = align / 10;
463 Short_t valign = align - 10 * halign;
466 case 0: x = bounding_box.left();
break;
467 case 1: x = 0;
break;
468 case 2: x = bounding_box.horizontal_center();
break;
469 case 3: x = bounding_box.right();
break;
472 case 0: y = bounding_box.bottom();
break;
473 case 1: y = 0;
break;
474 case 2: y = bounding_box.vertical_center();
break;
475 case 3: y = bounding_box.top();
break;
477 renderer->transform_pad(x0, y0, x, y);
483 void TMathText::GetBoundingBox(UInt_t &w, UInt_t &h, Bool_t )
485 const TString newText = GetTitle();
486 const Int_t length = newText.Length();
487 const Char_t *text = newText.Data();
488 const Double_t size = GetTextSize();
495 GetSize(x0, y0, x1, y1, size, 0, text, length);
496 w = (UInt_t)(TMath::Abs(gPad->XtoAbsPixel(x1) - gPad->XtoAbsPixel(x0)));
497 h = (UInt_t)(TMath::Abs(gPad->YtoAbsPixel(y0) - gPad->YtoAbsPixel(y1)));
503 Double_t TMathText::GetXsize(
void)
505 const TString newText = GetTitle();
506 const Int_t length = newText.Length();
507 const Char_t *text = newText.Data();
508 const Double_t size = GetTextSize();
509 const Double_t angle = GetTextAngle();
516 GetSize(x0, y0, x1, y1, size, angle, text, length);
518 return TMath::Abs(x1 - x0);
524 Double_t TMathText::GetYsize(
void)
526 const TString newText = GetTitle();
527 const Int_t length = newText.Length();
528 const Char_t *text = newText.Data();
529 const Double_t size = GetTextSize();
530 const Double_t angle = GetTextAngle();
537 GetSize(x0, y0, x1, y1, size, angle, text, length);
539 return TMath::Abs(y0 - y1);
546 TMathText *TMathText::DrawMathText(Double_t x, Double_t y,
const char *text)
548 TMathText *newtext =
new TMathText(x, y, text);
549 TAttText::Copy(*newtext);
551 newtext->SetBit(kCanDelete);
552 if (TestBit(kTextNDC)) newtext->SetNDC();
553 newtext->AppendPad();
561 void TMathText::Paint(Option_t *)
566 if (TestBit(kTextNDC)) {
567 fX = gPad->GetX1() + xsave * (gPad->GetX2() - gPad->GetX1());
568 fY = gPad->GetY1() + ysave * (gPad->GetY2() - gPad->GetY1());
569 PaintMathText(fX, fY, GetTextAngle(), GetTextSize(), GetTitle());
571 PaintMathText(gPad->XtoPad(fX), gPad->YtoPad(fY),
572 GetTextAngle(), GetTextSize(), GetTitle());
581 void TMathText::PaintMathText(Double_t x, Double_t y, Double_t angle,
582 Double_t size,
const Char_t *text1)
584 Double_t saveSize = size;
585 Int_t saveFont = fTextFont;
586 Short_t saveAlign = fTextAlign;
591 if (fTextFont % 10 < 2) {
593 gVirtualX->SetTextAngle(angle);
596 gVirtualPS->SetTextAngle(angle);
598 gPad->PaintText(x, y, text1);
602 if (fTextFont % 10 > 2) {
603 UInt_t w = TMath::Abs(gPad->XtoAbsPixel(gPad->GetX2()) -
604 gPad->XtoAbsPixel(gPad->GetX1()));
605 UInt_t h = TMath::Abs(gPad->YtoAbsPixel(gPad->GetY2()) -
606 gPad->YtoAbsPixel(gPad->GetY1()));
607 size = size / std::min(w, h);
608 SetTextFont(10 * (saveFont / 10) + 2);
611 TString newText = text1;
613 if (newText.Length() == 0)
return;
616 newText.ReplaceAll(
"\\omicron",
"o");
617 newText.ReplaceAll(
"\\Alpha",
"A");
618 newText.ReplaceAll(
"\\Beta",
"B");
619 newText.ReplaceAll(
"\\Epsilon",
"E");
620 newText.ReplaceAll(
"\\Zeta",
"Z");
621 newText.ReplaceAll(
"\\Eta",
"H");
622 newText.ReplaceAll(
"\\Iota",
"I");
623 newText.ReplaceAll(
"\\Kappa",
"K");
624 newText.ReplaceAll(
"\\Mu",
"M");
625 newText.ReplaceAll(
"\\Nu",
"N");
626 newText.ReplaceAll(
"\\Omicron",
"O");
627 newText.ReplaceAll(
"\\Rho",
"P");
628 newText.ReplaceAll(
"\\Tau",
"T");
629 newText.ReplaceAll(
"\\Chi",
"X");
630 newText.ReplaceAll(
"\\varomega",
"\\varpi");
631 newText.ReplaceAll(
"\\mbox",
"\\hbox");
632 newText.ReplaceAll(
"\\bar",
"\\wwbar");
633 if (newText.Contains(
"\\frac")) {
636 while (newText.Contains(
"\\frac")) {
637 len = newText.Length();
638 i1 = newText.Index(
"\\frac");
639 str = newText(i1,len).Data();
640 i2 = str.Index(
"}{");
641 newText.Replace(i1+i2,2,
" \\over ");
642 newText.Remove(i1,5);
645 if (newText.Contains(
"\\splitline")) {
648 while (newText.Contains(
"\\splitline")) {
649 len = newText.Length();
650 i1 = newText.Index(
"\\splitline");
651 str = newText(i1,len).Data();
652 i2 = str.Index(
"}{");
653 newText.Replace(i1+i2,2,
" \\atop ");
654 newText.Remove(i1,10);
658 const Int_t length = newText.Length();
659 const Char_t *text = newText.Data();
662 GetAlignPoint(x0, y0, size, angle, text, length, fTextAlign);
664 Render(x - x0, y - y0, size, angle, text, length);
666 SetTextSize(saveSize);
667 SetTextFont(saveFont);
668 SetTextAlign(saveAlign);
674 void TMathText::SavePrimitive(std::ostream &out, Option_t * )
676 const char quote =
'"';
678 if (gROOT->ClassSaved(TMathText::Class())) {
681 out <<
" TMathText *";
684 TString s = GetTitle();
686 s.ReplaceAll(
"\\",
"\\\\");
687 s.ReplaceAll(
"\"",
"\\\"");
688 out <<
"mathtex = new TMathText("<< fX <<
"," << fY <<
","
689 << quote << s.Data() << quote <<
");" << std::endl;
690 if (TestBit(kTextNDC)) {
691 out <<
"mathtex->SetNDC();" << std::endl;
694 SaveTextAttributes(out,
"mathtex", 11, 0, 1, 42, 0.05);
695 SaveFillAttributes(out,
"mathtex", 0, 1001);
697 out<<
" mathtex->Draw();" << std::endl;