30#include <harfbuzz/hb.h>
31#include <harfbuzz/hb-ft.h>
46FT_Library OUTLINE_FONT::m_freeType =
nullptr;
48OUTLINE_FONT::OUTLINE_FONT() :
67 FT_Library_Version(
m_freeType, &major, &minor, &patch );
75 return wxString::FromUTF8( HB_VERSION_STRING );
98 fc::FF_RESULT retval =
Fontconfig()->FindFont( aFontName, fontFile, aBold, aItalic );
100 if( retval == fc::FF_RESULT::FF_MISSING_BOLD || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
103 if( retval == fc::FF_RESULT::FF_MISSING_ITAL || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
106 if( retval != fc::FF_RESULT::FF_ERROR )
120 FT_Error e = FT_New_Face(
m_freeType, aFontFileName.mb_str( wxConvUTF8 ), 0, &
m_face );
124 FT_Select_Charmap(
m_face, FT_Encoding::FT_ENCODING_UNICODE );
175 static constexpr double interlineHackMultiplier = 1.2;
176 interline *= interlineHackMultiplier;
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() )
232 const wxString& aText,
const VECTOR2I& aPosition,
235 wxArrayString strings;
236 std::vector<VECTOR2I> positions;
237 std::vector<VECTOR2I> extents;
245 for(
size_t i = 0; i < strings.GetCount(); i++ )
247 (void)
drawMarkup(
nullptr, aGlyphs, strings.Item( i ), positions[i], aAttrs.
m_Size,
254 const wxString& aText,
const VECTOR2I& aSize,
256 bool aMirror,
const VECTOR2I& aOrigin,
261 constexpr double TAB_WIDTH = 4 * 0.6;
269 aBBox->
SetEnd( aPosition );
272 for( wxUniChar c : aText )
277 if( !textRun.IsEmpty() )
279 position =
getTextAsGlyphs( aBBox, aGlyphs, textRun, aSize, position, aAngle,
280 aMirror, aOrigin, aTextStyle );
284 int tabWidth =
KiROUND( aSize.
x * TAB_WIDTH );
285 int currentIntrusion = ( position.
x - aOrigin.
x ) % tabWidth;
287 position.
x += tabWidth - currentIntrusion;
295 if( !textRun.IsEmpty() )
297 position =
getTextAsGlyphs( aBBox, aGlyphs, textRun, aSize, position, aAngle, aMirror,
298 aOrigin, aTextStyle );
307 double thicknessRatio =
abs( (
double) thickness ) / (double) height;
308 double ascenderRatio = (double) ascender / (
double) height;
310 if( thicknessRatio < 0.05 )
312 else if( ascenderRatio < 0.78 )
314 else if( ascenderRatio < 0.80 )
322 const wxString& aText,
const VECTOR2I& aSize,
324 bool aMirror,
const VECTOR2I& aOrigin,
339 hb_buffer_t* buf = hb_buffer_create();
340 hb_buffer_add_utf8( buf,
UTF8( aText ).c_str(), -1, 0, -1 );
341 hb_buffer_guess_segment_properties( buf );
344 unsigned int glyphCount;
345 hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( buf, &glyphCount );
346 hb_glyph_position_t* glyphPos = hb_buffer_get_glyph_positions( buf, &glyphCount );
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 );
357 for(
unsigned int i = 0; i < glyphCount; i++ )
360 if( i > 0 && glyphInfo[i].cluster == glyphInfo[i-1].cluster )
369 const float angle = ( -M_PI * 12 ) / 180.0f;
370 matrix.xx = (FT_Fixed) ( cos(
angle ) * 0x10000L );
371 matrix.xy = (FT_Fixed) ( -sin(
angle ) * 0x10000L );
372 matrix.yx = (FT_Fixed) ( 0 * 0x10000L );
373 matrix.yy = (FT_Fixed) ( 1 * 0x10000L );
375 FT_Set_Transform(face, &matrix,0);
378 FT_Load_Glyph( face, glyphInfo[i].codepoint, FT_LOAD_NO_BITMAP );
381 FT_Outline_Embolden( &face->glyph->outline, 1 << 6 );
390 std::unique_ptr<OUTLINE_GLYPH> glyph = std::make_unique<OUTLINE_GLYPH>();
391 std::vector<SHAPE_LINE_CHAIN> holes;
411 pt.
x = aOrigin.
x - ( pt.
x - aOrigin.
x );
422 holes.push_back( std::move( shape ) );
424 glyph->AddOutline( std::move( shape ) );
429 if( hole.PointCount() )
431 for(
int ii = 0; ii < glyph->OutlineCount(); ++ii )
433 if( glyph->Outline( ii ).PointInside( hole.GetPoint( 0 ) ) )
435 glyph->AddHole( std::move( hole ), ii );
446 if( glyph->HasHoles() )
449 aGlyphs->push_back( std::move( glyph ) );
452 hb_glyph_position_t& pos = glyphPos[i];
460 VECTOR2I extents(
cursor.x * scaleFactor.
x, ( ascender + descender ) *
abs( scaleFactor.
y ) );
467 std::vector<std::unique_ptr<GLYPH>> underscoreGlyphs;
473 BOX2I underscoreBBox;
475 for(
const VECTOR2I& pt : underscoreGlyph->Outline( 0 ).CPoints() )
476 underscoreBBox.
Merge( pt );
478 int barThickness = underscoreBBox.
GetHeight();
481 double barTrim = barThickness / 2.0;
482 double barOffset =
getOverbarOffset( ascender, height, barThickness / scaleFactor.
y );
487 topLeft.
y += ascender * scaleFactor.
y * ( 1.0 + barOffset );
488 topRight.
y = topLeft.
y;
490 topLeft.
x += barTrim;
491 topRight.
x += extents.
x - barTrim;
493 extents.
y *= ( 1.0 + barOffset + barOffset );
494 extents.
x += barTrim;
505 topLeft.
x = aOrigin.
x - ( topLeft.
x - aOrigin.
x );
506 topRight.
x = aOrigin.
x - ( topRight.
x - aOrigin.
x );
517 int maxError =
KiROUND( barThickness / 48 );
522 std::unique_ptr<OUTLINE_GLYPH> overbarGlyph = std::make_unique<OUTLINE_GLYPH>( poly );
523 aGlyphs->push_back( std::move( overbarGlyph ) );
527 hb_buffer_destroy( buf );
528 hb_font_destroy( referencedFont );
533 aBBox->
Merge( aPosition + extents );
535 return VECTOR2I( aPosition.
x + cursorDisplacement.
x, aPosition.
y + cursorDisplacement.
y );
539#undef OUTLINEFONT_RENDER_AS_PIXELS
540#ifdef OUTLINEFONT_RENDER_AS_PIXELS
544void OUTLINE_FONT::RenderToOpenGLCanvas(
KIGFX::OPENGL_GAL& aGal,
const wxString& aString,
546 const EDA_ANGLE& aOrientation,
bool aIsMirrored )
const
548 hb_buffer_t* buf = hb_buffer_create();
549 hb_buffer_add_utf8( buf,
UTF8( aString ).c_str(), -1, 0, -1 );
550 hb_buffer_guess_segment_properties( buf );
552 unsigned int glyphCount;
553 hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( buf, &glyphCount );
554 hb_glyph_position_t* glyphPos = hb_buffer_get_glyph_positions( buf, &glyphCount );
555 hb_font_t* referencedFont = hb_ft_font_create_referenced(
m_face );
557 hb_ft_font_set_funcs( referencedFont );
558 hb_shape( referencedFont, buf,
nullptr, 0 );
560 const double mirror_factor = ( aIsMirrored ? 1 : -1 );
561 const double x_scaleFactor = mirror_factor * aGlyphSize.
x / mScaler;
562 const double y_scaleFactor = aGlyphSize.
y / mScaler;
564 hb_position_t cursor_x = 0;
565 hb_position_t cursor_y = 0;
567 for(
unsigned int i = 0; i < glyphCount; i++ )
569 hb_glyph_position_t& pos = glyphPos[i];
570 int codepoint = glyphInfo[i].codepoint;
572 FT_Error e = FT_Load_Glyph(
m_face, codepoint, FT_LOAD_DEFAULT );
576 e = FT_Get_Glyph(
m_face->glyph, &glyph );
579 wxPoint pt( aPosition );
580 pt.x += ( cursor_x >> 6 ) * x_scaleFactor;
581 pt.y += ( cursor_y >> 6 ) * y_scaleFactor;
583 cursor_x += pos.x_advance;
584 cursor_y += pos.y_advance;
587 hb_buffer_destroy( buf );
void SetOrigin(const Vec &pos)
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
coord_type GetHeight() const
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.
wxString m_fontName
Font name.
wxString m_fontFileName
Font file name.
void getLinePositions(const wxString &aText, const VECTOR2I &aPosition, wxArrayString &aTextLines, std::vector< VECTOR2I > &aPositions, std::vector< VECTOR2I > &aExtents, const TEXT_ATTRIBUTES &aAttrs) 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
static constexpr double INTERLINE_PITCH_RATIO
void OutlineToSegments(CONTOURS *aContours)
Class OUTLINE_FONT implements outline font drawing.
FT_Error loadFace(const wxString &aFontFileName)
static FT_Library m_freeType
BOX2I getBoundingBox(const std::vector< std::unique_ptr< GLYPH > > &aGlyphs) const
static constexpr double m_superscriptVerticalOffset
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
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()
bool IsItalic() const override
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.
double getOverbarOffset(int ascender, int height, int thickness) const
static constexpr double m_outlineFontSizeCompensation
static constexpr double m_underlineOffsetScaler
double ComputeOverbarVerticalPosition(double aGlyphHeight) const override
Compute the vertical position of an overbar.
int subscriptSize() const
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
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 Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
Represent a set of closed polygons.
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
static wxString Version()
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
static constexpr EDA_ANGLE & ANGLE_0
unsigned int TEXT_STYLE_FLAGS
bool IsOverbar(TEXT_STYLE_FLAGS aFlags)
bool IsSuperscript(TEXT_STYLE_FLAGS aFlags)
static constexpr double ITALIC_TILT
Tilt factor for italic style (this is the scaling factor on dY relative coordinates to give a tilted ...
bool IsSubscript(TEXT_STYLE_FLAGS aFlags)
FONTCONFIG * Fontconfig()
constexpr int GLYPH_RESOLUTION
std::vector< CONTOUR > CONTOURS
constexpr double GLYPH_SIZE_SCALER
std::vector< VECTOR2D > GLYPH_POINTS
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
static bool contourIsHole(const CONTOUR &c)
static bool contourIsFilled(const CONTOUR &c)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
FT_Orientation m_Orientation
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".