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-2023 Kicad Developers, see AUTHORS.txt for contributors.
6 *
7 * Outline font 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 <limits>
28#include <pgm_base.h>
30#include <harfbuzz/hb.h>
31#include <harfbuzz/hb-ft.h>
32#include <bezier_curves.h>
34#include <eda_text.h>
35#include <font/fontconfig.h>
36#include <font/outline_font.h>
37#include FT_GLYPH_H
38#include FT_BBOX_H
39#include <trigo.h>
40#include <font/fontconfig.h>
42
43using namespace KIFONT;
44
45
46FT_Library OUTLINE_FONT::m_freeType = nullptr;
48
50 m_face(NULL),
51 m_faceSize( 16 ),
52 m_fakeBold( false ),
53 m_fakeItal( false )
54{
55 std::lock_guard<std::mutex> guard( m_freeTypeMutex );
56
57 if( !m_freeType )
58 FT_Init_FreeType( &m_freeType );
59}
60
61
63{
64 std::lock_guard<std::mutex> guard( m_freeTypeMutex );
65
66 if( !m_freeType )
67 FT_Init_FreeType( &m_freeType );
68
69 FT_Int major = 0;
70 FT_Int minor = 0;
71 FT_Int patch = 0;
72 FT_Library_Version( m_freeType, &major, &minor, &patch );
73
74 return wxString::Format( "%d.%d.%d", major, minor, patch );
75}
76
77
79{
80 return wxString::FromUTF8( HB_VERSION_STRING );
81}
82
83
85{
87}
88
89
91{
92 return wxString::Format( "FreeType %s HarfBuzz %s", FreeTypeVersion(), HarfBuzzVersion() );
93}
94
95
96OUTLINE_FONT* OUTLINE_FONT::LoadFont( const wxString& aFontName, bool aBold, bool aItalic )
97{
98 std::unique_ptr<OUTLINE_FONT> font = std::make_unique<OUTLINE_FONT>();
99
100 wxString fontFile;
101 int faceIndex;
102 using fc = fontconfig::FONTCONFIG;
103
104 fc::FF_RESULT retval = Fontconfig()->FindFont( aFontName, fontFile, faceIndex, aBold, aItalic );
105
106 if( retval == fc::FF_RESULT::FF_ERROR )
107 return nullptr;
108
109 if( retval == fc::FF_RESULT::FF_MISSING_BOLD || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
110 font->SetFakeBold();
111
112 if( retval == fc::FF_RESULT::FF_MISSING_ITAL || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
113 font->SetFakeItal();
114
115 if( font->loadFace( fontFile, faceIndex ) != 0 )
116 return nullptr;
117
118 font->m_fontName = aFontName; // Keep asked-for name, even if we substituted.
119 font->m_fontFileName = fontFile;
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 // TODO: check that going from wxString to char* with UTF-8
130 // conversion for filename makes sense on any/all platforms
131 FT_Error e = FT_New_Face( m_freeType, aFontFileName.mb_str( wxConvUTF8 ), aFaceIndex, &m_face );
132
133 if( !e )
134 {
135 FT_Select_Charmap( m_face, FT_Encoding::FT_ENCODING_UNICODE );
136 // params:
137 // m_face = handle to face object
138 // 0 = char width in 1/64th of points ( 0 = same as char height )
139 // faceSize() = char height in 1/64th of points
140 // GLYPH_RESOLUTION = horizontal device resolution (288dpi, 4x default)
141 // 0 = vertical device resolution ( 0 = same as horizontal )
142 FT_Set_Char_Size( m_face, 0, faceSize(), GLYPH_RESOLUTION, 0 );
143 }
144
145 return e;
146}
147
148
153double OUTLINE_FONT::ComputeOverbarVerticalPosition( double aGlyphHeight ) const
154{
155 // The overbar on actual text is positioned above the bounding box of the glyphs. However,
156 // that's expensive to calculate so we use an estimation here (as this is only used for
157 // calculating bounding boxes).
158 return aGlyphHeight * m_outlineFontSizeCompensation;
159}
160
161
166double OUTLINE_FONT::ComputeUnderlineVerticalPosition( double aGlyphHeight ) const
167{
168 return aGlyphHeight * m_underlineOffsetScaler;
169}
170
171
176double OUTLINE_FONT::GetInterline( double aGlyphHeight, double aLineSpacing ) const
177{
178 double pitch = INTERLINE_PITCH_RATIO;
179
180 if( GetFace()->units_per_EM )
181 pitch = GetFace()->height / GetFace()->units_per_EM;
182
183 double interline = aLineSpacing * aGlyphHeight * pitch * m_outlineFontSizeCompensation;
184
185 // FONT TODO this hack is an attempt to fix interline spacing by eyeballing it
186 static constexpr double interlineHackMultiplier = 1.2;
187 interline *= interlineHackMultiplier;
188
189 return interline;
190}
191
192
193static bool contourIsFilled( const CONTOUR& c )
194{
195 switch( c.m_Orientation )
196 {
197 case FT_ORIENTATION_TRUETYPE: return c.m_Winding == 1;
198 case FT_ORIENTATION_POSTSCRIPT: return c.m_Winding == -1;
199 default: return false;
200 }
201}
202
203
204static bool contourIsHole( const CONTOUR& c )
205{
206 return !contourIsFilled( c );
207}
208
209
210BOX2I OUTLINE_FONT::getBoundingBox( const std::vector<std::unique_ptr<GLYPH>>& aGlyphs ) const
211{
212 int minX = INT_MAX;
213 int minY = INT_MAX;
214 int maxX = INT_MIN;
215 int maxY = INT_MIN;
216
217 for( const std::unique_ptr<KIFONT::GLYPH>& glyph : aGlyphs )
218 {
219 BOX2D bbox = glyph->BoundingBox();
220 bbox.Normalize();
221
222 if( minX > bbox.GetX() )
223 minX = bbox.GetX();
224
225 if( minY > bbox.GetY() )
226 minY = bbox.GetY();
227
228 if( maxX < bbox.GetRight() )
229 maxX = bbox.GetRight();
230
231 if( maxY < bbox.GetBottom() )
232 maxY = bbox.GetBottom();
233 }
234
235 BOX2I ret;
236 ret.SetOrigin( minX, minY );
237 ret.SetEnd( maxX, maxY );
238 return ret;
239}
240
241
242void OUTLINE_FONT::GetLinesAsGlyphs( std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
243 const wxString& aText, const VECTOR2I& aPosition,
244 const TEXT_ATTRIBUTES& aAttrs ) const
245{
246 wxArrayString strings;
247 std::vector<VECTOR2I> positions;
248 std::vector<VECTOR2I> extents;
249 TEXT_STYLE_FLAGS textStyle = 0;
250
251 if( aAttrs.m_Italic )
252 textStyle |= TEXT_STYLE::ITALIC;
253
254 getLinePositions( aText, aPosition, strings, positions, extents, aAttrs );
255
256 for( size_t i = 0; i < strings.GetCount(); i++ )
257 {
258 (void) drawMarkup( nullptr, aGlyphs, strings.Item( i ), positions[i], aAttrs.m_Size,
259 aAttrs.m_Angle, aAttrs.m_Mirrored, aPosition, textStyle );
260 }
261}
262
263
264VECTOR2I OUTLINE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
265 const wxString& aText, const VECTOR2I& aSize,
266 const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
267 bool aMirror, const VECTOR2I& aOrigin,
268 TEXT_STYLE_FLAGS aTextStyle ) const
269{
270 // HarfBuzz needs further processing to split tab-delimited text into text runs.
271
272 constexpr double TAB_WIDTH = 4 * 0.6;
273
274 VECTOR2I position = aPosition;
275 wxString textRun;
276
277 if( aBBox )
278 {
279 aBBox->SetOrigin( aPosition );
280 aBBox->SetEnd( aPosition );
281 }
282
283 for( wxUniChar c : aText )
284 {
285 // Handle tabs as locked to the nearest 4th column (in space-widths).
286 if( c == '\t' )
287 {
288 if( !textRun.IsEmpty() )
289 {
290 position = getTextAsGlyphs( aBBox, aGlyphs, textRun, aSize, position, aAngle,
291 aMirror, aOrigin, aTextStyle );
292 textRun.clear();
293 }
294
295 int tabWidth = KiROUND( aSize.x * TAB_WIDTH );
296 int currentIntrusion = ( position.x - aOrigin.x ) % tabWidth;
297
298 position.x += tabWidth - currentIntrusion;
299 }
300 else
301 {
302 textRun += c;
303 }
304 }
305
306 if( !textRun.IsEmpty() )
307 {
308 position = getTextAsGlyphs( aBBox, aGlyphs, textRun, aSize, position, aAngle, aMirror,
309 aOrigin, aTextStyle );
310 }
311
312 return position;
313}
314
315
316VECTOR2I OUTLINE_FONT::getTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
317 const wxString& aText, const VECTOR2I& aSize,
318 const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
319 bool aMirror, const VECTOR2I& aOrigin,
320 TEXT_STYLE_FLAGS aTextStyle ) const
321{
322 std::lock_guard<std::mutex> guard( m_freeTypeMutex );
323
324 return getTextAsGlyphsUnlocked( aBBox, aGlyphs, aText, aSize, aPosition, aAngle, aMirror,
325 aOrigin, aTextStyle );
326}
327
329 std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
330 const wxString& aText, const VECTOR2I& aSize,
331 const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
332 bool aMirror, const VECTOR2I& aOrigin,
333 TEXT_STYLE_FLAGS aTextStyle ) const
334{
335 VECTOR2D glyphSize = aSize;
336 FT_Face face = m_face;
337 double scaler = faceSize();
338
339 if( IsSubscript( aTextStyle ) || IsSuperscript( aTextStyle ) )
340 {
341 scaler = subscriptSize();
342 }
343
344 // set glyph resolution so that FT_Load_Glyph() results are good enough for decomposing
345 FT_Set_Char_Size( face, 0, scaler, GLYPH_RESOLUTION, 0 );
346
347 hb_buffer_t* buf = hb_buffer_create();
348 hb_buffer_add_utf8( buf, UTF8( aText ).c_str(), -1, 0, -1 );
349 hb_buffer_guess_segment_properties( buf ); // guess direction, script, and language based on
350 // contents
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 hb_font_t* referencedFont = hb_ft_font_create_referenced( face );
357 hb_ft_font_set_funcs( referencedFont );
358 hb_shape( referencedFont, buf, nullptr, 0 );
359
360 VECTOR2D scaleFactor( glyphSize.x / faceSize(), -glyphSize.y / faceSize() );
361 scaleFactor = scaleFactor * m_outlineFontSizeCompensation;
362
363 VECTOR2I cursor( 0, 0 );
364
365 if( aGlyphs )
366 aGlyphs->reserve( glyphCount );
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 if( m_fakeItal )
377 {
378 FT_Matrix matrix;
379 // Create a 12 degree slant
380 const float angle = (float)( -M_PI * 12.0f ) / 180.0f;
381 matrix.xx = (FT_Fixed) ( cos( angle ) * 0x10000L );
382 matrix.xy = (FT_Fixed) ( -sin( angle ) * 0x10000L );
383 matrix.yx = (FT_Fixed) ( 0 * 0x10000L ); // Don't rotate in the y direction
384 matrix.yy = (FT_Fixed) ( 1 * 0x10000L );
385
386 FT_Set_Transform( face, &matrix, 0 );
387 }
388
389 FT_Load_Glyph( face, glyphInfo[i].codepoint, FT_LOAD_NO_BITMAP );
390
391 if( m_fakeBold )
392 FT_Outline_Embolden( &face->glyph->outline, 1 << 6 );
393
394 // contours is a collection of all outlines in the glyph; for example the 'o' glyph
395 // generally contains 2 contours, one for the glyph outline and one for the hole
396 CONTOURS contours;
397
398 OUTLINE_DECOMPOSER decomposer( face->glyph->outline );
399 decomposer.OutlineToSegments( &contours );
400
401 std::unique_ptr<OUTLINE_GLYPH> glyph = std::make_unique<OUTLINE_GLYPH>();
402 std::vector<SHAPE_LINE_CHAIN> holes;
403
404 for( CONTOUR& c : contours )
405 {
406 GLYPH_POINTS points = c.m_Points;
407 SHAPE_LINE_CHAIN shape;
408
409 shape.ReservePoints( points.size() );
410
411 for( const VECTOR2D& v : points )
412 {
413 VECTOR2D pt( v + cursor );
414
415 if( IsSubscript( aTextStyle ) )
416 pt.y += m_subscriptVerticalOffset * scaler;
417 else if( IsSuperscript( aTextStyle ) )
418 pt.y += m_superscriptVerticalOffset * scaler;
419
420 pt *= scaleFactor;
421 pt += aPosition;
422
423 if( aMirror )
424 pt.x = aOrigin.x - ( pt.x - aOrigin.x );
425
426 if( !aAngle.IsZero() )
427 RotatePoint( pt, aOrigin, aAngle );
428
429 shape.Append( pt.x, pt.y );
430 }
431
432 shape.SetClosed( true );
433
434 if( contourIsHole( c ) )
435 holes.push_back( std::move( shape ) );
436 else
437 glyph->AddOutline( std::move( shape ) );
438 }
439
440 for( SHAPE_LINE_CHAIN& hole : holes )
441 {
442 if( hole.PointCount() )
443 {
444 for( int ii = 0; ii < glyph->OutlineCount(); ++ii )
445 {
446 if( glyph->Outline( ii ).PointInside( hole.GetPoint( 0 ) ) )
447 {
448 glyph->AddHole( std::move( hole ), ii );
449 break;
450 }
451 }
452 }
453 }
454
455 aGlyphs->push_back( std::move( glyph ) );
456 }
457
458 hb_glyph_position_t& pos = glyphPos[i];
459 cursor.x += ( pos.x_advance * GLYPH_SIZE_SCALER );
460 cursor.y += ( pos.y_advance * GLYPH_SIZE_SCALER );
461 }
462
463 int ascender = abs( face->size->metrics.ascender * GLYPH_SIZE_SCALER );
464 int descender = abs( face->size->metrics.descender * GLYPH_SIZE_SCALER );
465 VECTOR2I extents( cursor.x * scaleFactor.x, ( ascender + descender ) * abs( scaleFactor.y ) );
466
467 hb_buffer_destroy( buf );
468 hb_font_destroy( referencedFont );
469
470 VECTOR2I cursorDisplacement( cursor.x * scaleFactor.x, -cursor.y * scaleFactor.y );
471
472 if( aBBox )
473 aBBox->Merge( aPosition + extents );
474
475 return VECTOR2I( aPosition.x + cursorDisplacement.x, aPosition.y + cursorDisplacement.y );
476}
477
478
479#undef OUTLINEFONT_RENDER_AS_PIXELS
480#ifdef OUTLINEFONT_RENDER_AS_PIXELS
481/*
482 * WIP: eeschema (and PDF output?) should use pixel rendering instead of linear segmentation
483 */
484void OUTLINE_FONT::RenderToOpenGLCanvas( KIGFX::OPENGL_GAL& aGal, const wxString& aString,
485 const VECTOR2D& aGlyphSize, const VECTOR2I& aPosition,
486 const EDA_ANGLE& aOrientation, bool aIsMirrored ) const
487{
488 hb_buffer_t* buf = hb_buffer_create();
489 hb_buffer_add_utf8( buf, UTF8( aString ).c_str(), -1, 0, -1 );
490 hb_buffer_guess_segment_properties( buf ); // guess direction, script, and language based on contents
491
492 unsigned int glyphCount;
493 hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( buf, &glyphCount );
494 hb_glyph_position_t* glyphPos = hb_buffer_get_glyph_positions( buf, &glyphCount );
495
496 std::lock_guard<std::mutex> guard( m_freeTypeMutex );
497
498 hb_font_t* referencedFont = hb_ft_font_create_referenced( m_face );
499
500 hb_ft_font_set_funcs( referencedFont );
501 hb_shape( referencedFont, buf, nullptr, 0 );
502
503 const double mirror_factor = ( aIsMirrored ? 1 : -1 );
504 const double x_scaleFactor = mirror_factor * aGlyphSize.x / mScaler;
505 const double y_scaleFactor = aGlyphSize.y / mScaler;
506
507 hb_position_t cursor_x = 0;
508 hb_position_t cursor_y = 0;
509
510 for( unsigned int i = 0; i < glyphCount; i++ )
511 {
512 hb_glyph_position_t& pos = glyphPos[i];
513 int codepoint = glyphInfo[i].codepoint;
514
515 FT_Error e = FT_Load_Glyph( m_face, codepoint, FT_LOAD_DEFAULT );
516 // TODO handle FT_Load_Glyph error
517
518 FT_Glyph glyph;
519 e = FT_Get_Glyph( m_face->glyph, &glyph );
520 // TODO handle FT_Get_Glyph error
521
522 wxPoint pt( aPosition );
523 pt.x += ( cursor_x >> 6 ) * x_scaleFactor;
524 pt.y += ( cursor_y >> 6 ) * y_scaleFactor;
525
526 cursor_x += pos.x_advance;
527 cursor_y += pos.y_advance;
528 }
529
530 hb_buffer_destroy( buf );
531}
532#endif //OUTLINEFONT_RENDER_AS_PIXELS
void SetOrigin(const Vec &pos)
Definition: box2.h:203
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:120
coord_type GetY() const
Definition: box2.h:182
coord_type GetX() const
Definition: box2.h:181
coord_type GetRight() const
Definition: box2.h:190
coord_type GetBottom() const
Definition: box2.h:191
void SetEnd(coord_type x, coord_type y)
Definition: box2.h:256
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:589
bool IsZero() const
Definition: eda_angle.h:169
void getLinePositions(const wxString &aText, const VECTOR2I &aPosition, wxArrayString &aTextLines, std::vector< VECTOR2I > &aPositions, std::vector< VECTOR2I > &aExtents, const TEXT_ATTRIBUTES &aAttrs) const
Definition: font.cpp:166
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
Definition: font.cpp:362
static constexpr double INTERLINE_PITCH_RATIO
Definition: font.h:256
void OutlineToSegments(CONTOURS *aContours)
Class OUTLINE_FONT implements outline font drawing.
Definition: outline_font.h:52
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:150
static FT_Library m_freeType
Definition: outline_font.h:151
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:195
static wxString FreeTypeVersion()
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:118
double GetInterline(double aGlyphHeight=0.0, double aLineSpacing=1.0) const override
Compute the distance (interline) between 2 lines of text (for multiline texts).
static wxString FontConfigVersion()
void GetLinesAsGlyphs(std::vector< std::unique_ptr< GLYPH > > *aGlyphs, const wxString &aText, const VECTOR2I &aPosition, const TEXT_ATTRIBUTES &aAttrs) const
double ComputeUnderlineVerticalPosition(double aGlyphHeight) const override
Compute the vertical position of an underline.
int faceSize() const
Definition: outline_font.h:185
static constexpr double m_outlineFontSizeCompensation
Definition: outline_font.h:167
static constexpr double m_underlineOffsetScaler
Definition: outline_font.h:179
double ComputeOverbarVerticalPosition(double aGlyphHeight) const override
Compute the vertical position of an overbar.
int subscriptSize() const
Definition: outline_font.h:192
static wxString FontLibraryVersion()
static wxString HarfBuzzVersion()
static OUTLINE_FONT * LoadFont(const wxString &aFontFileName, bool aBold, bool aItalic)
Load an outline font.
static constexpr double m_subscriptVerticalOffset
Definition: outline_font.h:194
OpenGL implementation of the Graphics Abstraction Layer.
Definition: opengl_gal.h:70
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:71
static wxString Version()
Definition: fontconfig.cpp:42
unsigned int TEXT_STYLE_FLAGS
Definition: font.h:63
bool IsSuperscript(TEXT_STYLE_FLAGS aFlags)
Definition: font.h:78
bool IsSubscript(TEXT_STYLE_FLAGS aFlags)
Definition: font.h:84
FONTCONFIG * Fontconfig()
Definition: fontconfig.cpp:54
Definition: font.h:100
constexpr int GLYPH_RESOLUTION
Definition: glyph.h:41
std::vector< CONTOUR > CONTOURS
constexpr double GLYPH_SIZE_SCALER
Definition: glyph.h:42
std::vector< VECTOR2D > GLYPH_POINTS
Definition: glyph.h:110
static bool contourIsHole(const CONTOUR &c)
static bool contourIsFilled(const CONTOUR &c)
see class PGM_BASE
FT_Orientation m_Orientation
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
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:85
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588