KiCad PCB EDA Suite
Loading...
Searching...
No Matches
outline_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 <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <limits>
22#include <harfbuzz/hb.h>
23#include <harfbuzz/hb-ft.h>
24#include <bezier_curves.h>
26#include <font/fontconfig.h>
27#include <font/glyph_types.h>
28#include <font/outline_font.h>
29#include <ft2build.h>
30#include FT_FREETYPE_H
31#include FT_SFNT_NAMES_H
32#include FT_TRUETYPE_TABLES_H
33#include FT_GLYPH_H
34#include FT_BBOX_H
35#include <trigo.h>
36#include <core/utf8.h>
37
38using namespace KIFONT;
39
40
41FT_Library OUTLINE_FONT::m_freeType = nullptr;
43
45 m_face(NULL),
46 m_faceSize( 16 ),
47 m_fakeBold( false ),
48 m_fakeItal( false ),
49 m_forDrawingSheet( false )
50{
51 std::lock_guard<std::mutex> guard( m_freeTypeMutex );
52
53 if( !m_freeType )
54 FT_Init_FreeType( &m_freeType );
55}
56
57
59{
60 TT_OS2* os2 = reinterpret_cast<TT_OS2*>( FT_Get_Sfnt_Table( m_face, FT_SFNT_OS2 ) );
61
62 // If this table isn't present, we can't assume anything
63 if( !os2 )
65
66 // We don't support bitmap fonts, so this disables embedding
67 if( os2->fsType & FT_FSTYPE_BITMAP_EMBEDDING_ONLY )
69
70 // Per the OpenType spec, only bits 0-3 of fsType define the embedding license.
71 // Bits 8-9 (no-subsetting, bitmap-only) are independent modifiers and must be
72 // masked off before checking the embedding permission level.
73 // See: http://freetype.org/freetype2/docs/reference/ft2-information_retrieval.html
74 FT_UShort embeddingBits = os2->fsType & 0x000F;
75
76 // This allows the font to be exported from KiCad
77 if( embeddingBits == FT_FSTYPE_INSTALLABLE_EMBEDDING )
79
80 // This allows us to use the font in KiCad but not export
81 if( embeddingBits & FT_FSTYPE_EDITABLE_EMBEDDING )
83
84 // This is not actually supported by KiCad ATM(2024)
85 if( embeddingBits & FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING )
87
88 // Anything else that is not explicitly enabled we treat as restricted.
90}
91
92
93OUTLINE_FONT* OUTLINE_FONT::LoadFont( const wxString& aFontName, bool aBold, bool aItalic,
94 const std::vector<wxString>* aEmbeddedFiles, bool aForDrawingSheet )
95{
96 std::unique_ptr<OUTLINE_FONT> font = std::make_unique<OUTLINE_FONT>();
97
98 wxString fontFile;
99 int faceIndex;
100 using fc = fontconfig::FONTCONFIG;
101
102
103 fc::FF_RESULT retval = Fontconfig()->FindFont( aFontName, fontFile, faceIndex, aBold, aItalic, aEmbeddedFiles );
104
105 if( retval == fc::FF_RESULT::FF_ERROR )
106 return nullptr;
107
108 if( retval == fc::FF_RESULT::FF_MISSING_BOLD || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
109 font->SetFakeBold();
110
111 if( retval == fc::FF_RESULT::FF_MISSING_ITAL || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
112 font->SetFakeItal();
113
114 if( font->loadFace( fontFile, faceIndex ) != 0 )
115 return nullptr;
116
117 font->m_fontName = aFontName; // Keep asked-for name, even if we substituted.
118 font->m_fontFileName = fontFile;
119 font->m_forDrawingSheet = aForDrawingSheet;
120
121 return font.release();
122}
123
124
125FT_Error OUTLINE_FONT::loadFace( const wxString& aFontFileName, int aFaceIndex )
126{
127 std::lock_guard<std::mutex> guard( m_freeTypeMutex );
128
129 FT_Error e = FT_New_Face( m_freeType, aFontFileName.mb_str( wxConvUTF8 ), aFaceIndex, &m_face );
130
131 if( !e )
132 {
134 // params:
135 // m_face = handle to face object
136 // 0 = char width in 1/64th of points ( 0 = same as char height )
137 // faceSize() = char height in 1/64th of points
138 // GLYPH_RESOLUTION = horizontal device resolution (1152dpi, 16x default)
139 // 0 = vertical device resolution ( 0 = same as horizontal )
140 FT_Set_Char_Size( m_face, 0, faceSize(), GLYPH_RESOLUTION, 0 );
141 }
142
143 return e;
144}
145
146
147void OUTLINE_FONT::SelectCharmap( FT_Face aFace )
148{
149 // A normal text font carries a Unicode charmap that maps the Basic Latin block directly.
150 // Keep it when present.
151 if( FT_Select_Charmap( aFace, FT_ENCODING_UNICODE ) == 0 )
152 {
153 // Some legacy "symbol" fonts expose a Unicode charmap that only mirrors their private-use
154 // (U+F000..U+F0FF) glyph layout, leaving ASCII unmapped. Probe a few common characters to
155 // tell a usable Unicode charmap apart from such a font.
156 static const FT_ULong probes[] = { 'A', 'a', '0', ' ' };
157
158 for( FT_ULong codepoint : probes )
159 {
160 if( FT_Get_Char_Index( aFace, codepoint ) != 0 )
161 return;
162 }
163 }
164
165 // No Unicode charmap can resolve ASCII. If the font carries a Microsoft Symbol charmap,
166 // select it so HarfBuzz applies its U+F000 offset remapping and the glyphs become reachable.
167 if( FT_Select_Charmap( aFace, FT_ENCODING_MS_SYMBOL ) == 0 )
168 return;
169
170 // Otherwise fall back to the Unicode charmap (e.g. a CJK-only font with no Basic Latin).
171 FT_Select_Charmap( aFace, FT_ENCODING_UNICODE );
172}
173
174
175double OUTLINE_FONT::GetInterline( double aGlyphHeight, const METRICS& aFontMetrics ) const
176{
177 // The em-relative interline pitch already sets the line spacing; scaling it again by the face
178 // height / units_per_EM ratio double-counts and inflates spacing for non-default fonts
179 return aFontMetrics.GetInterline( aGlyphHeight );
180}
181
182
183static bool contourIsFilled( const CONTOUR& c )
184{
185 switch( c.m_Orientation )
186 {
187 case FT_ORIENTATION_TRUETYPE: return c.m_Winding == 1;
188 case FT_ORIENTATION_POSTSCRIPT: return c.m_Winding == -1;
189 default: return false;
190 }
191}
192
193
194static bool contourIsHole( const CONTOUR& c )
195{
196 return !contourIsFilled( c );
197}
198
199
200BOX2I OUTLINE_FONT::getBoundingBox( const std::vector<std::unique_ptr<GLYPH>>& aGlyphs ) const
201{
202 int minX = INT_MAX;
203 int minY = INT_MAX;
204 int maxX = INT_MIN;
205 int maxY = INT_MIN;
206
207 for( const std::unique_ptr<KIFONT::GLYPH>& glyph : aGlyphs )
208 {
209 BOX2D bbox = glyph->BoundingBox();
210 bbox.Normalize();
211
212 if( minX > bbox.GetX() )
213 minX = bbox.GetX();
214
215 if( minY > bbox.GetY() )
216 minY = bbox.GetY();
217
218 if( maxX < bbox.GetRight() )
219 maxX = bbox.GetRight();
220
221 if( maxY < bbox.GetBottom() )
222 maxY = bbox.GetBottom();
223 }
224
225 BOX2I ret;
226 ret.SetOrigin( minX, minY );
227 ret.SetEnd( maxX, maxY );
228 return ret;
229}
230
231
232void OUTLINE_FONT::GetLinesAsGlyphs( std::vector<std::unique_ptr<GLYPH>>* aGlyphs, const wxString& aText,
233 const VECTOR2I& aPosition, const TEXT_ATTRIBUTES& aAttrs,
234 const METRICS& aFontMetrics ) const
235{
236 wxArrayString strings;
237 std::vector<VECTOR2I> positions;
238 std::vector<VECTOR2I> extents;
239 TEXT_STYLE_FLAGS textStyle = 0;
240
241 if( aAttrs.m_Italic )
242 textStyle |= TEXT_STYLE::ITALIC;
243
244 getLinePositions( aText, aPosition, strings, positions, extents, aAttrs, aFontMetrics );
245
246 for( size_t i = 0; i < strings.GetCount(); i++ )
247 {
248 (void) drawMarkup( nullptr, aGlyphs, strings.Item( i ), positions[i], aAttrs.m_Size,
249 aAttrs.m_Angle.GetAngle(), aAttrs.m_Mirrored, aPosition, textStyle, aFontMetrics );
250 }
251}
252
253
254VECTOR2I OUTLINE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
255 const wxString& aText, const VECTOR2I& aSize, const VECTOR2I& aPosition,
256 const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
257 TEXT_STYLE_FLAGS aTextStyle ) const
258{
259 // HarfBuzz needs further processing to split tab-delimited text into text runs.
260
261 constexpr double TAB_WIDTH = 4 * 0.6;
262
263 VECTOR2I position = aPosition;
264 wxString textRun;
265
266 if( aBBox )
267 {
268 aBBox->SetOrigin( aPosition );
269 aBBox->SetEnd( aPosition );
270 }
271
272 for( wxUniChar c : aText )
273 {
274 // Handle tabs as locked to the nearest 4th column (in space-widths).
275 if( c == '\t' )
276 {
277 if( !textRun.IsEmpty() )
278 {
279 position = getTextAsGlyphs( aBBox, aGlyphs, textRun, aSize, position, aAngle, aMirror, aOrigin,
280 aTextStyle );
281 textRun.clear();
282 }
283
284 int tabWidth = KiROUND( aSize.x * TAB_WIDTH );
285 int currentIntrusion = ( position.x - aOrigin.x ) % tabWidth;
286
287 position.x += tabWidth - currentIntrusion;
288 }
289 else
290 {
291 textRun += c;
292 }
293 }
294
295 if( !textRun.IsEmpty() )
296 position = getTextAsGlyphs( aBBox, aGlyphs, textRun, aSize, position, aAngle, aMirror, aOrigin, aTextStyle );
297
298 return position;
299}
300
301
302VECTOR2I OUTLINE_FONT::getTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
303 const wxString& aText, const VECTOR2I& aSize, const VECTOR2I& aPosition,
304 const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
305 TEXT_STYLE_FLAGS aTextStyle ) const
306{
307 std::lock_guard<std::mutex> guard( m_freeTypeMutex );
308
309 return getTextAsGlyphsUnlocked( aBBox, aGlyphs, aText, aSize, aPosition, aAngle, aMirror, aOrigin, aTextStyle );
310}
311
312
314 FT_Face face;
315 std::string text;
317
318 bool operator==(const HARFBUZZ_CACHE_KEY& rhs ) const
319 {
320 return face == rhs.face
321 && scaler == rhs.scaler
322 && text == rhs.text;
323 }
324};
325
326
328{
329 std::vector<hb_glyph_info_t> m_GlyphInfo;
330 std::vector<hb_glyph_position_t> m_GlyphPositions;
331 bool m_Initialized = false;
332};
333
334
335namespace std
336{
337 template <>
339 {
340 std::size_t operator()( const HARFBUZZ_CACHE_KEY& k ) const
341 {
342 return hash_val( k.face, k.scaler, k.text );
343 }
344 };
345}
346
347
348static const HARFBUZZ_CACHE_ENTRY& getHarfbuzzShape( FT_Face aFace, const wxString& aText, int aScaler )
349{
350 static std::unordered_map<HARFBUZZ_CACHE_KEY, HARFBUZZ_CACHE_ENTRY> s_harfbuzzCache;
351
352 std::string textUtf8 = UTF8( aText );
353 HARFBUZZ_CACHE_KEY key = { aFace, textUtf8, aScaler };
354
355 HARFBUZZ_CACHE_ENTRY& entry = s_harfbuzzCache[key];
356
357 if( !entry.m_Initialized )
358 {
359 hb_buffer_t* buf = hb_buffer_create();
360 hb_buffer_add_utf8( buf, textUtf8.c_str(), -1, 0, -1 );
361 hb_buffer_guess_segment_properties( buf ); // guess direction, script, and language based on
362 // contents
363
364 hb_font_t* referencedFont = hb_ft_font_create_referenced( aFace );
365
366 hb_shape( referencedFont, buf, nullptr, 0 );
367
368 unsigned int glyphCount;
369 hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( buf, &glyphCount );
370 hb_glyph_position_t* glyphPos = hb_buffer_get_glyph_positions( buf, &glyphCount );
371
372 entry.m_GlyphInfo.assign( glyphInfo, glyphInfo + glyphCount );
373 entry.m_GlyphPositions.assign( glyphPos, glyphPos + glyphCount );
374 entry.m_Initialized = true;
375
376 hb_buffer_destroy( buf );
377 hb_font_destroy( referencedFont );
378 }
379
380 return entry;
381}
382
383
385 FT_Face face;
386 hb_codepoint_t codepoint;
391 bool mirror;
394
395 bool operator==(const GLYPH_CACHE_KEY& rhs ) const
396 {
397 return face == rhs.face
398 && codepoint == rhs.codepoint
399 && scale == rhs.scale
401 && fakeItalic == rhs.fakeItalic
402 && fakeBold == rhs.fakeBold
403 && mirror == rhs.mirror
404 && supersub == rhs.supersub
405 && angle == rhs.angle;
406 }
407};
408
409
410namespace std
411{
412 template <>
413 struct hash<GLYPH_CACHE_KEY>
414 {
415 std::size_t operator()( const GLYPH_CACHE_KEY& k ) const
416 {
417 return hash_val( k.face, k.codepoint, k.scale.x, k.scale.y, k.forDrawingSheet,
419 }
420 };
421}
422
423
424bool OUTLINE_FONT::LoadGlyphContours( unsigned int aGlyphIndex, std::vector<CONTOUR>& aContours ) const
425{
426 aContours.clear();
427
428 if( m_fakeItal )
429 {
430 FT_Matrix matrix;
431 // Create a 12 degree slant
432 const float angle = (float) ( -M_PI * 12.0f ) / 180.0f;
433 matrix.xx = (FT_Fixed) ( cos( angle ) * 0x10000L );
434 matrix.xy = (FT_Fixed) ( -sin( angle ) * 0x10000L );
435 matrix.yx = 0; // Don't rotate in the y direction
436 matrix.yy = 0x10000L;
437
438 FT_Set_Transform( m_face, &matrix, nullptr );
439 }
440
441 // FreeType clears the shared glyph slot before the font driver runs, so a failed load leaves
442 // an empty or partially parsed outline. Decomposing it would silently render nothing, so bail
443 // and let the caller draw a placeholder box instead.
444 if( FT_Load_Glyph( m_face, aGlyphIndex, FT_LOAD_NO_BITMAP ) != 0 )
445 return false;
446
447 // Bitmap-only fonts ignore FT_LOAD_NO_BITMAP and load without error, leaving no outline.
448 if( m_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE )
449 return false;
450
451 if( m_fakeBold )
452 FT_Outline_Embolden( &m_face->glyph->outline, 1 << 6 );
453
454 OUTLINE_DECOMPOSER decomposer( m_face->glyph->outline );
455
456 if( !decomposer.OutlineToSegments( &aContours ) )
457 {
458 aContours.clear();
459 return false;
460 }
461
462 return true;
463}
464
465
466VECTOR2I OUTLINE_FONT::getTextAsGlyphsUnlocked( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
467 const wxString& aText, const VECTOR2I& aSize,
468 const VECTOR2I& aPosition, const EDA_ANGLE& aAngle, bool aMirror,
469 const VECTOR2I& aOrigin, TEXT_STYLE_FLAGS aTextStyle ) const
470{
471 VECTOR2D glyphSize = aSize;
472 FT_Face face = m_face;
473 double scaler = faceSize();
474 bool supersub = IsSuperscript( aTextStyle ) || IsSubscript( aTextStyle );
475
476 if( supersub )
477 scaler = subscriptSize();
478
479 // set glyph resolution so that FT_Load_Glyph() results are good enough for decomposing
480 FT_Set_Char_Size( face, 0, scaler, GLYPH_RESOLUTION, 0 );
481
482 const HARFBUZZ_CACHE_ENTRY& hbShape = getHarfbuzzShape( face, aText, scaler );
483
484 unsigned int glyphCount = static_cast<unsigned int>( hbShape.m_GlyphInfo.size() );
485 const hb_glyph_info_t* glyphInfo = hbShape.m_GlyphInfo.data();
486 const hb_glyph_position_t* glyphPos = hbShape.m_GlyphPositions.data();
487
488 VECTOR2D scaleFactor( glyphSize.x / faceSize(), -glyphSize.y / faceSize() );
489 scaleFactor = scaleFactor * m_outlineFontSizeCompensation;
490
491 VECTOR2D origin( aPosition );
492
493 if( supersub )
494 origin.y += glyphSize.y * GetSuperSubSizeMultiplier() * GetSuperSubBaselineOffset( aTextStyle );
495
496 VECTOR2I cursor( 0, 0 );
497
498 if( aGlyphs )
499 aGlyphs->reserve( glyphCount );
500
501 // GLYPH_DATA is a collection of all outlines in the glyph; for example the 'o' glyph
502 // generally contains 2 contours, one for the glyph outline and one for the hole
503 static std::unordered_map<GLYPH_CACHE_KEY, GLYPH_DATA> s_glyphCache;
504
505 for( unsigned int i = 0; i < glyphCount; i++ )
506 {
507 if( aGlyphs )
508 {
509 GLYPH_CACHE_KEY key = { face, glyphInfo[i].codepoint, scaleFactor, m_forDrawingSheet, m_fakeItal,
510 m_fakeBold, aMirror, supersub, aAngle };
511 GLYPH_DATA& glyphData = s_glyphCache[ key ];
512
513 if( !glyphData.m_Loaded )
514 {
515 glyphData.m_Loaded = true;
516
517 if( !LoadGlyphContours( glyphInfo[i].codepoint, glyphData.m_Contours ) )
518 {
519 double hb_advance = glyphPos[i].x_advance * GLYPH_SIZE_SCALER;
520 BOX2D tofuBox( { scaler * 0.03, 0.0 }, { hb_advance - scaler * 0.02, scaler * 0.72 } );
521
522 CONTOUR outline;
523 outline.m_Winding = 1;
524 outline.m_Orientation = FT_ORIENTATION_TRUETYPE;
525 outline.m_Points.push_back( tofuBox.GetPosition() );
526 outline.m_Points.push_back( { tofuBox.GetSize().x, tofuBox.GetPosition().y } );
527 outline.m_Points.push_back( tofuBox.GetSize() );
528 outline.m_Points.push_back( { tofuBox.GetPosition().x, tofuBox.GetSize().y } );
529 glyphData.m_Contours.push_back( std::move( outline ) );
530
531 CONTOUR hole;
532 tofuBox.Move( { scaler * 0.06, scaler * 0.06 } );
533 tofuBox.SetSize( { tofuBox.GetWidth() - scaler * 0.06, tofuBox.GetHeight() - scaler * 0.06 } );
534 hole.m_Winding = 1;
535 hole.m_Orientation = FT_ORIENTATION_NONE;
536 hole.m_Points.push_back( tofuBox.GetPosition() );
537 hole.m_Points.push_back( { tofuBox.GetSize().x, tofuBox.GetPosition().y } );
538 hole.m_Points.push_back( tofuBox.GetSize() );
539 hole.m_Points.push_back( { tofuBox.GetPosition().x, tofuBox.GetSize().y } );
540 glyphData.m_Contours.push_back( std::move( hole ) );
541 }
542 }
543
544 std::unique_ptr<OUTLINE_GLYPH> glyph = std::make_unique<OUTLINE_GLYPH>();
545 std::vector<SHAPE_LINE_CHAIN> holes;
546
547 for( const CONTOUR& c : glyphData.m_Contours )
548 {
549 const std::vector<VECTOR2D>& points = c.m_Points;
550 SHAPE_LINE_CHAIN shape;
551
552 shape.ReservePoints( points.size() );
553
554 for( const VECTOR2D& v : points )
555 {
556 VECTOR2D pt( v + cursor );
557
558 pt *= scaleFactor;
559 pt += origin;
560
561 if( aMirror )
562 pt.x = aOrigin.x - ( pt.x - aOrigin.x );
563
564 if( !aAngle.IsZero() )
565 RotatePoint( pt, aOrigin, aAngle );
566
567 shape.Append( pt.x, pt.y );
568 }
569
570 shape.SetClosed( true );
571
572 if( contourIsHole( c ) )
573 holes.push_back( std::move( shape ) );
574 else
575 glyph->AddOutline( std::move( shape ) );
576 }
577
578 for( SHAPE_LINE_CHAIN& hole : holes )
579 {
580 bool added_hole = false;
581
582 if( hole.PointCount() )
583 {
584 for( int ii = 0; ii < glyph->OutlineCount(); ++ii )
585 {
586 if( glyph->Outline( ii ).PointInside( hole.GetPoint( 0 ) ) )
587 {
588 glyph->AddHole( std::move( hole ), ii );
589 added_hole = true;
590 break;
591 }
592 }
593
594 // Some lovely TTF fonts decided that winding didn't matter for outlines that
595 // don't have holes, so holes that don't fit in any outline are added as
596 // outlines.
597 if( !added_hole )
598 glyph->AddOutline( std::move( hole ) );
599 }
600 }
601
602 if( glyphData.m_TriangulationData.empty() )
603 {
604 glyph->CacheTriangulation();
605 glyphData.m_TriangulationData = glyph->GetTriangulationData();
606 }
607 else
608 {
609 glyph->CacheTriangulation( glyphData.m_TriangulationData );
610 }
611
612 aGlyphs->push_back( std::move( glyph ) );
613 }
614
615 const hb_glyph_position_t& pos = glyphPos[i];
616 cursor.x += ( pos.x_advance * GLYPH_SIZE_SCALER );
617 cursor.y += ( pos.y_advance * GLYPH_SIZE_SCALER );
618 }
619
620 int ascender = abs( face->size->metrics.ascender * GLYPH_SIZE_SCALER );
621 int descender = abs( face->size->metrics.descender * GLYPH_SIZE_SCALER );
622
623 if( aBBox )
624 {
625 aBBox->Merge( aPosition - VECTOR2I( 0, ascender * abs( scaleFactor.y ) ) );
626 aBBox->Merge( aPosition + VECTOR2I( cursor.x * scaleFactor.x, descender * abs( scaleFactor.y ) ) );
627 }
628
629 return VECTOR2I( aPosition.x + cursor.x * scaleFactor.x, aPosition.y - cursor.y * scaleFactor.y );
630}
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
BOX2< VECTOR2D > BOX2D
Definition box2.h:915
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:234
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:143
constexpr coord_type GetY() const
Definition box2.h:205
constexpr coord_type GetX() const
Definition box2.h:204
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:594
constexpr coord_type GetRight() const
Definition box2.h:214
constexpr void SetEnd(coord_type x, coord_type y)
Definition box2.h:294
constexpr coord_type GetBottom() const
Definition box2.h:219
double AsDegrees() const
Definition eda_angle.h:115
bool IsZero() const
Definition eda_angle.h:135
EDA_ANGLE GetAngle() const
Definition eda_angle.h:533
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:179
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:383
double GetInterline(double aFontHeight) const
bool OutlineToSegments(std::vector< CONTOUR > *aContours)
VECTOR2I getTextAsGlyphsUnlocked(BOX2I *aBoundingBox, 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
static void SelectCharmap(FT_Face aFace)
Select the charmap used to map characters to glyphs for aFace.
static std::mutex m_freeTypeMutex
Mutex for freetype access, FT_Library and FT_Face are not thread safe.
double GetInterline(double aGlyphHeight, const METRICS &aFontMetrics) const override
Compute the distance (interline) between 2 lines of text (for multiline texts).
double GetSuperSubBaselineOffset(TEXT_STYLE_FLAGS aTextStyle) const override
Return the baseline shift of a superscript or subscript run, as a downwards fraction of the reduced g...
static FT_Library m_freeType
BOX2I getBoundingBox(const std::vector< std::unique_ptr< GLYPH > > &aGlyphs) const
FT_Error loadFace(const wxString &aFontFileName, int aFaceIndex)
VECTOR2I getTextAsGlyphs(BOX2I *aBoundingBox, 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
bool LoadGlyphContours(unsigned int aGlyphIndex, std::vector< CONTOUR > &aContours) const
Load a single glyph into the shared FreeType slot and decompose its outline into line-chain contours.
VECTOR2I GetTextAsGlyphs(BOX2I *aBoundingBox, 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 override
Convert text string to an array of GLYPHs.
int faceSize(int aSize) const
void GetLinesAsGlyphs(std::vector< std::unique_ptr< GLYPH > > *aGlyphs, const wxString &aText, const VECTOR2I &aPosition, const TEXT_ATTRIBUTES &aAttrs, const METRICS &aFontMetrics) const
static OUTLINE_FONT * LoadFont(const wxString &aFontFileName, bool aBold, bool aItalic, const std::vector< wxString > *aEmbeddedFiles, bool aForDrawingSheet)
Load an outline font.
static constexpr double m_outlineFontSizeCompensation
EMBEDDING_PERMISSION GetEmbeddingPermission() const
double GetSuperSubSizeMultiplier() const override
Return the factor the text size is multiplied by for a superscript or subscript run.
int subscriptSize() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
void ReservePoints(size_t aSize)
Allocate a number of points all at once (for performance).
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
EDA_ORIENTATION m_Angle
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition utf8.h:67
FF_RESULT FindFont(const wxString &aFontName, wxString &aFontFile, int &aFaceIndex, bool aBold, bool aItalic, const std::vector< wxString > *aEmbeddedFiles=nullptr)
Given a fully-qualified font name ("Times:Bold:Italic") find the closest matching font and return its...
@ ITALIC
Definition font.h:44
unsigned int TEXT_STYLE_FLAGS
Definition font.h:61
bool IsSuperscript(TEXT_STYLE_FLAGS aFlags)
Definition font.h:76
bool IsSubscript(TEXT_STYLE_FLAGS aFlags)
Definition font.h:82
FONTCONFIG * Fontconfig()
static constexpr std::size_t hash_val(const Types &... args)
Definition hash.h:48
constexpr int GLYPH_RESOLUTION
constexpr double GLYPH_SIZE_SCALER
STL namespace.
static bool contourIsHole(const CONTOUR &c)
static bool contourIsFilled(const CONTOUR &c)
static const HARFBUZZ_CACHE_ENTRY & getHarfbuzzShape(FT_Face aFace, const wxString &aText, int aScaler)
hb_codepoint_t codepoint
bool operator==(const GLYPH_CACHE_KEY &rhs) const
std::vector< hb_glyph_info_t > m_GlyphInfo
std::vector< hb_glyph_position_t > m_GlyphPositions
bool m_Initialized
bool operator==(const HARFBUZZ_CACHE_KEY &rhs) const
std::vector< VECTOR2D > m_Points
FT_Orientation m_Orientation
std::vector< CONTOUR > m_Contours
std::vector< std::unique_ptr< SHAPE_POLY_SET::TRIANGULATED_POLYGON > > m_TriangulationData
std::size_t operator()(const GLYPH_CACHE_KEY &k) const
std::size_t operator()(const HARFBUZZ_CACHE_KEY &k) const
#define M_PI
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:227
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707