1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkMathTextFreeTypeTextRenderer.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15
16 #include "vtkMathTextFreeTypeTextRenderer.h"
17
18 #include "vtkFreeTypeTools.h"
19 #include "vtkMathTextUtilities.h"
20 #include "vtkObjectFactory.h"
21 #include "vtkStdString.h"
22 #include "vtkUnicodeString.h"
23 #include "vtkTextProperty.h"
24
25 //------------------------------------------------------------------------------
vtkObjectFactoryNewMacro(vtkMathTextFreeTypeTextRenderer)26 vtkObjectFactoryNewMacro(vtkMathTextFreeTypeTextRenderer)
27
28 //------------------------------------------------------------------------------
29 void vtkMathTextFreeTypeTextRenderer::PrintSelf(ostream &os, vtkIndent indent)
30 {
31 this->Superclass::PrintSelf(os, indent);
32
33 if (this->FreeTypeTools)
34 {
35 os << indent << "FreeTypeTools:" << endl;
36 this->FreeTypeTools->PrintSelf(os, indent.GetNextIndent());
37 }
38 else
39 {
40 os << indent << "FreeTypeTools: (nullptr)" << endl;
41 }
42
43 if (this->MathTextUtilities)
44 {
45 os << indent << "MathTextUtilities:" << endl;
46 this->MathTextUtilities->PrintSelf(os, indent.GetNextIndent());
47 }
48 else
49 {
50 os << indent << "MathTextUtilities: (nullptr)" << endl;
51 }
52 }
53
54 //------------------------------------------------------------------------------
FreeTypeIsSupported()55 bool vtkMathTextFreeTypeTextRenderer::FreeTypeIsSupported()
56 {
57 return this->FreeTypeTools != nullptr;
58 }
59
60 //------------------------------------------------------------------------------
MathTextIsSupported()61 bool vtkMathTextFreeTypeTextRenderer::MathTextIsSupported()
62 {
63 return this->MathTextUtilities != nullptr &&
64 this->MathTextUtilities->IsAvailable();
65 }
66
67 //------------------------------------------------------------------------------
GetBoundingBoxInternal(vtkTextProperty * tprop,const vtkStdString & str,int bbox[4],int dpi,int backend)68 bool vtkMathTextFreeTypeTextRenderer::GetBoundingBoxInternal(
69 vtkTextProperty *tprop, const vtkStdString &str, int bbox[4], int dpi,
70 int backend)
71 {
72 if (!bbox || !tprop)
73 {
74 vtkErrorMacro("No bounding box container and/or text property supplied!");
75 return false;
76 }
77
78 memset(bbox, 0, 4 * sizeof(int));
79 if (str.empty())
80 {
81 return true;
82 }
83
84 if (static_cast<Backend>(backend) == Default)
85 {
86 backend = this->DefaultBackend;
87 }
88
89 if (static_cast<Backend>(backend) == Detect)
90 {
91 backend = static_cast<int>(this->DetectBackend(str));
92 }
93
94 switch (static_cast<Backend>(backend))
95 {
96 case MathText:
97 if (this->MathTextIsSupported())
98 {
99 if (this->MathTextUtilities->GetBoundingBox(tprop, str.c_str(), dpi,
100 bbox))
101 {
102 return true;
103 }
104 }
105 vtkDebugMacro("MathText unavailable. Falling back to FreeType.");
106 VTK_FALLTHROUGH;
107 case FreeType:
108 {
109 vtkStdString cleanString(str);
110 this->CleanUpFreeTypeEscapes(cleanString);
111 // Interpret string as UTF-8, use the UTF-16 GetBoundingBox overload:
112 return this->FreeTypeTools->GetBoundingBox(
113 tprop, vtkUnicodeString::from_utf8(cleanString), dpi, bbox);
114 }
115 case Default:
116 case UserBackend:
117 default:
118 vtkDebugMacro("Unrecognized backend requested: " << backend);
119 break;
120 case Detect:
121 vtkDebugMacro("Unhandled 'Detect' backend requested!");
122 break;
123 }
124 return false;
125 }
126
127 //------------------------------------------------------------------------------
GetBoundingBoxInternal(vtkTextProperty * tprop,const vtkUnicodeString & str,int bbox[],int dpi,int backend)128 bool vtkMathTextFreeTypeTextRenderer::GetBoundingBoxInternal(
129 vtkTextProperty *tprop, const vtkUnicodeString &str, int bbox[], int dpi,
130 int backend)
131 {
132 if (!bbox || !tprop)
133 {
134 vtkErrorMacro("No bounding box container and/or text property supplied!");
135 return false;
136 }
137
138 memset(bbox, 0, 4 * sizeof(int));
139 if (str.empty())
140 {
141 return true;
142 }
143
144 if (static_cast<Backend>(backend) == Default)
145 {
146 backend = this->DefaultBackend;
147 }
148
149 if (static_cast<Backend>(backend) == Detect)
150 {
151 backend = static_cast<int>(this->DetectBackend(str));
152 }
153
154 switch (static_cast<Backend>(backend))
155 {
156 case MathText:
157 if (this->MathTextIsSupported())
158 {
159 vtkDebugMacro("Converting UTF16 to UTF8 for MathText rendering.");
160 if (this->MathTextUtilities->GetBoundingBox(tprop, str.utf8_str(), dpi,
161 bbox))
162 {
163 return true;
164 }
165 }
166 vtkDebugMacro("MathText unavailable. Falling back to FreeType.");
167 VTK_FALLTHROUGH;
168 case FreeType:
169 {
170 vtkUnicodeString cleanString(str);
171 this->CleanUpFreeTypeEscapes(cleanString);
172 return this->FreeTypeTools->GetBoundingBox(tprop, cleanString, dpi, bbox);
173 }
174 case Default:
175 case UserBackend:
176 default:
177 vtkDebugMacro("Unrecognized backend requested: " << backend);
178 break;
179 case Detect:
180 vtkDebugMacro("Unhandled 'Detect' backend requested!");
181 break;
182 }
183 return false;
184 }
185
186 //------------------------------------------------------------------------------
GetMetricsInternal(vtkTextProperty * tprop,const vtkStdString & str,vtkTextRenderer::Metrics & metrics,int dpi,int backend)187 bool vtkMathTextFreeTypeTextRenderer::GetMetricsInternal(
188 vtkTextProperty *tprop, const vtkStdString &str,
189 vtkTextRenderer::Metrics &metrics, int dpi, int backend)
190 {
191 if (!tprop)
192 {
193 vtkErrorMacro("No text property supplied!");
194 return false;
195 }
196
197 metrics = Metrics();
198 if (str.empty())
199 {
200 return true;
201 }
202
203 if (static_cast<Backend>(backend) == Default)
204 {
205 backend = this->DefaultBackend;
206 }
207
208 if (static_cast<Backend>(backend) == Detect)
209 {
210 backend = static_cast<int>(this->DetectBackend(str));
211 }
212
213 switch (static_cast<Backend>(backend))
214 {
215 case MathText:
216 if (this->MathTextIsSupported())
217 {
218 if (this->MathTextUtilities->GetMetrics(tprop, str.c_str(), dpi,
219 metrics))
220 {
221 return true;
222 }
223 }
224 vtkDebugMacro("MathText unavailable. Falling back to FreeType.");
225 VTK_FALLTHROUGH;
226 case FreeType:
227 {
228 vtkStdString cleanString(str);
229 this->CleanUpFreeTypeEscapes(cleanString);
230 // Interpret string as UTF-8, use the UTF-16 GetBoundingBox overload:
231 return this->FreeTypeTools->GetMetrics(
232 tprop, vtkUnicodeString::from_utf8(cleanString), dpi, metrics);
233 }
234 case Default:
235 case UserBackend:
236 default:
237 vtkDebugMacro("Unrecognized backend requested: " << backend);
238 break;
239 case Detect:
240 vtkDebugMacro("Unhandled 'Detect' backend requested!");
241 break;
242 }
243 return false;
244 }
245
246 //------------------------------------------------------------------------------
GetMetricsInternal(vtkTextProperty * tprop,const vtkUnicodeString & str,vtkTextRenderer::Metrics & metrics,int dpi,int backend)247 bool vtkMathTextFreeTypeTextRenderer::GetMetricsInternal(
248 vtkTextProperty *tprop, const vtkUnicodeString &str,
249 vtkTextRenderer::Metrics &metrics, int dpi, int backend)
250 {
251 if (!tprop)
252 {
253 vtkErrorMacro("No text property supplied!");
254 return false;
255 }
256
257 metrics = Metrics();
258 if (str.empty())
259 {
260 return true;
261 }
262
263 if (static_cast<Backend>(backend) == Default)
264 {
265 backend = this->DefaultBackend;
266 }
267
268 if (static_cast<Backend>(backend) == Detect)
269 {
270 backend = static_cast<int>(this->DetectBackend(str));
271 }
272
273 switch (static_cast<Backend>(backend))
274 {
275 case MathText:
276 if (this->MathTextIsSupported())
277 {
278 vtkDebugMacro("Converting UTF16 to UTF8 for MathText rendering.");
279 if (this->MathTextUtilities->GetMetrics(tprop, str.utf8_str(), dpi,
280 metrics))
281 {
282 return true;
283 }
284 }
285 vtkDebugMacro("MathText unavailable. Falling back to FreeType.");
286 VTK_FALLTHROUGH;
287 case FreeType:
288 {
289 vtkUnicodeString cleanString(str);
290 this->CleanUpFreeTypeEscapes(cleanString);
291 return this->FreeTypeTools->GetMetrics(tprop, cleanString, dpi, metrics);
292 }
293 case Default:
294 case UserBackend:
295 default:
296 vtkDebugMacro("Unrecognized backend requested: " << backend);
297 break;
298 case Detect:
299 vtkDebugMacro("Unhandled 'Detect' backend requested!");
300 break;
301 }
302 return false;
303 }
304
305 //------------------------------------------------------------------------------
RenderStringInternal(vtkTextProperty * tprop,const vtkStdString & str,vtkImageData * data,int textDims[2],int dpi,int backend)306 bool vtkMathTextFreeTypeTextRenderer::RenderStringInternal(
307 vtkTextProperty *tprop, const vtkStdString &str, vtkImageData *data,
308 int textDims[2], int dpi, int backend)
309 {
310 if (!data || !tprop)
311 {
312 vtkErrorMacro("No image container and/or text property supplied!");
313 return false;
314 }
315
316 if (static_cast<Backend>(backend) == Default)
317 {
318 backend = this->DefaultBackend;
319 }
320
321 if (static_cast<Backend>(backend) == Detect)
322 {
323 backend = static_cast<int>(this->DetectBackend(str));
324 }
325
326 switch (static_cast<Backend>(backend))
327 {
328 case MathText:
329 if (this->MathTextIsSupported())
330 {
331 if (this->MathTextUtilities->RenderString(str.c_str(), data, tprop,
332 dpi, textDims))
333 {
334 return true;
335 }
336 }
337 vtkDebugMacro("MathText unavailable. Falling back to FreeType.");
338 VTK_FALLTHROUGH;
339 case FreeType:
340 {
341 vtkStdString cleanString(str);
342 this->CleanUpFreeTypeEscapes(cleanString);
343 // Interpret string as UTF-8, use the UTF-16 RenderString overload:
344 return this->FreeTypeTools->RenderString(
345 tprop, vtkUnicodeString::from_utf8(cleanString), dpi, data,
346 textDims);
347 }
348 case Default:
349 case UserBackend:
350 default:
351 vtkDebugMacro("Unrecognized backend requested: " << backend);
352 break;
353 case Detect:
354 vtkDebugMacro("Unhandled 'Detect' backend requested!");
355 break;
356 }
357 return false;
358 }
359
360 //------------------------------------------------------------------------------
RenderStringInternal(vtkTextProperty * tprop,const vtkUnicodeString & str,vtkImageData * data,int textDims[],int dpi,int backend)361 bool vtkMathTextFreeTypeTextRenderer::RenderStringInternal(
362 vtkTextProperty *tprop, const vtkUnicodeString &str, vtkImageData *data,
363 int textDims[], int dpi, int backend)
364 {
365 if (!data || !tprop)
366 {
367 vtkErrorMacro("No image container and/or text property supplied!");
368 return false;
369 }
370
371 if (static_cast<Backend>(backend) == Default)
372 {
373 backend = this->DefaultBackend;
374 }
375
376 if (static_cast<Backend>(backend) == Detect)
377 {
378 backend = static_cast<int>(this->DetectBackend(str));
379 }
380
381 switch (static_cast<Backend>(backend))
382 {
383 case MathText:
384 if (this->MathTextIsSupported())
385 {
386 vtkDebugMacro("Converting UTF16 to UTF8 for MathText rendering.");
387 if (this->MathTextUtilities->RenderString(str.utf8_str(), data, tprop,
388 dpi, textDims))
389 {
390 return true;
391 }
392 }
393 vtkDebugMacro("MathText unavailable. Falling back to FreeType.");
394 VTK_FALLTHROUGH;
395 case FreeType:
396 {
397 vtkUnicodeString cleanString(str);
398 this->CleanUpFreeTypeEscapes(cleanString);
399 return this->FreeTypeTools->RenderString(tprop, cleanString, dpi, data,
400 textDims);
401 }
402 case Default:
403 case UserBackend:
404 default:
405 vtkDebugMacro("Unrecognized backend requested: " << backend);
406 break;
407 case Detect:
408 vtkDebugMacro("Unhandled 'Detect' backend requested!");
409 break;
410 }
411 return false;
412 }
413
414 //------------------------------------------------------------------------------
GetConstrainedFontSizeInternal(const vtkStdString & str,vtkTextProperty * tprop,int targetWidth,int targetHeight,int dpi,int backend)415 int vtkMathTextFreeTypeTextRenderer::GetConstrainedFontSizeInternal(
416 const vtkStdString &str, vtkTextProperty *tprop, int targetWidth,
417 int targetHeight, int dpi, int backend)
418 {
419 if (!tprop)
420 {
421 vtkErrorMacro("No text property supplied!");
422 return false;
423 }
424
425 if (static_cast<Backend>(backend) == Default)
426 {
427 backend = this->DefaultBackend;
428 }
429
430 if (static_cast<Backend>(backend) == Detect)
431 {
432 backend = static_cast<int>(this->DetectBackend(str));
433 }
434
435 switch (static_cast<Backend>(backend))
436 {
437 case MathText:
438 if (this->MathTextIsSupported())
439 {
440 if (this->MathTextUtilities->GetConstrainedFontSize(str.c_str(), tprop,
441 targetWidth,
442 targetHeight,
443 dpi) != -1)
444 {
445 return tprop->GetFontSize();
446 }
447 }
448 vtkDebugMacro("MathText unavailable. Falling back to FreeType.");
449 VTK_FALLTHROUGH;
450 case FreeType:
451 {
452 vtkStdString cleanString(str);
453 this->CleanUpFreeTypeEscapes(cleanString);
454 return this->FreeTypeTools->GetConstrainedFontSize(cleanString, tprop,
455 dpi, targetWidth,
456 targetHeight);
457 }
458 case Default:
459 case UserBackend:
460 default:
461 vtkDebugMacro("Unrecognized backend requested: " << backend);
462 break;
463 case Detect:
464 vtkDebugMacro("Unhandled 'Detect' backend requested!");
465 break;
466 }
467 return false;
468 }
469
470 //------------------------------------------------------------------------------
GetConstrainedFontSizeInternal(const vtkUnicodeString & str,vtkTextProperty * tprop,int targetWidth,int targetHeight,int dpi,int backend)471 int vtkMathTextFreeTypeTextRenderer::GetConstrainedFontSizeInternal(
472 const vtkUnicodeString &str, vtkTextProperty *tprop, int targetWidth,
473 int targetHeight, int dpi, int backend)
474 {
475 if (!tprop)
476 {
477 vtkErrorMacro("No text property supplied!");
478 return false;
479 }
480
481 if (static_cast<Backend>(backend) == Default)
482 {
483 backend = this->DefaultBackend;
484 }
485
486 if (static_cast<Backend>(backend) == Detect)
487 {
488 backend = static_cast<int>(this->DetectBackend(str));
489 }
490
491 switch (static_cast<Backend>(backend))
492 {
493 case MathText:
494 if (this->MathTextIsSupported())
495 {
496 vtkDebugMacro("Converting UTF16 to UTF8 for MathText rendering.");
497 if (this->MathTextUtilities->GetConstrainedFontSize(str.utf8_str(),
498 tprop, targetWidth,
499 targetHeight,
500 dpi) != -1)
501 {
502 return tprop->GetFontSize();
503 }
504 }
505 vtkDebugMacro("MathText unavailable. Falling back to FreeType.");
506 VTK_FALLTHROUGH;
507 case FreeType:
508 {
509 vtkUnicodeString cleanString(str);
510 this->CleanUpFreeTypeEscapes(cleanString);
511 return this->FreeTypeTools->GetConstrainedFontSize(cleanString, tprop,
512 dpi, targetWidth,
513 targetHeight);
514 }
515 case Default:
516 case UserBackend:
517 default:
518 vtkDebugMacro("Unrecognized backend requested: " << backend);
519 break;
520 case Detect:
521 vtkDebugMacro("Unhandled 'Detect' backend requested!");
522 break;
523 }
524 return false;
525 }
526
527 //------------------------------------------------------------------------------
StringToPathInternal(vtkTextProperty * tprop,const vtkStdString & str,vtkPath * path,int dpi,int backend)528 bool vtkMathTextFreeTypeTextRenderer::StringToPathInternal(
529 vtkTextProperty *tprop, const vtkStdString &str, vtkPath *path, int dpi,
530 int backend)
531 {
532 if (!path || !tprop)
533 {
534 vtkErrorMacro("No path container and/or text property supplied!");
535 return false;
536 }
537
538 if (static_cast<Backend>(backend) == Default)
539 {
540 backend = this->DefaultBackend;
541 }
542
543 if (static_cast<Backend>(backend) == Detect)
544 {
545 backend = static_cast<int>(this->DetectBackend(str));
546 }
547
548 switch (static_cast<Backend>(backend))
549 {
550 case MathText:
551 if (this->MathTextIsSupported())
552 {
553 if (this->MathTextUtilities->StringToPath(str.c_str(), path, tprop,
554 dpi))
555 {
556 return true;
557 }
558 }
559 vtkDebugMacro("MathText unavailable. Falling back to FreeType.");
560 VTK_FALLTHROUGH;
561 case FreeType:
562 {
563 vtkStdString cleanString(str);
564 this->CleanUpFreeTypeEscapes(cleanString);
565 return this->FreeTypeTools->StringToPath(tprop, str, dpi, path);
566 }
567 case Default:
568 case UserBackend:
569 default:
570 vtkDebugMacro("Unrecognized backend requested: " << backend);
571 break;
572 case Detect:
573 vtkDebugMacro("Unhandled 'Detect' backend requested!");
574 break;
575 }
576 return false;
577 }
578
579 //------------------------------------------------------------------------------
StringToPathInternal(vtkTextProperty * tprop,const vtkUnicodeString & str,vtkPath * path,int dpi,int backend)580 bool vtkMathTextFreeTypeTextRenderer::StringToPathInternal(
581 vtkTextProperty *tprop, const vtkUnicodeString &str, vtkPath *path, int dpi,
582 int backend)
583 {
584 if (!path || !tprop)
585 {
586 vtkErrorMacro("No path container and/or text property supplied!");
587 return false;
588 }
589
590 if (static_cast<Backend>(backend) == Default)
591 {
592 backend = this->DefaultBackend;
593 }
594
595 if (static_cast<Backend>(backend) == Detect)
596 {
597 backend = static_cast<int>(this->DetectBackend(str));
598 }
599
600 switch (static_cast<Backend>(backend))
601 {
602 case MathText:
603 if (this->MathTextIsSupported())
604 {
605 vtkDebugMacro("Converting UTF16 to UTF8 for MathText rendering.");
606 if (this->MathTextUtilities->StringToPath(str.utf8_str(), path, tprop,
607 dpi))
608 {
609 return true;
610 }
611 }
612 vtkDebugMacro("MathText unavailable. Falling back to FreeType.");
613 VTK_FALLTHROUGH;
614 case FreeType:
615 {
616 vtkUnicodeString cleanString(str);
617 this->CleanUpFreeTypeEscapes(cleanString);
618 return this->FreeTypeTools->StringToPath(tprop, str, dpi, path);
619 }
620 case Default:
621 case UserBackend:
622 default:
623 vtkDebugMacro("Unrecognized backend requested: " << backend);
624 break;
625 case Detect:
626 vtkDebugMacro("Unhandled 'Detect' backend requested!");
627 break;
628 }
629 return false;
630 }
631
632 //------------------------------------------------------------------------------
SetScaleToPowerOfTwoInternal(bool scale)633 void vtkMathTextFreeTypeTextRenderer::SetScaleToPowerOfTwoInternal(bool scale)
634 {
635 if (this->FreeTypeTools)
636 {
637 this->FreeTypeTools->SetScaleToPowerTwo(scale);
638 }
639 if (this->MathTextUtilities)
640 {
641 this->MathTextUtilities->SetScaleToPowerOfTwo(scale);
642 }
643 }
644
645 //------------------------------------------------------------------------------
vtkMathTextFreeTypeTextRenderer()646 vtkMathTextFreeTypeTextRenderer::vtkMathTextFreeTypeTextRenderer()
647 {
648 this->FreeTypeTools = vtkFreeTypeTools::GetInstance();
649 this->MathTextUtilities = vtkMathTextUtilities::GetInstance();
650 }
651
652 //------------------------------------------------------------------------------
653 vtkMathTextFreeTypeTextRenderer::~vtkMathTextFreeTypeTextRenderer() = default;
654