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 (C) 2021-2024 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, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <limits>
26#include <harfbuzz/hb.h>
27#include <harfbuzz/hb-ft.h>
28#include <bezier_curves.h>
30#include <font/fontconfig.h>
31#include <font/outline_font.h>
32#include <ft2build.h>
33#include FT_FREETYPE_H
34#include FT_SFNT_NAMES_H
35#include FT_TRUETYPE_TABLES_H
36#include FT_GLYPH_H
37#include FT_BBOX_H
38#include <trigo.h>
39#include <core/utf8.h>
40
41using namespace KIFONT;
42
43
44FT_Library OUTLINE_FONT::m_freeType = nullptr;
46
48 m_face(NULL),
49 m_faceSize( 16 ),
50 m_fakeBold( false ),
51 m_fakeItal( false )
52{
53 std::lock_guard<std::mutex> guard( m_freeTypeMutex );
54
55 if( !m_freeType )
56 FT_Init_FreeType( &m_freeType );
57}
58
59
61{
62 TT_OS2* os2 = reinterpret_cast<TT_OS2*>( FT_Get_Sfnt_Table( m_face, FT_SFNT_OS2 ) );
63
64 // If this table isn't present, we can't assume anything
65 if( !os2 )
67
68 if( os2->fsType == FT_FSTYPE_INSTALLABLE_EMBEDDING ) // This allows the font to be exported from KiCad
70
71 if( os2->fsType & FT_FSTYPE_BITMAP_EMBEDDING_ONLY ) // We don't support bitmap fonts, so this disables embedding
73
74 if( os2->fsType & FT_FSTYPE_EDITABLE_EMBEDDING ) // This allows us to use the font in KiCad but not export
76
77 if( os2->fsType & FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING ) // This is not actually supported by KiCad ATM(2024)
79
80 // Anything else that is not explicitly enabled we treat as restricted.
82}
83
84
85OUTLINE_FONT* OUTLINE_FONT::LoadFont( const wxString& aFontName, bool aBold, bool aItalic,
86 const std::vector<wxString>* aEmbeddedFiles )
87{
88 std::unique_ptr<OUTLINE_FONT> font = std::make_unique<OUTLINE_FONT>();
89
90 wxString fontFile;
91 int faceIndex;
92 using fc = fontconfig::FONTCONFIG;
93
94
95 fc::FF_RESULT retval = Fontconfig()->FindFont( aFontName, fontFile, faceIndex, aBold, aItalic,
96 aEmbeddedFiles );
97
98 if( retval == fc::FF_RESULT::FF_ERROR )
99 return nullptr;
100
101 if( retval == fc::FF_RESULT::FF_MISSING_BOLD || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
102 font->SetFakeBold();
103
104 if( retval == fc::FF_RESULT::FF_MISSING_ITAL || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
105 font->SetFakeItal();
106
107 if( font->loadFace( fontFile, faceIndex ) != 0 )
108 return nullptr;
109
110 font->m_fontName = aFontName; // Keep asked-for name, even if we substituted.
111 font->m_fontFileName = fontFile;
112
113 return font.release();
114}
115
116
117FT_Error OUTLINE_FONT::loadFace( const wxString& aFontFileName, int aFaceIndex )
118{
119 std::lock_guard<std::mutex> guard( m_freeTypeMutex );
120
121 FT_Error e = FT_New_Face( m_freeType, aFontFileName.mb_str( wxConvUTF8 ), aFaceIndex, &m_face );
122
123 if( !e )
124 {
125 FT_Select_Charmap( m_face, FT_Encoding::FT_ENCODING_UNICODE );
126 // params:
127 // m_face = handle to face object
128 // 0 = char width in 1/64th of points ( 0 = same as char height )
129 // faceSize() = char height in 1/64th of points
130 // GLYPH_RESOLUTION = horizontal device resolution (1152dpi, 16x default)
131 // 0 = vertical device resolution ( 0 = same as horizontal )
132 FT_Set_Char_Size( m_face, 0, faceSize(), GLYPH_RESOLUTION, 0 );
133 }
134
135 return e;
136}
137
138
143double OUTLINE_FONT::GetInterline( double aGlyphHeight, const METRICS& aFontMetrics ) const
144{
145 double glyphToFontHeight = 1.0;
146
147 if( GetFace()->units_per_EM )
148 glyphToFontHeight = GetFace()->height / GetFace()->units_per_EM;
149
150 return aFontMetrics.GetInterline( aGlyphHeight * glyphToFontHeight );
151}
152
153
154static bool contourIsFilled( const CONTOUR& c )
155{
156 switch( c.m_Orientation )
157 {
158 case FT_ORIENTATION_TRUETYPE: return c.m_Winding == 1;
159 case FT_ORIENTATION_POSTSCRIPT: return c.m_Winding == -1;
160 default: return false;
161 }
162}
163
164
165static bool contourIsHole( const CONTOUR& c )
166{
167 return !contourIsFilled( c );
168}
169
170
171BOX2I OUTLINE_FONT::getBoundingBox( const std::vector<std::unique_ptr<GLYPH>>& aGlyphs ) const
172{
173 int minX = INT_MAX;
174 int minY = INT_MAX;
175 int maxX = INT_MIN;
176 int maxY = INT_MIN;
177
178 for( const std::unique_ptr<KIFONT::GLYPH>& glyph : aGlyphs )
179 {
180 BOX2D bbox = glyph->BoundingBox();
181 bbox.Normalize();
182
183 if( minX > bbox.GetX() )
184 minX = bbox.GetX();
185
186 if( minY > bbox.GetY() )
187 minY = bbox.GetY();
188
189 if( maxX < bbox.GetRight() )
190 maxX = bbox.GetRight();
191
192 if( maxY < bbox.GetBottom() )
193 maxY = bbox.GetBottom();
194 }
195
196 BOX2I ret;
197 ret.SetOrigin( minX, minY );
198 ret.SetEnd( maxX, maxY );
199 return ret;
200}
201
202
203void OUTLINE_FONT::GetLinesAsGlyphs( std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
204 const wxString& aText, const VECTOR2I& aPosition,
205 const TEXT_ATTRIBUTES& aAttrs,
206 const METRICS& aFontMetrics ) const
207{
208 wxArrayString strings;
209 std::vector<VECTOR2I> positions;
210 std::vector<VECTOR2I> extents;
211 TEXT_STYLE_FLAGS textStyle = 0;
212
213 if( aAttrs.m_Italic )
214 textStyle |= TEXT_STYLE::ITALIC;
215
216 getLinePositions( aText, aPosition, strings, positions, extents, aAttrs, aFontMetrics );
217
218 for( size_t i = 0; i < strings.GetCount(); i++ )
219 {
220 (void) drawMarkup( nullptr, aGlyphs, strings.Item( i ), positions[i], aAttrs.m_Size,
221 aAttrs.m_Angle, aAttrs.m_Mirrored, aPosition, textStyle, aFontMetrics );
222 }
223}
224
225
226VECTOR2I OUTLINE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
227 const wxString& aText, const VECTOR2I& aSize,
228 const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
229 bool aMirror, const VECTOR2I& aOrigin,
230 TEXT_STYLE_FLAGS aTextStyle ) const
231{
232 // HarfBuzz needs further processing to split tab-delimited text into text runs.
233
234 constexpr double TAB_WIDTH = 4 * 0.6;
235
236 VECTOR2I position = aPosition;
237 wxString textRun;
238
239 if( aBBox )
240 {
241 aBBox->SetOrigin( aPosition );
242 aBBox->SetEnd( aPosition );
243 }
244
245 for( wxUniChar c : aText )
246 {
247 // Handle tabs as locked to the nearest 4th column (in space-widths).
248 if( c == '\t' )
249 {
250 if( !textRun.IsEmpty() )
251 {
252 position = getTextAsGlyphs( aBBox, aGlyphs, textRun, aSize, position, aAngle,
253 aMirror, aOrigin, aTextStyle );
254 textRun.clear();
255 }
256
257 int tabWidth = KiROUND( aSize.x * TAB_WIDTH );
258 int currentIntrusion = ( position.x - aOrigin.x ) % tabWidth;
259
260 position.x += tabWidth - currentIntrusion;
261 }
262 else
263 {
264 textRun += c;
265 }
266 }
267
268 if( !textRun.IsEmpty() )
269 {
270 position = getTextAsGlyphs( aBBox, aGlyphs, textRun, aSize, position, aAngle, aMirror,
271 aOrigin, aTextStyle );
272 }
273
274 return position;
275}
276
277
278VECTOR2I OUTLINE_FONT::getTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
279 const wxString& aText, const VECTOR2I& aSize,
280 const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
281 bool aMirror, const VECTOR2I& aOrigin,
282 TEXT_STYLE_FLAGS aTextStyle ) const
283{
284 std::lock_guard<std::mutex> guard( m_freeTypeMutex );
285
286 return getTextAsGlyphsUnlocked( aBBox, aGlyphs, aText, aSize, aPosition, aAngle, aMirror,
287 aOrigin, aTextStyle );
288}
289
290
292 FT_Face face;
293 hb_codepoint_t codepoint;
294 double scaler;
297 bool mirror;
299
300 bool operator==(const GLYPH_CACHE_KEY& rhs ) const
301 {
302 return face == rhs.face && codepoint == rhs.codepoint && scaler == rhs.scaler
303 && fakeItalic == rhs.fakeItalic && fakeBold == rhs.fakeBold
304 && mirror == rhs.mirror && angle == rhs.angle;
305 }
306};
307
308namespace std
309{
310 template <>
311 struct hash<GLYPH_CACHE_KEY>
312 {
313 std::size_t operator()( const GLYPH_CACHE_KEY& k ) const
314 {
315 return hash<const void*>()( k.face ) ^ hash<unsigned>()( k.codepoint )
316 ^ hash<double>()( k.scaler )
317 ^ hash<int>()( k.fakeItalic ) ^ hash<int>()( k.fakeBold )
318 ^ hash<int>()( k.mirror ) ^ hash<int>()( k.angle.AsTenthsOfADegree() );
319 }
320 };
321}
322
323
325 std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
326 const wxString& aText, const VECTOR2I& aSize,
327 const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
328 bool aMirror, const VECTOR2I& aOrigin,
329 TEXT_STYLE_FLAGS aTextStyle ) const
330{
331 VECTOR2D glyphSize = aSize;
332 FT_Face face = m_face;
333 double scaler = faceSize();
334
335 if( IsSubscript( aTextStyle ) || IsSuperscript( aTextStyle ) )
336 {
337 scaler = subscriptSize();
338 }
339
340 // set glyph resolution so that FT_Load_Glyph() results are good enough for decomposing
341 FT_Set_Char_Size( face, 0, scaler, GLYPH_RESOLUTION, 0 );
342
343 hb_buffer_t* buf = hb_buffer_create();
344 hb_buffer_add_utf8( buf, UTF8( aText ).c_str(), -1, 0, -1 );
345 hb_buffer_guess_segment_properties( buf ); // guess direction, script, and language based on
346 // contents
347
348 hb_font_t* referencedFont = hb_ft_font_create_referenced( face );
349 hb_ft_font_set_funcs( referencedFont );
350 hb_shape( referencedFont, buf, nullptr, 0 );
351
352 unsigned int glyphCount;
353 hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( buf, &glyphCount );
354 hb_glyph_position_t* glyphPos = hb_buffer_get_glyph_positions( buf, &glyphCount );
355
356 VECTOR2D scaleFactor( glyphSize.x / faceSize(), -glyphSize.y / faceSize() );
357 scaleFactor = scaleFactor * m_outlineFontSizeCompensation;
358
359 VECTOR2I cursor( 0, 0 );
360
361 if( aGlyphs )
362 aGlyphs->reserve( glyphCount );
363
364 // GLYPH_DATA is a collection of all outlines in the glyph; for example the 'o' glyph
365 // generally contains 2 contours, one for the glyph outline and one for the hole
366 static std::unordered_map<GLYPH_CACHE_KEY, GLYPH_DATA> s_glyphCache;
367
368 for( unsigned int i = 0; i < glyphCount; i++ )
369 {
370 // Don't process glyphs that were already included in a previous cluster
371 if( i > 0 && glyphInfo[i].cluster == glyphInfo[i-1].cluster )
372 continue;
373
374 if( aGlyphs )
375 {
376 GLYPH_CACHE_KEY key = { face, glyphInfo[i].codepoint, scaler, m_fakeItal, m_fakeBold,
377 aMirror, aAngle };
378 GLYPH_DATA& glyphData = s_glyphCache[ key ];
379
380 if( glyphData.m_Contours.empty() )
381 {
382 if( m_fakeItal )
383 {
384 FT_Matrix matrix;
385 // Create a 12 degree slant
386 const float angle = (float)( -M_PI * 12.0f ) / 180.0f;
387 matrix.xx = (FT_Fixed) ( cos( angle ) * 0x10000L );
388 matrix.xy = (FT_Fixed) ( -sin( angle ) * 0x10000L );
389 matrix.yx = (FT_Fixed) ( 0 * 0x10000L ); // Don't rotate in the y direction
390 matrix.yy = (FT_Fixed) ( 1 * 0x10000L );
391
392 FT_Set_Transform( face, &matrix, nullptr );
393 }
394
395 FT_Load_Glyph( face, glyphInfo[i].codepoint, FT_LOAD_NO_BITMAP );
396
397 if( m_fakeBold )
398 FT_Outline_Embolden( &face->glyph->outline, 1 << 6 );
399
400 OUTLINE_DECOMPOSER decomposer( face->glyph->outline );
401
402 if( !decomposer.OutlineToSegments( &glyphData.m_Contours ) )
403 {
404 double hb_advance = glyphPos[i].x_advance * GLYPH_SIZE_SCALER;
405 BOX2D tofuBox( { scaler * 0.03, 0.0 },
406 { hb_advance - scaler * 0.02, scaler * 0.72 } );
407
408 glyphData.m_Contours.clear();
409
410 CONTOUR outline;
411 outline.m_Winding = 1;
412 outline.m_Orientation = FT_ORIENTATION_TRUETYPE;
413 outline.m_Points.push_back( tofuBox.GetPosition() );
414 outline.m_Points.push_back( { tofuBox.GetSize().x, tofuBox.GetPosition().y } );
415 outline.m_Points.push_back( tofuBox.GetSize() );
416 outline.m_Points.push_back( { tofuBox.GetPosition().x, tofuBox.GetSize().y } );
417 glyphData.m_Contours.push_back( outline );
418
419 CONTOUR hole;
420 tofuBox.Move( { scaler * 0.06, scaler * 0.06 } );
421 tofuBox.SetSize( { tofuBox.GetWidth() - scaler * 0.06,
422 tofuBox.GetHeight() - scaler * 0.06 } );
423 hole.m_Winding = 1;
424 hole.m_Orientation = FT_ORIENTATION_NONE;
425 hole.m_Points.push_back( tofuBox.GetPosition() );
426 hole.m_Points.push_back( { tofuBox.GetSize().x, tofuBox.GetPosition().y } );
427 hole.m_Points.push_back( tofuBox.GetSize() );
428 hole.m_Points.push_back( { tofuBox.GetPosition().x, tofuBox.GetSize().y } );
429 glyphData.m_Contours.push_back( hole );
430 }
431 }
432
433 std::unique_ptr<OUTLINE_GLYPH> glyph = std::make_unique<OUTLINE_GLYPH>();
434 std::vector<SHAPE_LINE_CHAIN> holes;
435
436 for( CONTOUR& c : glyphData.m_Contours )
437 {
438 std::vector<VECTOR2D> points = c.m_Points;
439 SHAPE_LINE_CHAIN shape;
440
441 shape.ReservePoints( points.size() );
442
443 for( const VECTOR2D& v : points )
444 {
445 VECTOR2D pt( v + cursor );
446
447 if( IsSubscript( aTextStyle ) )
448 pt.y += m_subscriptVerticalOffset * scaler;
449 else if( IsSuperscript( aTextStyle ) )
450 pt.y += m_superscriptVerticalOffset * scaler;
451
452 pt *= scaleFactor;
453 pt += aPosition;
454
455 if( aMirror )
456 pt.x = aOrigin.x - ( pt.x - aOrigin.x );
457
458 if( !aAngle.IsZero() )
459 RotatePoint( pt, aOrigin, aAngle );
460
461 shape.Append( pt.x, pt.y );
462 }
463
464 shape.SetClosed( true );
465
466 if( contourIsHole( c ) )
467 holes.push_back( std::move( shape ) );
468 else
469 glyph->AddOutline( std::move( shape ) );
470 }
471
472 for( SHAPE_LINE_CHAIN& hole : holes )
473 {
474 if( hole.PointCount() )
475 {
476 for( int ii = 0; ii < glyph->OutlineCount(); ++ii )
477 {
478 if( glyph->Outline( ii ).PointInside( hole.GetPoint( 0 ) ) )
479 {
480 glyph->AddHole( std::move( hole ), ii );
481 break;
482 }
483 }
484 }
485 }
486
487 if( glyphData.m_TriangulationData.empty() )
488 {
489 glyph->CacheTriangulation( false, false );
490 glyphData.m_TriangulationData = glyph->GetTriangulationData();
491 }
492 else
493 {
494 glyph->CacheTriangulation( glyphData.m_TriangulationData );
495 }
496
497 aGlyphs->push_back( std::move( glyph ) );
498 }
499
500 hb_glyph_position_t& pos = glyphPos[i];
501 cursor.x += ( pos.x_advance * GLYPH_SIZE_SCALER );
502 cursor.y += ( pos.y_advance * GLYPH_SIZE_SCALER );
503 }
504
505 int ascender = abs( face->size->metrics.ascender * GLYPH_SIZE_SCALER );
506 int descender = abs( face->size->metrics.descender * GLYPH_SIZE_SCALER );
507 VECTOR2I extents( cursor.x * scaleFactor.x, ( ascender + descender ) * abs( scaleFactor.y ) );
508
509 hb_buffer_destroy( buf );
510 hb_font_destroy( referencedFont );
511
512 VECTOR2I cursorDisplacement( cursor.x * scaleFactor.x, -cursor.y * scaleFactor.y );
513
514 if( aBBox )
515 aBBox->Merge( aPosition + extents );
516
517 return VECTOR2I( aPosition.x + cursorDisplacement.x, aPosition.y + cursorDisplacement.y );
518}
519
520
521#undef OUTLINEFONT_RENDER_AS_PIXELS
522#ifdef OUTLINEFONT_RENDER_AS_PIXELS
523/*
524 * WIP: eeschema (and PDF output?) should use pixel rendering instead of linear segmentation
525 */
526void OUTLINE_FONT::RenderToOpenGLCanvas( KIGFX::OPENGL_GAL& aGal, const wxString& aString,
527 const VECTOR2D& aGlyphSize, const VECTOR2I& aPosition,
528 const EDA_ANGLE& aOrientation, bool aIsMirrored ) const
529{
530 hb_buffer_t* buf = hb_buffer_create();
531 hb_buffer_add_utf8( buf, UTF8( aString ).c_str(), -1, 0, -1 );
532 hb_buffer_guess_segment_properties( buf ); // guess direction, script, and language based on contents
533
534 unsigned int glyphCount;
535 hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( buf, &glyphCount );
536 hb_glyph_position_t* glyphPos = hb_buffer_get_glyph_positions( buf, &glyphCount );
537
538 std::lock_guard<std::mutex> guard( m_freeTypeMutex );
539
540 hb_font_t* referencedFont = hb_ft_font_create_referenced( m_face );
541
542 hb_ft_font_set_funcs( referencedFont );
543 hb_shape( referencedFont, buf, nullptr, 0 );
544
545 const double mirror_factor = ( aIsMirrored ? 1 : -1 );
546 const double x_scaleFactor = mirror_factor * aGlyphSize.x / mScaler;
547 const double y_scaleFactor = aGlyphSize.y / mScaler;
548
549 hb_position_t cursor_x = 0;
550 hb_position_t cursor_y = 0;
551
552 for( unsigned int i = 0; i < glyphCount; i++ )
553 {
554 hb_glyph_position_t& pos = glyphPos[i];
555 int codepoint = glyphInfo[i].codepoint;
556
557 FT_Error e = FT_Load_Glyph( m_face, codepoint, FT_LOAD_DEFAULT );
558 // TODO handle FT_Load_Glyph error
559
560 FT_Glyph glyph;
561 e = FT_Get_Glyph( m_face->glyph, &glyph );
562 // TODO handle FT_Get_Glyph error
563
564 wxPoint pt( aPosition );
565 pt.x += ( cursor_x >> 6 ) * x_scaleFactor;
566 pt.y += ( cursor_y >> 6 ) * y_scaleFactor;
567
568 cursor_x += pos.x_advance;
569 cursor_y += pos.y_advance;
570 }
571
572 hb_buffer_destroy( buf );
573}
574#endif //OUTLINEFONT_RENDER_AS_PIXELS
void SetOrigin(const Vec &pos)
Definition: box2.h:227
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:136
coord_type GetY() const
Definition: box2.h:198
coord_type GetX() const
Definition: box2.h:197
coord_type GetRight() const
Definition: box2.h:207
coord_type GetBottom() const
Definition: box2.h:212
void SetEnd(coord_type x, coord_type y)
Definition: box2.h:280
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:623
int AsTenthsOfADegree() const
Definition: eda_angle.h:115
bool IsZero() const
Definition: eda_angle.h:133
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:178
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) const
Definition: font.cpp:383
double GetInterline(double aFontHeight) const
Definition: font.h:114
bool OutlineToSegments(std::vector< CONTOUR > *aContours)
Class OUTLINE_FONT implements outline font drawing.
Definition: outline_font.h:53
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 std::mutex m_freeTypeMutex
Mutex for freetype access, FT_Library and FT_Face are not thread safe.
Definition: outline_font.h:147
double GetInterline(double aGlyphHeight, const METRICS &aFontMetrics) const override
Compute the distance (interline) between 2 lines of text (for multiline texts).
static FT_Library m_freeType
Definition: outline_font.h:148
BOX2I getBoundingBox(const std::vector< std::unique_ptr< GLYPH > > &aGlyphs) const
FT_Error loadFace(const wxString &aFontFileName, int aFaceIndex)
static constexpr double m_superscriptVerticalOffset
Definition: outline_font.h:192
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
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.
const FT_Face & GetFace() const
Definition: outline_font.h:115
static OUTLINE_FONT * LoadFont(const wxString &aFontFileName, bool aBold, bool aItalic, const std::vector< wxString > *aEmbeddedFiles)
Load an outline font.
void GetLinesAsGlyphs(std::vector< std::unique_ptr< GLYPH > > *aGlyphs, const wxString &aText, const VECTOR2I &aPosition, const TEXT_ATTRIBUTES &aAttrs, const METRICS &aFontMetrics) const
int faceSize() const
Definition: outline_font.h:182
static constexpr double m_outlineFontSizeCompensation
Definition: outline_font.h:164
EMBEDDING_PERMISSION GetEmbeddingPermission() const
int subscriptSize() const
Definition: outline_font.h:189
static constexpr double m_subscriptVerticalOffset
Definition: outline_font.h:191
OpenGL implementation of the Graphics Abstraction Layer.
Definition: opengl_gal.h:71
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.
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition: utf8.h:72
unsigned int TEXT_STYLE_FLAGS
Definition: font.h:64
bool IsSuperscript(TEXT_STYLE_FLAGS aFlags)
Definition: font.h:79
bool IsSubscript(TEXT_STYLE_FLAGS aFlags)
Definition: font.h:85
FONTCONFIG * Fontconfig()
Definition: fontconfig.cpp:100
constexpr int GLYPH_RESOLUTION
constexpr double GLYPH_SIZE_SCALER
STL namespace.
static bool contourIsHole(const CONTOUR &c)
static bool contourIsFilled(const CONTOUR &c)
hb_codepoint_t codepoint
bool operator==(const GLYPH_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
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:228
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:121
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:673