22#include <harfbuzz/hb.h>
23#include <harfbuzz/hb-ft.h>
30#include FT_SFNT_NAMES_H
31#include FT_TRUETYPE_TABLES_H
59 TT_OS2* os2 =
reinterpret_cast<TT_OS2*
>( FT_Get_Sfnt_Table(
m_face, FT_SFNT_OS2 ) );
66 if( os2->fsType & FT_FSTYPE_BITMAP_EMBEDDING_ONLY )
73 FT_UShort embeddingBits = os2->fsType & 0x000F;
76 if( embeddingBits == FT_FSTYPE_INSTALLABLE_EMBEDDING )
80 if( embeddingBits & FT_FSTYPE_EDITABLE_EMBEDDING )
84 if( embeddingBits & FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING )
93 const std::vector<wxString>* aEmbeddedFiles,
bool aForDrawingSheet )
95 std::unique_ptr<OUTLINE_FONT> font = std::make_unique<OUTLINE_FONT>();
102 fc::FF_RESULT retval =
Fontconfig()->
FindFont( aFontName, fontFile, faceIndex, aBold, aItalic, aEmbeddedFiles );
104 if( retval == fc::FF_RESULT::FF_ERROR )
107 if( retval == fc::FF_RESULT::FF_MISSING_BOLD || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
110 if( retval == fc::FF_RESULT::FF_MISSING_ITAL || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
113 if( font->loadFace( fontFile, faceIndex ) != 0 )
116 font->m_fontName = aFontName;
117 font->m_fontFileName = fontFile;
118 font->m_forDrawingSheet = aForDrawingSheet;
120 return font.release();
128 FT_Error e = FT_New_Face(
m_freeType, aFontFileName.mb_str( wxConvUTF8 ), aFaceIndex, &
m_face );
150 if( FT_Select_Charmap( aFace, FT_ENCODING_UNICODE ) == 0 )
155 static const FT_ULong probes[] = {
'A',
'a',
'0',
' ' };
157 for( FT_ULong codepoint : probes )
159 if( FT_Get_Char_Index( aFace, codepoint ) != 0 )
166 if( FT_Select_Charmap( aFace, FT_ENCODING_MS_SYMBOL ) == 0 )
170 FT_Select_Charmap( aFace, FT_ENCODING_UNICODE );
186 case FT_ORIENTATION_TRUETYPE:
return c.
m_Winding == 1;
187 case FT_ORIENTATION_POSTSCRIPT:
return c.
m_Winding == -1;
188 default:
return false;
206 for(
const std::unique_ptr<KIFONT::GLYPH>& glyph : aGlyphs )
208 BOX2D bbox = glyph->BoundingBox();
211 if( minX > bbox.
GetX() )
214 if( minY > bbox.
GetY() )
233 const METRICS& aFontMetrics )
const
235 wxArrayString strings;
236 std::vector<VECTOR2I> positions;
237 std::vector<VECTOR2I> extents;
243 getLinePositions( aText, aPosition, strings, positions, extents, aAttrs, aFontMetrics );
245 for(
size_t i = 0; i < strings.GetCount(); i++ )
247 (void)
drawMarkup(
nullptr, aGlyphs, strings.Item( i ), positions[i], aAttrs.
m_Size,
260 constexpr double TAB_WIDTH = 4 * 0.6;
268 aBBox->
SetEnd( aPosition );
271 for( wxUniChar c : aText )
276 if( !textRun.IsEmpty() )
278 position =
getTextAsGlyphs( aBBox, aGlyphs, textRun, aSize, position, aAngle, aMirror, aOrigin,
283 int tabWidth =
KiROUND( aSize.
x * TAB_WIDTH );
284 int currentIntrusion = ( position.
x - aOrigin.
x ) % tabWidth;
286 position.
x += tabWidth - currentIntrusion;
294 if( !textRun.IsEmpty() )
295 position =
getTextAsGlyphs( aBBox, aGlyphs, textRun, aSize, position, aAngle, aMirror, aOrigin, aTextStyle );
308 return getTextAsGlyphsUnlocked( aBBox, aGlyphs, aText, aSize, aPosition, aAngle, aMirror, aOrigin, aTextStyle );
349 static std::unordered_map<HARFBUZZ_CACHE_KEY, HARFBUZZ_CACHE_ENTRY> s_harfbuzzCache;
351 std::string textUtf8 =
UTF8( aText );
358 hb_buffer_t* buf = hb_buffer_create();
359 hb_buffer_add_utf8( buf, textUtf8.c_str(), -1, 0, -1 );
360 hb_buffer_guess_segment_properties( buf );
363 hb_font_t* referencedFont = hb_ft_font_create_referenced( aFace );
365 hb_shape( referencedFont, buf,
nullptr, 0 );
367 unsigned int glyphCount;
368 hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( buf, &glyphCount );
369 hb_glyph_position_t* glyphPos = hb_buffer_get_glyph_positions( buf, &glyphCount );
371 entry.
m_GlyphInfo.assign( glyphInfo, glyphInfo + glyphCount );
375 hb_buffer_destroy( buf );
376 hb_font_destroy( referencedFont );
431 const float angle = (float) ( -
M_PI * 12.0f ) / 180.0f;
432 matrix.xx = (FT_Fixed) ( cos( angle ) * 0x10000L );
433 matrix.xy = (FT_Fixed) ( -sin( angle ) * 0x10000L );
435 matrix.yy = 0x10000L;
437 FT_Set_Transform(
m_face, &matrix,
nullptr );
443 if( FT_Load_Glyph(
m_face, aGlyphIndex, FT_LOAD_NO_BITMAP ) != 0 )
447 if(
m_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE )
451 FT_Outline_Embolden( &
m_face->glyph->outline, 1 << 6 );
466 const wxString& aText,
const VECTOR2I& aSize,
483 unsigned int glyphCount =
static_cast<unsigned int>( hbShape.
m_GlyphInfo.size() );
484 const hb_glyph_info_t* glyphInfo = hbShape.
m_GlyphInfo.data();
493 aGlyphs->reserve( glyphCount );
497 static std::unordered_map<GLYPH_CACHE_KEY, GLYPH_DATA> s_glyphCache;
499 for(
unsigned int i = 0; i < glyphCount; i++ )
514 BOX2D tofuBox( { scaler * 0.03, 0.0 }, { hb_advance - scaler * 0.02, scaler * 0.72 } );
518 outline.m_Orientation = FT_ORIENTATION_TRUETYPE;
519 outline.m_Points.push_back( tofuBox.GetPosition() );
520 outline.m_Points.push_back( { tofuBox.GetSize().x, tofuBox.GetPosition().y } );
521 outline.m_Points.push_back( tofuBox.GetSize() );
522 outline.m_Points.push_back( { tofuBox.GetPosition().x, tofuBox.GetSize().y } );
523 glyphData.
m_Contours.push_back( std::move( outline ) );
526 tofuBox.Move( { scaler * 0.06, scaler * 0.06 } );
527 tofuBox.SetSize( { tofuBox.GetWidth() - scaler * 0.06, tofuBox.GetHeight() - scaler * 0.06 } );
530 hole.
m_Points.push_back( tofuBox.GetPosition() );
531 hole.
m_Points.push_back( { tofuBox.GetSize().x, tofuBox.GetPosition().y } );
532 hole.
m_Points.push_back( tofuBox.GetSize() );
533 hole.
m_Points.push_back( { tofuBox.GetPosition().x, tofuBox.GetSize().y } );
534 glyphData.
m_Contours.push_back( std::move( hole ) );
538 std::unique_ptr<OUTLINE_GLYPH> glyph = std::make_unique<OUTLINE_GLYPH>();
539 std::vector<SHAPE_LINE_CHAIN> holes;
543 const std::vector<VECTOR2D>& points = c.
m_Points;
561 pt.
x = aOrigin.
x - ( pt.
x - aOrigin.
x );
572 holes.push_back( std::move( shape ) );
574 glyph->AddOutline( std::move( shape ) );
579 bool added_hole =
false;
581 if( hole.PointCount() )
583 for(
int ii = 0; ii < glyph->OutlineCount(); ++ii )
585 if( glyph->Outline( ii ).PointInside( hole.GetPoint( 0 ) ) )
587 glyph->AddHole( std::move( hole ), ii );
597 glyph->AddOutline( std::move( hole ) );
603 glyph->CacheTriangulation();
611 aGlyphs->push_back( std::move( glyph ) );
614 const hb_glyph_position_t& pos = glyphPos[i];
624 aBBox->
Merge( aPosition -
VECTOR2I( 0, ascender * abs( scaleFactor.
y ) ) );
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
constexpr void SetOrigin(const Vec &pos)
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
constexpr coord_type GetY() const
constexpr coord_type GetX() const
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
constexpr coord_type GetRight() const
constexpr void SetEnd(coord_type x, coord_type y)
constexpr coord_type GetBottom() 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, std::optional< VECTOR2I > aMousePos=std::nullopt, wxString *aActiveUrl=nullptr) const
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).
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
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
int subscriptSize() const
static constexpr double m_subscriptVerticalOffset
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...
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...
unsigned int TEXT_STYLE_FLAGS
bool IsSuperscript(TEXT_STYLE_FLAGS aFlags)
bool IsSubscript(TEXT_STYLE_FLAGS aFlags)
FONTCONFIG * Fontconfig()
static constexpr std::size_t hash_val(const Types &... args)
constexpr int GLYPH_RESOLUTION
constexpr double GLYPH_SIZE_SCALER
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)
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 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
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.
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D