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, 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 m_forDrawingSheet( false )
53{
54 std::lock_guard<std::mutex> guard( m_freeTypeMutex );
55
56 if( !m_freeType )
57 FT_Init_FreeType( &m_freeType );
58}
59
60
62{
63 TT_OS2* os2 = reinterpret_cast<TT_OS2*>( FT_Get_Sfnt_Table( m_face, FT_SFNT_OS2 ) );
64
65 // If this table isn't present, we can't assume anything
66 if( !os2 )
68
69 // This allows the font to be exported from KiCad
70 if( os2->fsType == FT_FSTYPE_INSTALLABLE_EMBEDDING )
72
73 // We don't support bitmap fonts, so this disables embedding
74 if( os2->fsType & FT_FSTYPE_BITMAP_EMBEDDING_ONLY )
76
77 // This allows us to use the font in KiCad but not export
78 if( os2->fsType & FT_FSTYPE_EDITABLE_EMBEDDING )
80
81 // This is not actually supported by KiCad ATM(2024)
82 if( os2->fsType & FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING )
84
85 // Anything else that is not explicitly enabled we treat as restricted.
87}
88
89
90OUTLINE_FONT* OUTLINE_FONT::LoadFont( const wxString& aFontName, bool aBold, bool aItalic,
91 const std::vector<wxString>* aEmbeddedFiles,
92 bool aForDrawingSheet )
93{
94 std::unique_ptr<OUTLINE_FONT> font = std::make_unique<OUTLINE_FONT>();
95
96 wxString fontFile;
97 int faceIndex;
98 using fc = fontconfig::FONTCONFIG;
99
100
101 fc::FF_RESULT retval = Fontconfig()->FindFont( aFontName, fontFile, faceIndex, aBold, aItalic,
102 aEmbeddedFiles );
103
104 if( retval == fc::FF_RESULT::FF_ERROR )
105 return nullptr;
106
107 if( retval == fc::FF_RESULT::FF_MISSING_BOLD || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
108 font->SetFakeBold();
109
110 if( retval == fc::FF_RESULT::FF_MISSING_ITAL || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
111 font->SetFakeItal();
112
113 if( font->loadFace( fontFile, faceIndex ) != 0 )
114 return nullptr;
115
116 font->m_fontName = aFontName; // Keep asked-for name, even if we substituted.
117 font->m_fontFileName = fontFile;
118 font->m_forDrawingSheet = aForDrawingSheet;
119
120 return font.release();
121}
122
123
124FT_Error OUTLINE_FONT::loadFace( const wxString& aFontFileName, int aFaceIndex )
125{
126 std::lock_guard<std::mutex> guard( m_freeTypeMutex );
127
128 FT_Error e = FT_New_Face( m_freeType, aFontFileName.mb_str( wxConvUTF8 ), aFaceIndex, &m_face );
129
130 if( !e )
131 {
132 FT_Select_Charmap( m_face, FT_Encoding::FT_ENCODING_UNICODE );
133 // params:
134 // m_face = handle to face object
135 // 0 = char width in 1/64th of points ( 0 = same as char height )
136 // faceSize() = char height in 1/64th of points
137 // GLYPH_RESOLUTION = horizontal device resolution (1152dpi, 16x default)
138 // 0 = vertical device resolution ( 0 = same as horizontal )
139 FT_Set_Char_Size( m_face, 0, faceSize(), GLYPH_RESOLUTION, 0 );
140 }
141
142 return e;
143}
144
145
146double OUTLINE_FONT::GetInterline( double aGlyphHeight, const METRICS& aFontMetrics ) const
147{
148 double glyphToFontHeight = 1.0;
149
150 if( GetFace()->units_per_EM )
151 glyphToFontHeight = GetFace()->height / GetFace()->units_per_EM;
152
153 return aFontMetrics.GetInterline( aGlyphHeight * glyphToFontHeight );
154}
155
156
157static bool contourIsFilled( const CONTOUR& c )
158{
159 switch( c.m_Orientation )
160 {
161 case FT_ORIENTATION_TRUETYPE: return c.m_Winding == 1;
162 case FT_ORIENTATION_POSTSCRIPT: return c.m_Winding == -1;
163 default: return false;
164 }
165}
166
167
168static bool contourIsHole( const CONTOUR& c )
169{
170 return !contourIsFilled( c );
171}
172
173
174BOX2I OUTLINE_FONT::getBoundingBox( const std::vector<std::unique_ptr<GLYPH>>& aGlyphs ) const
175{
176 int minX = INT_MAX;
177 int minY = INT_MAX;
178 int maxX = INT_MIN;
179 int maxY = INT_MIN;
180
181 for( const std::unique_ptr<KIFONT::GLYPH>& glyph : aGlyphs )
182 {
183 BOX2D bbox = glyph->BoundingBox();
184 bbox.Normalize();
185
186 if( minX > bbox.GetX() )
187 minX = bbox.GetX();
188
189 if( minY > bbox.GetY() )
190 minY = bbox.GetY();
191
192 if( maxX < bbox.GetRight() )
193 maxX = bbox.GetRight();
194
195 if( maxY < bbox.GetBottom() )
196 maxY = bbox.GetBottom();
197 }
198
199 BOX2I ret;
200 ret.SetOrigin( minX, minY );
201 ret.SetEnd( maxX, maxY );
202 return ret;
203}
204
205
206void OUTLINE_FONT::GetLinesAsGlyphs( std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
207 const wxString& aText, const VECTOR2I& aPosition,
208 const TEXT_ATTRIBUTES& aAttrs,
209 const METRICS& aFontMetrics ) const
210{
211 wxArrayString strings;
212 std::vector<VECTOR2I> positions;
213 std::vector<VECTOR2I> extents;
214 TEXT_STYLE_FLAGS textStyle = 0;
215
216 if( aAttrs.m_Italic )
217 textStyle |= TEXT_STYLE::ITALIC;
218
219 getLinePositions( aText, aPosition, strings, positions, extents, aAttrs, aFontMetrics );
220
221 for( size_t i = 0; i < strings.GetCount(); i++ )
222 {
223 (void) drawMarkup( nullptr, aGlyphs, strings.Item( i ), positions[i], aAttrs.m_Size,
224 aAttrs.m_Angle, aAttrs.m_Mirrored, aPosition, textStyle, aFontMetrics );
225 }
226}
227
228
229VECTOR2I OUTLINE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
230 const wxString& aText, const VECTOR2I& aSize,
231 const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
232 bool aMirror, const VECTOR2I& aOrigin,
233 TEXT_STYLE_FLAGS aTextStyle ) const
234{
235 // HarfBuzz needs further processing to split tab-delimited text into text runs.
236
237 constexpr double TAB_WIDTH = 4 * 0.6;
238
239 VECTOR2I position = aPosition;
240 wxString textRun;
241
242 if( aBBox )
243 {
244 aBBox->SetOrigin( aPosition );
245 aBBox->SetEnd( aPosition );
246 }
247
248 for( wxUniChar c : aText )
249 {
250 // Handle tabs as locked to the nearest 4th column (in space-widths).
251 if( c == '\t' )
252 {
253 if( !textRun.IsEmpty() )
254 {
255 position = getTextAsGlyphs( aBBox, aGlyphs, textRun, aSize, position, aAngle,
256 aMirror, aOrigin, aTextStyle );
257 textRun.clear();
258 }
259
260 int tabWidth = KiROUND( aSize.x * TAB_WIDTH );
261 int currentIntrusion = ( position.x - aOrigin.x ) % tabWidth;
262
263 position.x += tabWidth - currentIntrusion;
264 }
265 else
266 {
267 textRun += c;
268 }
269 }
270
271 if( !textRun.IsEmpty() )
272 {
273 position = getTextAsGlyphs( aBBox, aGlyphs, textRun, aSize, position, aAngle, aMirror,
274 aOrigin, aTextStyle );
275 }
276
277 return position;
278}
279
280
281VECTOR2I OUTLINE_FONT::getTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
282 const wxString& aText, const VECTOR2I& aSize,
283 const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
284 bool aMirror, const VECTOR2I& aOrigin,
285 TEXT_STYLE_FLAGS aTextStyle ) const
286{
287 std::lock_guard<std::mutex> guard( m_freeTypeMutex );
288
289 return getTextAsGlyphsUnlocked( aBBox, aGlyphs, aText, aSize, aPosition, aAngle, aMirror,
290 aOrigin, aTextStyle );
291}
292
293
295 FT_Face face;
296 std::string text;
298
299 bool operator==(const HARFBUZZ_CACHE_KEY& rhs ) const
300 {
301 return face == rhs.face
302 && scaler == rhs.scaler
303 && text == rhs.text;
304 }
305};
306
307
309{
310 std::vector<hb_glyph_info_t> m_GlyphInfo;
311 std::vector<hb_glyph_position_t> m_GlyphPositions;
312 bool m_Initialized = false;
313};
314
315
316namespace std
317{
318 template <>
320 {
321 std::size_t operator()( const HARFBUZZ_CACHE_KEY& k ) const
322 {
323 return hash_val( k.face, k.scaler, k.text );
324 }
325 };
326}
327
328
329static const HARFBUZZ_CACHE_ENTRY& getHarfbuzzShape( FT_Face aFace, const wxString& aText,
330 int aScaler )
331{
332 static std::unordered_map<HARFBUZZ_CACHE_KEY, HARFBUZZ_CACHE_ENTRY> s_harfbuzzCache;
333
334 std::string textUtf8 = UTF8( aText );
335 HARFBUZZ_CACHE_KEY key = { aFace, textUtf8, aScaler };
336
337 HARFBUZZ_CACHE_ENTRY& entry = s_harfbuzzCache[key];
338
339 if( !entry.m_Initialized )
340 {
341 hb_buffer_t* buf = hb_buffer_create();
342 hb_buffer_add_utf8( buf, textUtf8.c_str(), -1, 0, -1 );
343 hb_buffer_guess_segment_properties( buf ); // guess direction, script, and language based on
344 // contents
345
346 hb_font_t* referencedFont = hb_ft_font_create_referenced( aFace );
347 hb_ft_font_set_funcs( referencedFont );
348 hb_shape( referencedFont, buf, nullptr, 0 );
349
350 unsigned int glyphCount;
351 hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( buf, &glyphCount );
352 hb_glyph_position_t* glyphPos = hb_buffer_get_glyph_positions( buf, &glyphCount );
353
354 entry.m_GlyphInfo.assign( glyphInfo, glyphInfo + glyphCount );
355 entry.m_GlyphPositions.assign( glyphPos, glyphPos + glyphCount );
356 entry.m_Initialized = true;
357
358 hb_buffer_destroy( buf );
359 hb_font_destroy( referencedFont );
360 }
361
362 return entry;
363}
364
365
367 FT_Face face;
368 hb_codepoint_t codepoint;
373 bool mirror;
376
377 bool operator==(const GLYPH_CACHE_KEY& rhs ) const
378 {
379 return face == rhs.face
380 && codepoint == rhs.codepoint
381 && scale == rhs.scale
383 && fakeItalic == rhs.fakeItalic
384 && fakeBold == rhs.fakeBold
385 && mirror == rhs.mirror
386 && supersub == rhs.supersub
387 && angle == rhs.angle;
388 }
389};
390
391
392namespace std
393{
394 template <>
395 struct hash<GLYPH_CACHE_KEY>
396 {
397 std::size_t operator()( const GLYPH_CACHE_KEY& k ) const
398 {
399 return hash_val( k.face, k.codepoint, k.scale.x, k.scale.y, k.forDrawingSheet,
401 }
402 };
403}
404
405
407 std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
408 const wxString& aText, const VECTOR2I& aSize,
409 const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
410 bool aMirror, const VECTOR2I& aOrigin,
411 TEXT_STYLE_FLAGS aTextStyle ) const
412{
413 VECTOR2D glyphSize = aSize;
414 FT_Face face = m_face;
415 double scaler = faceSize();
416 bool supersub = IsSuperscript( aTextStyle ) || IsSubscript( aTextStyle );
417
418 if( supersub )
419 scaler = subscriptSize();
420
421 // set glyph resolution so that FT_Load_Glyph() results are good enough for decomposing
422 FT_Set_Char_Size( face, 0, scaler, GLYPH_RESOLUTION, 0 );
423
424 const HARFBUZZ_CACHE_ENTRY& hbShape = getHarfbuzzShape( face, aText, scaler );
425
426 unsigned int glyphCount = static_cast<unsigned int>( hbShape.m_GlyphInfo.size() );
427 const hb_glyph_info_t* glyphInfo = hbShape.m_GlyphInfo.data();
428 const hb_glyph_position_t* glyphPos = hbShape.m_GlyphPositions.data();
429
430 VECTOR2D scaleFactor( glyphSize.x / faceSize(), -glyphSize.y / faceSize() );
431 scaleFactor = scaleFactor * m_outlineFontSizeCompensation;
432
433 VECTOR2I cursor( 0, 0 );
434
435 if( aGlyphs )
436 aGlyphs->reserve( glyphCount );
437
438 // GLYPH_DATA is a collection of all outlines in the glyph; for example the 'o' glyph
439 // generally contains 2 contours, one for the glyph outline and one for the hole
440 static std::unordered_map<GLYPH_CACHE_KEY, GLYPH_DATA> s_glyphCache;
441
442 for( unsigned int i = 0; i < glyphCount; i++ )
443 {
444 // Don't process glyphs that were already included in a previous cluster
445 if( i > 0 && glyphInfo[i].cluster == glyphInfo[i-1].cluster )
446 continue;
447
448 if( aGlyphs )
449 {
450 GLYPH_CACHE_KEY key = { face, glyphInfo[i].codepoint, scaleFactor, m_forDrawingSheet,
451 m_fakeItal, m_fakeBold, aMirror, supersub, aAngle };
452 GLYPH_DATA& glyphData = s_glyphCache[ key ];
453
454 if( glyphData.m_Contours.empty() )
455 {
456 if( m_fakeItal )
457 {
458 FT_Matrix matrix;
459 // Create a 12 degree slant
460 const float angle = (float)( -M_PI * 12.0f ) / 180.0f;
461 matrix.xx = (FT_Fixed) ( cos( angle ) * 0x10000L );
462 matrix.xy = (FT_Fixed) ( -sin( angle ) * 0x10000L );
463 matrix.yx = (FT_Fixed) ( 0 * 0x10000L ); // Don't rotate in the y direction
464 matrix.yy = (FT_Fixed) ( 1 * 0x10000L );
465
466 FT_Set_Transform( face, &matrix, nullptr );
467 }
468
469 FT_Load_Glyph( face, glyphInfo[i].codepoint, FT_LOAD_NO_BITMAP );
470
471 if( m_fakeBold )
472 FT_Outline_Embolden( &face->glyph->outline, 1 << 6 );
473
474 OUTLINE_DECOMPOSER decomposer( face->glyph->outline );
475
476 if( !decomposer.OutlineToSegments( &glyphData.m_Contours ) )
477 {
478 double hb_advance = glyphPos[i].x_advance * GLYPH_SIZE_SCALER;
479 BOX2D tofuBox( { scaler * 0.03, 0.0 },
480 { hb_advance - scaler * 0.02, scaler * 0.72 } );
481
482 glyphData.m_Contours.clear();
483
484 CONTOUR outline;
485 outline.m_Winding = 1;
486 outline.m_Orientation = FT_ORIENTATION_TRUETYPE;
487 outline.m_Points.push_back( tofuBox.GetPosition() );
488 outline.m_Points.push_back( { tofuBox.GetSize().x, tofuBox.GetPosition().y } );
489 outline.m_Points.push_back( tofuBox.GetSize() );
490 outline.m_Points.push_back( { tofuBox.GetPosition().x, tofuBox.GetSize().y } );
491 glyphData.m_Contours.push_back( std::move( outline ) );
492
493 CONTOUR hole;
494 tofuBox.Move( { scaler * 0.06, scaler * 0.06 } );
495 tofuBox.SetSize( { tofuBox.GetWidth() - scaler * 0.06,
496 tofuBox.GetHeight() - scaler * 0.06 } );
497 hole.m_Winding = 1;
498 hole.m_Orientation = FT_ORIENTATION_NONE;
499 hole.m_Points.push_back( tofuBox.GetPosition() );
500 hole.m_Points.push_back( { tofuBox.GetSize().x, tofuBox.GetPosition().y } );
501 hole.m_Points.push_back( tofuBox.GetSize() );
502 hole.m_Points.push_back( { tofuBox.GetPosition().x, tofuBox.GetSize().y } );
503 glyphData.m_Contours.push_back( std::move( hole ) );
504 }
505 }
506
507 std::unique_ptr<OUTLINE_GLYPH> glyph = std::make_unique<OUTLINE_GLYPH>();
508 std::vector<SHAPE_LINE_CHAIN> holes;
509
510 for( CONTOUR& c : glyphData.m_Contours )
511 {
512 std::vector<VECTOR2D> points = c.m_Points;
513 SHAPE_LINE_CHAIN shape;
514
515 shape.ReservePoints( points.size() );
516
517 for( const VECTOR2D& v : points )
518 {
519 VECTOR2D pt( v + cursor );
520
521 if( IsSubscript( aTextStyle ) )
522 pt.y += m_subscriptVerticalOffset * scaler;
523 else if( IsSuperscript( aTextStyle ) )
524 pt.y += m_superscriptVerticalOffset * scaler;
525
526 pt *= scaleFactor;
527 pt += aPosition;
528
529 if( aMirror )
530 pt.x = aOrigin.x - ( pt.x - aOrigin.x );
531
532 if( !aAngle.IsZero() )
533 RotatePoint( pt, aOrigin, aAngle );
534
535 shape.Append( pt.x, pt.y );
536 }
537
538 shape.SetClosed( true );
539
540 if( contourIsHole( c ) )
541 holes.push_back( std::move( shape ) );
542 else
543 glyph->AddOutline( std::move( shape ) );
544 }
545
546 for( SHAPE_LINE_CHAIN& hole : holes )
547 {
548 bool added_hole = false;
549
550 if( hole.PointCount() )
551 {
552 for( int ii = 0; ii < glyph->OutlineCount(); ++ii )
553 {
554 if( glyph->Outline( ii ).PointInside( hole.GetPoint( 0 ) ) )
555 {
556 glyph->AddHole( std::move( hole ), ii );
557 added_hole = true;
558 break;
559 }
560 }
561
562 // Some lovely TTF fonts decided that winding didn't matter for outlines that
563 // don't have holes, so holes that don't fit in any outline are added as
564 // outlines.
565 if( !added_hole )
566 glyph->AddOutline( std::move( hole ) );
567 }
568 }
569
570 if( glyphData.m_TriangulationData.empty() )
571 {
572 glyph->CacheTriangulation( false, false );
573 glyphData.m_TriangulationData = glyph->GetTriangulationData();
574 }
575 else
576 {
577 glyph->CacheTriangulation( glyphData.m_TriangulationData );
578 }
579
580 aGlyphs->push_back( std::move( glyph ) );
581 }
582
583 const hb_glyph_position_t& pos = glyphPos[i];
584 cursor.x += ( pos.x_advance * GLYPH_SIZE_SCALER );
585 cursor.y += ( pos.y_advance * GLYPH_SIZE_SCALER );
586 }
587
588 int ascender = abs( face->size->metrics.ascender * GLYPH_SIZE_SCALER );
589 int descender = abs( face->size->metrics.descender * GLYPH_SIZE_SCALER );
590 VECTOR2I extents( cursor.x * scaleFactor.x, ( ascender + descender ) * abs( scaleFactor.y ) );
591
592 VECTOR2I cursorDisplacement( cursor.x * scaleFactor.x, -cursor.y * scaleFactor.y );
593
594 if( aBBox )
595 aBBox->Merge( aPosition + extents );
596
597 return VECTOR2I( aPosition.x + cursorDisplacement.x, aPosition.y + cursorDisplacement.y );
598}
599
600
601#undef OUTLINEFONT_RENDER_AS_PIXELS
602#ifdef OUTLINEFONT_RENDER_AS_PIXELS
603/*
604 * WIP: Eeschema (and PDF output?) should use pixel rendering instead of linear segmentation
605 */
606void OUTLINE_FONT::RenderToOpenGLCanvas( KIGFX::OPENGL_GAL& aGal, const wxString& aString,
607 const VECTOR2D& aGlyphSize, const VECTOR2I& aPosition,
608 const EDA_ANGLE& aOrientation, bool aIsMirrored ) const
609{
610 hb_buffer_t* buf = hb_buffer_create();
611 hb_buffer_add_utf8( buf, UTF8( aString ).c_str(), -1, 0, -1 );
612
613 // guess direction, script, and language based on contents
614 hb_buffer_guess_segment_properties( buf );
615
616 unsigned int glyphCount;
617 hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( buf, &glyphCount );
618 hb_glyph_position_t* glyphPos = hb_buffer_get_glyph_positions( buf, &glyphCount );
619
620 std::lock_guard<std::mutex> guard( m_freeTypeMutex );
621
622 hb_font_t* referencedFont = hb_ft_font_create_referenced( m_face );
623
624 hb_ft_font_set_funcs( referencedFont );
625 hb_shape( referencedFont, buf, nullptr, 0 );
626
627 const double mirror_factor = ( aIsMirrored ? 1 : -1 );
628 const double x_scaleFactor = mirror_factor * aGlyphSize.x / mScaler;
629 const double y_scaleFactor = aGlyphSize.y / mScaler;
630
631 hb_position_t cursor_x = 0;
632 hb_position_t cursor_y = 0;
633
634 for( unsigned int i = 0; i < glyphCount; i++ )
635 {
636 const hb_glyph_position_t& pos = glyphPos[i];
637 int codepoint = glyphInfo[i].codepoint;
638
639 FT_Error e = FT_Load_Glyph( m_face, codepoint, FT_LOAD_DEFAULT );
640 // TODO handle FT_Load_Glyph error
641
642 FT_Glyph glyph;
643 e = FT_Get_Glyph( m_face->glyph, &glyph );
644 // TODO handle FT_Get_Glyph error
645
646 wxPoint pt( aPosition );
647 pt.x += ( cursor_x >> 6 ) * x_scaleFactor;
648 pt.y += ( cursor_y >> 6 ) * y_scaleFactor;
649
650 cursor_x += pos.x_advance;
651 cursor_y += pos.y_advance;
652 }
653
654 hb_buffer_destroy( buf );
655}
656
657#endif //OUTLINEFONT_RENDER_AS_PIXELS
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
BOX2< VECTOR2D > BOX2D
Definition box2.h:923
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:237
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:146
constexpr coord_type GetY() const
Definition box2.h:208
constexpr coord_type GetX() const
Definition box2.h:207
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 coord_type GetRight() const
Definition box2.h:217
constexpr void SetEnd(coord_type x, coord_type y)
Definition box2.h:297
constexpr coord_type GetBottom() const
Definition box2.h:222
double AsDegrees() const
Definition eda_angle.h:116
bool IsZero() const
Definition eda_angle.h:136
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
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:376
double GetInterline(double aFontHeight) const
Definition font.h:114
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 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).
static FT_Library m_freeType
BOX2I getBoundingBox(const std::vector< std::unique_ptr< GLYPH > > &aGlyphs) const
FT_Error loadFace(const wxString &aFontFileName, int aFaceIndex)
static constexpr double m_superscriptVerticalOffset
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
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
int subscriptSize() const
static constexpr double m_subscriptVerticalOffset
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
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:47
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()
static constexpr std::size_t hash_val(const Types &... args)
Definition hash.h:51
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:229
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694