KiCad PCB EDA Suite
Loading...
Searching...
No Matches
font.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KICAD, a free EDA CAD application.
3 *
4 * Copyright (C) 2021 Ola Rinta-Koski
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * Font abstract base class
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27#include <list>
28#include <mutex>
29#include <unordered_map>
30
31#include <macros.h>
32#include <string_utils.h>
34#include <font/stroke_font.h>
35#include <font/outline_font.h>
36#include <trigo.h>
37#include <markup_parser.h>
38
39// The "official" name of the Kicad stroke font (always existing)
41#include <wx/tokenzr.h>
42
43// markup_parser.h includes pegtl.hpp which includes windows.h... which leaks #define DrawText
44#undef DrawText
45
46
47using namespace KIFONT;
48
50
51
53{
54 return g_defaultMetrics;
55}
56
57
58FONT* FONT::s_defaultFont = nullptr;
59
60std::map< std::tuple<wxString, bool, bool, bool>, FONT*> FONT::s_fontMap;
61
63{
64public:
65 struct ENTRY
66 {
67 std::string source;
68 std::unique_ptr<MARKUP::NODE> root;
69 };
70
71 MARKUP_CACHE( size_t aMaxSize ) :
72 m_maxSize( aMaxSize )
73 {
74 }
75
76 ENTRY& Put( const wxString& aQuery, ENTRY&& aResult )
77 {
78 auto it = m_cache.find( aQuery );
79
80 m_cacheMru.emplace_front( std::make_pair( aQuery, std::move( aResult ) ) );
81
82 if( it != m_cache.end() )
83 {
84 m_cacheMru.erase( it->second );
85 m_cache.erase( it );
86 }
87
88 m_cache[aQuery] = m_cacheMru.begin();
89
90 if( m_cache.size() > m_maxSize )
91 {
92 auto last = m_cacheMru.end();
93 last--;
94 m_cache.erase( last->first );
95 m_cacheMru.pop_back();
96 }
97
98 return m_cacheMru.begin()->second;
99 }
100
101 ENTRY* Get( const wxString& aQuery )
102 {
103 auto it = m_cache.find( aQuery );
104
105 if( it == m_cache.end() )
106 return nullptr;
107
108 m_cacheMru.splice( m_cacheMru.begin(), m_cacheMru, it->second );
109
110 return &m_cacheMru.begin()->second;
111 }
112
113 void Clear()
114 {
115 m_cacheMru.clear();
116 m_cache.clear();
117 }
118
119private:
120 size_t m_maxSize;
121 std::list<std::pair<wxString, ENTRY>> m_cacheMru;
122 std::unordered_map<wxString, std::list<std::pair<wxString, ENTRY>>::iterator> m_cache;
123};
124
125
127static std::mutex s_markupCacheMutex;
128static std::mutex s_defaultFontMutex;;
129
130
132{
133}
134
135
137{
138 std::lock_guard lock( s_defaultFontMutex );
139
140 if( !s_defaultFont )
141 s_defaultFont = STROKE_FONT::LoadFont( wxEmptyString );
142
143 return s_defaultFont;
144}
145
146
147FONT* FONT::GetFont( const wxString& aFontName, bool aBold, bool aItalic,
148 const std::vector<wxString>* aEmbeddedFiles, bool aForDrawingSheet )
149{
150 if( aFontName.empty() || aFontName.StartsWith( KICAD_FONT_NAME ) )
151 return getDefaultFont();
152
153 std::tuple<wxString, bool, bool, bool> key = { aFontName, aBold, aItalic, aForDrawingSheet };
154
155 FONT* font = nullptr;
156
157 if( s_fontMap.find( key ) != s_fontMap.end() )
158 font = s_fontMap[key];
159
160 if( !font )
161 font = OUTLINE_FONT::LoadFont( aFontName, aBold, aItalic, aEmbeddedFiles,
162 aForDrawingSheet );
163
164 if( !font )
165 font = getDefaultFont();
166
167 s_fontMap[key] = font;
168
169 return font;
170}
171
172
173bool FONT::IsStroke( const wxString& aFontName )
174{
175 // This would need a more complex implementation if we ever support more stroke fonts
176 // than the KiCad Font.
177 return aFontName == _( "Default Font" ) || aFontName == KICAD_FONT_NAME;
178}
179
180
181void FONT::getLinePositions( const wxString& aText, const VECTOR2I& aPosition,
182 wxArrayString& aTextLines, std::vector<VECTOR2I>& aPositions,
183 std::vector<VECTOR2I>& aExtents, const TEXT_ATTRIBUTES& aAttrs,
184 const METRICS& aFontMetrics ) const
185{
186 wxStringSplit( aText, aTextLines, '\n' );
187 int lineCount = aTextLines.Count();
188 aPositions.reserve( lineCount );
189
190 int interline = GetInterline( aAttrs.m_Size.y, aFontMetrics ) * aAttrs.m_LineSpacing;
191 int height = 0;
192
193 for( int i = 0; i < lineCount; i++ )
194 {
195 VECTOR2I pos( aPosition.x, aPosition.y + i * interline );
196 VECTOR2I end = boundingBoxSingleLine( nullptr, aTextLines[i], pos, aAttrs.m_Size,
197 aAttrs.m_Italic, aFontMetrics );
198 VECTOR2I bBox( end - pos );
199
200 aExtents.push_back( bBox );
201
202 if( i == 0 )
203 height += ( aAttrs.m_Size.y * 1.17 ); // 1.17 is a fudge to match 6.0 positioning
204 else
205 height += interline;
206 }
207
208 VECTOR2I offset( 0, 0 );
209 offset.y += aAttrs.m_Size.y;
210
211 if( IsStroke() )
212 {
213 // Fudge factors to match 6.0 positioning
214 offset.x += aAttrs.m_StrokeWidth / 1.52;
215 offset.y -= aAttrs.m_StrokeWidth * 0.052;
216 }
217
218 switch( aAttrs.m_Valign )
219 {
220 case GR_TEXT_V_ALIGN_TOP: break;
221 case GR_TEXT_V_ALIGN_CENTER: offset.y -= height / 2; break;
222 case GR_TEXT_V_ALIGN_BOTTOM: offset.y -= height; break;
224 wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
225 break;
226 }
227
228 for( int i = 0; i < lineCount; i++ )
229 {
230 VECTOR2I lineSize = aExtents.at( i );
231 VECTOR2I lineOffset( offset );
232
233 lineOffset.y += i * interline;
234
235 switch( aAttrs.m_Halign )
236 {
237 case GR_TEXT_H_ALIGN_LEFT: break;
238 case GR_TEXT_H_ALIGN_CENTER: lineOffset.x = -lineSize.x / 2; break;
239 case GR_TEXT_H_ALIGN_RIGHT: lineOffset.x = -( lineSize.x + offset.x ); break;
241 wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
242 break;
243 }
244
245 aPositions.push_back( aPosition + lineOffset );
246 }
247}
248
249
250void FONT::Draw( KIGFX::GAL* aGal, const wxString& aText, const VECTOR2I& aPosition, const VECTOR2I& aCursor,
251 const TEXT_ATTRIBUTES& aAttrs, const METRICS& aFontMetrics, std::optional<VECTOR2I> aMousePos,
252 wxString* aActiveUrl ) const
253{
254 if( !aGal || aText.empty() )
255 return;
256
257 VECTOR2I position( aPosition - aCursor );
258
259 // Split multiline strings into separate ones and draw them line by line
260 wxArrayString strings_list;
261 std::vector<VECTOR2I> positions;
262 std::vector<VECTOR2I> extents;
263
264 getLinePositions( aText, position, strings_list, positions, extents, aAttrs, aFontMetrics );
265
266 aGal->SetLineWidth( aAttrs.m_StrokeWidth );
267
268 for( size_t i = 0; i < strings_list.GetCount(); i++ )
269 {
270 drawSingleLineText( aGal, nullptr, strings_list[i], positions[i], aAttrs.m_Size, aAttrs.m_Angle,
271 aAttrs.m_Mirrored, aPosition, aAttrs.m_Italic, aAttrs.m_Underlined, aAttrs.m_Hover,
272 aFontMetrics, aMousePos, aActiveUrl );
273 }
274}
275
276
280VECTOR2I drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs, const MARKUP::NODE* aNode,
281 const VECTOR2I& aPosition, const KIFONT::FONT* aFont, const VECTOR2I& aSize,
282 const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin, TEXT_STYLE_FLAGS aTextStyle,
283 const METRICS& aFontMetrics, std::optional<VECTOR2I> aMousePos, wxString* aActiveUrl )
284{
285 VECTOR2I nextPosition = aPosition;
286 bool drawUnderline = false;
287 bool drawOverbar = false;
288 bool useHoverColor = false;
289 int start = aGlyphs ? (int) aGlyphs->size() : 0;
290
291
292 if( aNode )
293 {
294 TEXT_STYLE_FLAGS textStyle = aTextStyle;
295
296 if( !aNode->is_root() )
297 {
298 if( aNode->isSubscript() )
299 textStyle |= TEXT_STYLE::SUBSCRIPT;
300 else if( aNode->isSuperscript() )
301 textStyle |= TEXT_STYLE::SUPERSCRIPT;
302
303 if( aNode->isOverbar() )
304 drawOverbar = true;
305
306 if( aTextStyle & TEXT_STYLE::UNDERLINE )
307 drawUnderline = true;
308
309 if( aNode->has_content() )
310 {
311 BOX2I bbox;
312
313 nextPosition = aFont->GetTextAsGlyphs( &bbox, aGlyphs, aNode->asWxString(), aSize,
314 nextPosition, aAngle, aMirror, aOrigin, textStyle );
315
316 if( aBoundingBox )
317 aBoundingBox->Merge( bbox );
318
319 if( aNode->isURL() && aMousePos.has_value() && bbox.Contains( aMousePos.value() ) )
320 {
321 useHoverColor = true;
322 drawUnderline = true;
323 }
324 }
325 }
326
327 for( const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
328 {
329 nextPosition = drawMarkup( aBoundingBox, aGlyphs, child.get(), nextPosition, aFont, aSize,
330 aAngle, aMirror, aOrigin, textStyle, aFontMetrics, aMousePos,
331 aActiveUrl );
332 }
333 }
334
335 if( drawUnderline )
336 {
337 // Shorten the bar a little so its rounded ends don't make it over-long
338 double barTrim = aSize.x * 0.1;
339 double barOffset = aFontMetrics.GetUnderlineVerticalPosition( aSize.y );
340
341 VECTOR2D barStart( aPosition.x + barTrim, aPosition.y - barOffset );
342 VECTOR2D barEnd( nextPosition.x - barTrim, nextPosition.y - barOffset );
343
344 if( aGlyphs )
345 {
346 STROKE_GLYPH barGlyph;
347
348 barGlyph.AddPoint( barStart );
349 barGlyph.AddPoint( barEnd );
350 barGlyph.Finalize();
351
352 aGlyphs->push_back( barGlyph.Transform( { 1.0, 1.0 }, { 0, 0 }, false, aAngle, aMirror,
353 aOrigin ) );
354 }
355 }
356
357 if( drawOverbar )
358 {
359 // Shorten the bar a little so its rounded ends don't make it over-long
360 double barTrim = aSize.x * 0.1;
361 double barOffset = aFontMetrics.GetOverbarVerticalPosition( aSize.y );
362
363 VECTOR2D barStart( aPosition.x + barTrim, aPosition.y - barOffset );
364 VECTOR2D barEnd( nextPosition.x - barTrim, nextPosition.y - barOffset );
365
366 if( aGlyphs )
367 {
368 STROKE_GLYPH barGlyph;
369
370 barGlyph.AddPoint( barStart );
371 barGlyph.AddPoint( barEnd );
372 barGlyph.Finalize();
373
374 aGlyphs->push_back( barGlyph.Transform( { 1.0, 1.0 }, { 0, 0 }, false, aAngle, aMirror,
375 aOrigin ) );
376 }
377 }
378
379 if( useHoverColor )
380 {
381 for( int ii = start; ii < (int) aGlyphs->size(); ++ii )
382 (*aGlyphs)[ii]->SetIsHover( true );
383
384 if( aActiveUrl )
385 *aActiveUrl = aNode->asWxString();
386 }
387
388 return nextPosition;
389}
390
391
392VECTOR2I FONT::drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
393 const wxString& aText, const VECTOR2I& aPosition, const VECTOR2I& aSize,
394 const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
395 TEXT_STYLE_FLAGS aTextStyle, const METRICS& aFontMetrics,
396 std::optional<VECTOR2I> aMousePos, wxString* aActiveUrl ) const
397{
398 std::lock_guard<std::mutex> lock( s_markupCacheMutex );
399
400 MARKUP_CACHE::ENTRY* markup = s_markupCache.Get( aText );
401
402 if( !markup || !markup->root )
403 {
404 MARKUP_CACHE::ENTRY& cached = s_markupCache.Put( aText, {} );
405
406 cached.source = TO_UTF8( aText );
407 MARKUP::MARKUP_PARSER markupParser( &cached.source );
408 cached.root = markupParser.Parse();
409 markup = &cached;
410 }
411
412 wxASSERT( markup && markup->root );
413
414 return ::drawMarkup( aBoundingBox, aGlyphs, markup->root.get(), aPosition, this, aSize, aAngle,
415 aMirror, aOrigin, aTextStyle, aFontMetrics, aMousePos, aActiveUrl );
416}
417
418
419void FONT::drawSingleLineText( KIGFX::GAL* aGal, BOX2I* aBoundingBox, const wxString& aText,
420 const VECTOR2I& aPosition, const VECTOR2I& aSize, const EDA_ANGLE& aAngle,
421 bool aMirror, const VECTOR2I& aOrigin, bool aItalic, bool aUnderline,
422 bool aHover, const METRICS& aFontMetrics, std::optional<VECTOR2I> aMousePos,
423 wxString* aActiveUrl ) const
424{
425 if( !aGal )
426 return;
427
428 TEXT_STYLE_FLAGS textStyle = 0;
429
430 if( aItalic )
431 textStyle |= TEXT_STYLE::ITALIC;
432
433 if( aUnderline )
434 textStyle |= TEXT_STYLE::UNDERLINE;
435
436 std::vector<std::unique_ptr<GLYPH>> glyphs;
437
438 (void) drawMarkup( aBoundingBox, &glyphs, aText, aPosition, aSize, aAngle, aMirror, aOrigin,
439 textStyle, aFontMetrics, aMousePos, aActiveUrl );
440
441 if( aHover )
442 {
443 for( std::unique_ptr<GLYPH>& glyph : glyphs )
444 glyph->SetIsHover( true );
445 }
446
447 aGal->DrawGlyphs( glyphs );
448}
449
450
451VECTOR2I FONT::StringBoundaryLimits( const wxString& aText, const VECTOR2I& aSize, int aThickness,
452 bool aBold, bool aItalic, const METRICS& aFontMetrics ) const
453{
454 // TODO do we need to parse every time - have we already parsed?
456 TEXT_STYLE_FLAGS textStyle = 0;
457
458 if( aBold )
459 textStyle |= TEXT_STYLE::BOLD;
460
461 if( aItalic )
462 textStyle |= TEXT_STYLE::ITALIC;
463
464 (void) drawMarkup( &boundingBox, nullptr, aText, VECTOR2I(), aSize, ANGLE_0, false, VECTOR2I(),
465 textStyle, aFontMetrics );
466
467 if( IsStroke() )
468 {
469 // Inflate by a bit more than thickness/2 to catch diacriticals, descenders, etc.
470 boundingBox.Inflate( KiROUND( aThickness * 1.5 ) );
471 }
472 else if( IsOutline() )
473 {
474 // Outline fonts have thickness built in, and *usually* stay within their ascent/descent
475 }
476
477 return boundingBox.GetSize();
478}
479
480
481VECTOR2I FONT::boundingBoxSingleLine( BOX2I* aBBox, const wxString& aText,
482 const VECTOR2I& aPosition, const VECTOR2I& aSize,
483 bool aItalic, const METRICS& aFontMetrics ) const
484{
485 TEXT_STYLE_FLAGS textStyle = 0;
486
487 if( aItalic )
488 textStyle |= TEXT_STYLE::ITALIC;
489
490 VECTOR2I extents = drawMarkup( aBBox, nullptr, aText, aPosition, aSize, ANGLE_0, false,
491 VECTOR2I(), textStyle, aFontMetrics );
492
493 return extents;
494}
495
496
503void wordbreakMarkup( std::vector<std::pair<wxString, int>>* aWords,
504 const std::unique_ptr<MARKUP::NODE>& aNode, const KIFONT::FONT* aFont,
505 const VECTOR2I& aSize, TEXT_STYLE_FLAGS aTextStyle )
506{
507 TEXT_STYLE_FLAGS textStyle = aTextStyle;
508
509 if( !aNode->is_root() )
510 {
511 wxChar escapeChar = 0;
512
513 if( aNode->isSubscript() )
514 {
515 escapeChar = '_';
516 textStyle = TEXT_STYLE::SUBSCRIPT;
517 }
518 else if( aNode->isSuperscript() )
519 {
520 escapeChar = '^';
521 textStyle = TEXT_STYLE::SUPERSCRIPT;
522 }
523
524 if( aNode->isOverbar() )
525 {
526 escapeChar = '~';
527 textStyle |= TEXT_STYLE::OVERBAR;
528 }
529
530 if( escapeChar )
531 {
532 wxString word = wxString::Format( wxT( "%c{" ), escapeChar );
533 int width = 0;
534
535 if( aNode->has_content() )
536 {
537 VECTOR2I next = aFont->GetTextAsGlyphs( nullptr, nullptr, aNode->asWxString(),
538 aSize, { 0, 0 }, ANGLE_0, false, { 0, 0 },
539 textStyle );
540 word += aNode->asWxString();
541 width += next.x;
542 }
543
544 std::vector<std::pair<wxString, int>> childWords;
545
546 for( const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
547 wordbreakMarkup( &childWords, child, aFont, aSize, textStyle );
548
549 for( const std::pair<wxString, int>& childWord : childWords )
550 {
551 word += childWord.first;
552 width += childWord.second;
553 }
554
555 word += wxT( "}" );
556 aWords->emplace_back( std::make_pair( word, width ) );
557 return;
558 }
559 else
560 {
561 wxString textRun = aNode->asWxString();
562 wxStringTokenizer tokenizer( textRun, " ", wxTOKEN_RET_DELIMS );
563 std::vector<wxString> words;
564
565 while( tokenizer.HasMoreTokens() )
566 words.emplace_back( tokenizer.GetNextToken() );
567
568 for( const wxString& word : words )
569 {
570 wxString chars = word;
571 chars.Trim();
572
573 int w = aFont->GetTextAsGlyphs( nullptr, nullptr, chars, aSize, { 0, 0 },
574 ANGLE_0, false, { 0, 0 }, textStyle ).x;
575
576 aWords->emplace_back( std::make_pair( word, w ) );
577 }
578 }
579 }
580
581 for( const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
582 wordbreakMarkup( aWords, child, aFont, aSize, textStyle );
583}
584
585
586void FONT::wordbreakMarkup( std::vector<std::pair<wxString, int>>* aWords, const wxString& aText,
587 const VECTOR2I& aSize, TEXT_STYLE_FLAGS aTextStyle ) const
588{
589 MARKUP::MARKUP_PARSER markupParser( TO_UTF8( aText ) );
590 std::unique_ptr<MARKUP::NODE> root = markupParser.Parse();
591
592 ::wordbreakMarkup( aWords, root, this, aSize, aTextStyle );
593}
594
595
596void FONT::LinebreakText( wxString& aText, int aColumnWidth, const VECTOR2I& aSize, int aThickness,
597 bool aBold, bool aItalic ) const
598{
599 TEXT_STYLE_FLAGS textStyle = 0;
600
601 if( aBold )
602 textStyle |= TEXT_STYLE::BOLD;
603
604 if( aItalic )
605 textStyle |= TEXT_STYLE::ITALIC;
606
607 int spaceWidth = GetTextAsGlyphs( nullptr, nullptr, wxS( " " ), aSize, VECTOR2I(), ANGLE_0,
608 false, VECTOR2I(), textStyle ).x;
609
610 wxArrayString textLines;
611 wxStringSplit( aText, textLines, '\n' );
612
613 aText = wxEmptyString;
614
615 for( size_t ii = 0; ii < textLines.Count(); ++ii )
616 {
617 std::vector<std::pair<wxString, int>> markup;
618 std::vector<std::pair<wxString, int>> words;
619
620 wordbreakMarkup( &markup, textLines[ii], aSize, textStyle );
621
622 for( const auto& [ run, runWidth ] : markup )
623 {
624 if( !words.empty() && !words.back().first.EndsWith( ' ' ) )
625 {
626 words.back().first += run;
627 words.back().second += runWidth;
628 }
629 else
630 {
631 words.emplace_back( std::make_pair( run, runWidth ) );
632 }
633 }
634
635 bool buryMode = false;
636 int lineWidth = 0;
637 wxString pendingSpaces;
638
639 for( const auto& [ word, wordWidth ] : words )
640 {
641 int pendingSpaceWidth = (int) pendingSpaces.Length() * spaceWidth;
642 bool overflow = lineWidth + pendingSpaceWidth + wordWidth > aColumnWidth - aThickness;
643
644 if( overflow && pendingSpaces.Length() > 0 )
645 {
646 aText += '\n';
647 lineWidth = 0;
648 pendingSpaces = wxEmptyString;
649 pendingSpaceWidth = 0;
650 buryMode = true;
651 }
652
653 if( word == wxS( " " ) )
654 {
655 pendingSpaces += word;
656 }
657 else
658 {
659 if( buryMode )
660 {
661 buryMode = false;
662 }
663 else
664 {
665 aText += pendingSpaces;
666 lineWidth += pendingSpaceWidth;
667 }
668
669 if( word.EndsWith( ' ' ) )
670 {
671 aText += word.Left( word.Length() - 1 );
672 pendingSpaces = wxS( " " );
673 }
674 else
675 {
676 aText += word;
677 pendingSpaces = wxEmptyString;
678 }
679
680 lineWidth += wordWidth;
681 }
682 }
683
684 // Add the newlines back onto the string
685 if( ii != ( textLines.Count() - 1 ) )
686 aText += '\n';
687 }
688}
689
690
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:658
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:168
FONT is an abstract base class for both outline and stroke fonts.
Definition font.h:131
VECTOR2I boundingBoxSingleLine(BOX2I *aBBox, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aSize, bool aItalic, const METRICS &aFontMetrics) const
Compute the bounding box for a single line of text.
Definition font.cpp:481
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
Definition font.cpp:147
virtual bool IsStroke() const
Definition font.h:138
static FONT * s_defaultFont
Definition font.h:303
void getLinePositions(const wxString &aText, const VECTOR2I &aPosition, wxArrayString &aTextLines, std::vector< VECTOR2I > &aPositions, std::vector< VECTOR2I > &aExtents, const TEXT_ATTRIBUTES &aAttrs, const METRICS &aFontMetrics) const
Definition font.cpp:181
void wordbreakMarkup(std::vector< std::pair< wxString, int > > *aWords, const wxString &aText, const VECTOR2I &aSize, TEXT_STYLE_FLAGS aTextStyle) const
Definition font.cpp:586
void Draw(KIGFX::GAL *aGal, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aCursor, const TEXT_ATTRIBUTES &aAttributes, const METRICS &aFontMetrics, std::optional< VECTOR2I > aMousePos=std::nullopt, wxString *aActiveUrl=nullptr) const
Draw a string.
Definition font.cpp:250
void drawSingleLineText(KIGFX::GAL *aGal, BOX2I *aBoundingBox, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aAngle, bool aMirror, const VECTOR2I &aOrigin, bool aItalic, bool aUnderline, bool aHover, const METRICS &aFontMetrics, std::optional< VECTOR2I > aMousePos, wxString *aActiveUrl) const
Draw a single line of text.
Definition font.cpp:419
virtual bool IsOutline() const
Definition font.h:139
VECTOR2I drawMarkup(BOX2I *aBoundingBox, std::vector< std::unique_ptr< GLYPH > > *aGlyphs, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aAngle, bool aMirror, const VECTOR2I &aOrigin, TEXT_STYLE_FLAGS aTextStyle, const METRICS &aFontMetrics, std::optional< VECTOR2I > aMousePos=std::nullopt, wxString *aActiveUrl=nullptr) const
Definition font.cpp:392
VECTOR2I StringBoundaryLimits(const wxString &aText, const VECTOR2I &aSize, int aThickness, bool aBold, bool aItalic, const METRICS &aFontMetrics) const
Compute the boundary limits of aText (the bounding box of all shapes).
Definition font.cpp:451
static std::map< std::tuple< wxString, bool, bool, bool >, FONT * > s_fontMap
Definition font.h:305
virtual double GetInterline(double aGlyphHeight, const METRICS &aFontMetrics) const =0
Compute the distance (interline) between 2 lines of text (for multiline texts).
virtual VECTOR2I GetTextAsGlyphs(BOX2I *aBBox, std::vector< std::unique_ptr< GLYPH > > *aGlyphs, const wxString &aText, const VECTOR2I &aSize, const VECTOR2I &aPosition, const EDA_ANGLE &aAngle, bool aMirror, const VECTOR2I &aOrigin, TEXT_STYLE_FLAGS aTextStyle) const =0
Convert text string to an array of GLYPHs.
static FONT * getDefaultFont()
Definition font.cpp:136
void LinebreakText(wxString &aText, int aColumnWidth, const VECTOR2I &aGlyphSize, int aThickness, bool aBold, bool aItalic) const
Insert characters into text to ensure that no lines are wider than aColumnWidth.
Definition font.cpp:596
double GetUnderlineVerticalPosition(double aGlyphHeight) const
Compute the vertical position of an underline.
Definition font.h:109
double GetOverbarVerticalPosition(double aGlyphHeight) const
Compute the vertical position of an overbar.
Definition font.h:100
static const METRICS & Default()
Definition font.cpp:52
static OUTLINE_FONT * LoadFont(const wxString &aFontFileName, bool aBold, bool aItalic, const std::vector< wxString > *aEmbeddedFiles, bool aForDrawingSheet)
Load an outline font.
static STROKE_FONT * LoadFont(const wxString &aFontName)
Load a stroke font.
void AddPoint(const VECTOR2D &aPoint)
Definition glyph.cpp:39
std::unique_ptr< GLYPH > Transform(const VECTOR2D &aGlyphSize, const VECTOR2I &aOffset, double aTilt, const EDA_ANGLE &aAngle, bool aMirror, const VECTOR2I &aOrigin)
Definition glyph.cpp:74
Abstract interface for drawing on a 2D-surface.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
virtual void DrawGlyphs(const std::vector< std::unique_ptr< KIFONT::GLYPH > > &aGlyphs)
Draw polygons representing font glyphs.
std::unique_ptr< NODE > Parse()
std::list< std::pair< wxString, ENTRY > > m_cacheMru
Definition font.cpp:121
MARKUP_CACHE(size_t aMaxSize)
Definition font.cpp:71
ENTRY & Put(const wxString &aQuery, ENTRY &&aResult)
Definition font.cpp:76
void Clear()
Definition font.cpp:113
size_t m_maxSize
Definition font.cpp:120
ENTRY * Get(const wxString &aQuery)
Definition font.cpp:101
std::unordered_map< wxString, std::list< std::pair< wxString, ENTRY > >::iterator > m_cache
Definition font.cpp:122
GR_TEXT_H_ALIGN_T m_Halign
GR_TEXT_V_ALIGN_T m_Valign
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
METRICS g_defaultMetrics
Definition font.cpp:49
static std::mutex s_markupCacheMutex
Definition font.cpp:127
void wordbreakMarkup(std::vector< std::pair< wxString, int > > *aWords, const std::unique_ptr< MARKUP::NODE > &aNode, const KIFONT::FONT *aFont, const VECTOR2I &aSize, TEXT_STYLE_FLAGS aTextStyle)
Break marked-up text into "words".
Definition font.cpp:503
static std::mutex s_defaultFontMutex
Definition font.cpp:128
static MARKUP_CACHE s_markupCache(1024)
VECTOR2I drawMarkup(BOX2I *aBoundingBox, std::vector< std::unique_ptr< GLYPH > > *aGlyphs, const MARKUP::NODE *aNode, const VECTOR2I &aPosition, const KIFONT::FONT *aFont, const VECTOR2I &aSize, const EDA_ANGLE &aAngle, bool aMirror, const VECTOR2I &aOrigin, TEXT_STYLE_FLAGS aTextStyle, const METRICS &aFontMetrics, std::optional< VECTOR2I > aMousePos, wxString *aActiveUrl)
Definition font.cpp:280
@ BOLD
Definition font.h:46
@ SUBSCRIPT
Definition font.h:48
@ OVERBAR
Definition font.h:50
@ UNDERLINE
Definition font.h:51
@ ITALIC
Definition font.h:47
@ SUPERSCRIPT
Definition font.h:49
unsigned int TEXT_STYLE_FLAGS
Definition font.h:64
#define KICAD_FONT_NAME
This file contains miscellaneous commonly used macros and functions.
CITER next(CITER it)
Definition ptree.cpp:124
BOX2I boundingBox(T aObject, int aLayer)
Used by SHAPE_INDEX to get the bounding box of a generic T object.
Definition shape_index.h:62
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Split aString to a string list separated at aSplitter.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
bool isOverbar() const
bool isURL() const
bool isSuperscript() const
wxString asWxString() const
bool isSubscript() const
std::unique_ptr< MARKUP::NODE > root
Definition font.cpp:68
std::string source
Definition font.cpp:67
VECTOR2I end
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_H_ALIGN_INDETERMINATE
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_INDETERMINATE
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694