26#include <harfbuzz/hb.h>
27#include <harfbuzz/hb-ft.h>
58 std::unique_ptr<OUTLINE_FONT> font = std::make_unique<OUTLINE_FONT>();
64 fc::FF_RESULT retval =
Fontconfig()->FindFont( aFontName, fontFile, faceIndex, aBold, aItalic );
66 if( retval == fc::FF_RESULT::FF_ERROR )
69 if( retval == fc::FF_RESULT::FF_MISSING_BOLD || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
72 if( retval == fc::FF_RESULT::FF_MISSING_ITAL || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
75 if( font->loadFace( fontFile, faceIndex ) != 0 )
78 font->m_fontName = aFontName;
79 font->m_fontFileName = fontFile;
81 return font.release();
89 FT_Error e = FT_New_Face(
m_freeType, aFontFileName.mb_str( wxConvUTF8 ), aFaceIndex, &
m_face );
93 FT_Select_Charmap(
m_face, FT_Encoding::FT_ENCODING_UNICODE );
113 double glyphToFontHeight = 1.0;
118 return aFontMetrics.
GetInterline( aGlyphHeight * glyphToFontHeight );
126 case FT_ORIENTATION_TRUETYPE:
return c.
m_Winding == 1;
127 case FT_ORIENTATION_POSTSCRIPT:
return c.
m_Winding == -1;
128 default:
return false;
146 for(
const std::unique_ptr<KIFONT::GLYPH>& glyph : aGlyphs )
148 BOX2D bbox = glyph->BoundingBox();
151 if( minX > bbox.
GetX() )
154 if( minY > bbox.
GetY() )
172 const wxString& aText,
const VECTOR2I& aPosition,
174 const METRICS& aFontMetrics )
const
176 wxArrayString strings;
177 std::vector<VECTOR2I> positions;
178 std::vector<VECTOR2I> extents;
182 textStyle |= TEXT_STYLE::ITALIC;
184 getLinePositions( aText, aPosition, strings, positions, extents, aAttrs, aFontMetrics );
186 for(
size_t i = 0; i < strings.GetCount(); i++ )
188 (void)
drawMarkup(
nullptr, aGlyphs, strings.Item( i ), positions[i], aAttrs.
m_Size,
195 const wxString& aText,
const VECTOR2I& aSize,
197 bool aMirror,
const VECTOR2I& aOrigin,
202 constexpr double TAB_WIDTH = 4 * 0.6;
210 aBBox->
SetEnd( aPosition );
213 for( wxUniChar c : aText )
218 if( !textRun.IsEmpty() )
220 position =
getTextAsGlyphs( aBBox, aGlyphs, textRun, aSize, position, aAngle,
221 aMirror, aOrigin, aTextStyle );
225 int tabWidth =
KiROUND( aSize.
x * TAB_WIDTH );
226 int currentIntrusion = ( position.
x - aOrigin.
x ) % tabWidth;
228 position.
x += tabWidth - currentIntrusion;
236 if( !textRun.IsEmpty() )
238 position =
getTextAsGlyphs( aBBox, aGlyphs, textRun, aSize, position, aAngle, aMirror,
239 aOrigin, aTextStyle );
247 const wxString& aText,
const VECTOR2I& aSize,
249 bool aMirror,
const VECTOR2I& aOrigin,
255 aOrigin, aTextStyle );
282 return hash<const void*>()( k.
face ) ^ hash<unsigned>()( k.
codepoint )
291 std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
292 const wxString& aText,
const VECTOR2I& aSize,
294 bool aMirror,
const VECTOR2I& aOrigin,
309 hb_buffer_t* buf = hb_buffer_create();
310 hb_buffer_add_utf8( buf,
UTF8( aText ).c_str(), -1, 0, -1 );
311 hb_buffer_guess_segment_properties( buf );
314 hb_font_t* referencedFont = hb_ft_font_create_referenced( face );
315 hb_ft_font_set_funcs( referencedFont );
316 hb_shape( referencedFont, buf,
nullptr, 0 );
318 unsigned int glyphCount;
319 hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( buf, &glyphCount );
320 hb_glyph_position_t* glyphPos = hb_buffer_get_glyph_positions( buf, &glyphCount );
328 aGlyphs->reserve( glyphCount );
332 static std::unordered_map<GLYPH_CACHE_KEY, GLYPH_DATA> s_glyphCache;
334 for(
unsigned int i = 0; i < glyphCount; i++ )
337 if( i > 0 && glyphInfo[i].cluster == glyphInfo[i-1].cluster )
352 const float angle = (float)( -M_PI * 12.0f ) / 180.0f;
353 matrix.xx = (FT_Fixed) ( cos( angle ) * 0x10000L );
354 matrix.xy = (FT_Fixed) ( -sin( angle ) * 0x10000L );
355 matrix.yx = (FT_Fixed) ( 0 * 0x10000L );
356 matrix.yy = (FT_Fixed) ( 1 * 0x10000L );
358 FT_Set_Transform( face, &matrix,
nullptr );
361 FT_Load_Glyph( face, glyphInfo[i].codepoint, FT_LOAD_NO_BITMAP );
364 FT_Outline_Embolden( &face->glyph->outline, 1 << 6 );
371 BOX2D tofuBox( { scaler * 0.03, 0.0 },
372 { hb_advance - scaler * 0.02, scaler * 0.72 } );
379 outline.
m_Points.push_back( tofuBox.GetPosition() );
380 outline.
m_Points.push_back( { tofuBox.GetSize().x, tofuBox.GetPosition().y } );
381 outline.
m_Points.push_back( tofuBox.GetSize() );
382 outline.
m_Points.push_back( { tofuBox.GetPosition().x, tofuBox.GetSize().y } );
386 tofuBox.Move( { scaler * 0.06, scaler * 0.06 } );
387 tofuBox.SetSize( { tofuBox.GetWidth() - scaler * 0.06,
388 tofuBox.GetHeight() - scaler * 0.06 } );
391 hole.
m_Points.push_back( tofuBox.GetPosition() );
392 hole.
m_Points.push_back( { tofuBox.GetSize().x, tofuBox.GetPosition().y } );
393 hole.
m_Points.push_back( tofuBox.GetSize() );
394 hole.
m_Points.push_back( { tofuBox.GetPosition().x, tofuBox.GetSize().y } );
399 std::unique_ptr<OUTLINE_GLYPH> glyph = std::make_unique<OUTLINE_GLYPH>();
400 std::vector<SHAPE_LINE_CHAIN> holes;
404 std::vector<VECTOR2D> points = c.
m_Points;
422 pt.
x = aOrigin.
x - ( pt.
x - aOrigin.
x );
433 holes.push_back( std::move( shape ) );
435 glyph->AddOutline( std::move( shape ) );
440 if( hole.PointCount() )
442 for(
int ii = 0; ii < glyph->OutlineCount(); ++ii )
444 if( glyph->Outline( ii ).PointInside( hole.GetPoint( 0 ) ) )
446 glyph->AddHole( std::move( hole ), ii );
455 glyph->CacheTriangulation(
false,
false );
463 aGlyphs->push_back( std::move( glyph ) );
466 hb_glyph_position_t& pos = glyphPos[i];
473 VECTOR2I extents(
cursor.x * scaleFactor.
x, ( ascender + descender ) * abs( scaleFactor.
y ) );
475 hb_buffer_destroy( buf );
476 hb_font_destroy( referencedFont );
481 aBBox->
Merge( aPosition + extents );
483 return VECTOR2I( aPosition.
x + cursorDisplacement.
x, aPosition.
y + cursorDisplacement.
y );
487#undef OUTLINEFONT_RENDER_AS_PIXELS
488#ifdef OUTLINEFONT_RENDER_AS_PIXELS
492void OUTLINE_FONT::RenderToOpenGLCanvas(
KIGFX::OPENGL_GAL& aGal,
const wxString& aString,
494 const EDA_ANGLE& aOrientation,
bool aIsMirrored )
const
496 hb_buffer_t* buf = hb_buffer_create();
497 hb_buffer_add_utf8( buf,
UTF8( aString ).c_str(), -1, 0, -1 );
498 hb_buffer_guess_segment_properties( buf );
500 unsigned int glyphCount;
501 hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( buf, &glyphCount );
502 hb_glyph_position_t* glyphPos = hb_buffer_get_glyph_positions( buf, &glyphCount );
506 hb_font_t* referencedFont = hb_ft_font_create_referenced(
m_face );
508 hb_ft_font_set_funcs( referencedFont );
509 hb_shape( referencedFont, buf,
nullptr, 0 );
511 const double mirror_factor = ( aIsMirrored ? 1 : -1 );
512 const double x_scaleFactor = mirror_factor * aGlyphSize.
x / mScaler;
513 const double y_scaleFactor = aGlyphSize.
y / mScaler;
515 hb_position_t cursor_x = 0;
516 hb_position_t cursor_y = 0;
518 for(
unsigned int i = 0; i < glyphCount; i++ )
520 hb_glyph_position_t& pos = glyphPos[i];
521 int codepoint = glyphInfo[i].codepoint;
523 FT_Error e = FT_Load_Glyph(
m_face, codepoint, FT_LOAD_DEFAULT );
527 e = FT_Get_Glyph(
m_face->glyph, &glyph );
530 wxPoint pt( aPosition );
531 pt.x += ( cursor_x >> 6 ) * x_scaleFactor;
532 pt.y += ( cursor_y >> 6 ) * y_scaleFactor;
534 cursor_x += pos.x_advance;
535 cursor_y += pos.y_advance;
538 hb_buffer_destroy( buf );
void SetOrigin(const Vec &pos)
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
coord_type GetRight() const
coord_type GetBottom() const
void SetEnd(coord_type x, coord_type y)
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
int AsTenthsOfADegree() const
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
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
double GetInterline(double aFontHeight) const
bool OutlineToSegments(std::vector< CONTOUR > *aContours)
Class OUTLINE_FONT implements outline font drawing.
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
void GetLinesAsGlyphs(std::vector< std::unique_ptr< GLYPH > > *aGlyphs, const wxString &aText, const VECTOR2I &aPosition, const TEXT_ATTRIBUTES &aAttrs, const METRICS &aFontMetrics) const
static constexpr double m_outlineFontSizeCompensation
int subscriptSize() const
static OUTLINE_FONT * LoadFont(const wxString &aFontFileName, bool aBold, bool aItalic)
Load an outline font.
static constexpr double m_subscriptVerticalOffset
OpenGL implementation of the Graphics Abstraction Layer.
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...
unsigned int TEXT_STYLE_FLAGS
bool IsSuperscript(TEXT_STYLE_FLAGS aFlags)
bool IsSubscript(TEXT_STYLE_FLAGS aFlags)
FONTCONFIG * Fontconfig()
constexpr int GLYPH_RESOLUTION
constexpr double GLYPH_SIZE_SCALER
static bool contourIsHole(const CONTOUR &c)
static bool contourIsFilled(const CONTOUR &c)
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.
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".