diff --git a/common/font/outline_decomposer.cpp b/common/font/outline_decomposer.cpp index 6b3d5efd34..65cca8d1b3 100644 --- a/common/font/outline_decomposer.cpp +++ b/common/font/outline_decomposer.cpp @@ -38,7 +38,8 @@ OUTLINE_DECOMPOSER::OUTLINE_DECOMPOSER( FT_Outline& aOutline ) : static VECTOR2D toVector2D( const FT_Vector* aFreeTypeVector ) { - return VECTOR2D( aFreeTypeVector->x, aFreeTypeVector->y ); + return VECTOR2D( aFreeTypeVector->x * GLYPH_SIZE_SCALER, + aFreeTypeVector->y * GLYPH_SIZE_SCALER ); } @@ -62,8 +63,7 @@ int OUTLINE_DECOMPOSER::moveTo( const FT_Vector* aEndPoint, void* aCallbackData { OUTLINE_DECOMPOSER* decomposer = static_cast( aCallbackData ); - decomposer->m_lastEndPoint.x = aEndPoint->x; - decomposer->m_lastEndPoint.y = aEndPoint->y; + decomposer->m_lastEndPoint = toVector2D( aEndPoint ); decomposer->newContour(); decomposer->addContourPoint( decomposer->m_lastEndPoint ); @@ -76,8 +76,7 @@ int OUTLINE_DECOMPOSER::lineTo( const FT_Vector* aEndPoint, void* aCallbackData { OUTLINE_DECOMPOSER* decomposer = static_cast( aCallbackData ); - decomposer->m_lastEndPoint.x = aEndPoint->x; - decomposer->m_lastEndPoint.y = aEndPoint->y; + decomposer->m_lastEndPoint = toVector2D( aEndPoint ); decomposer->addContourPoint( decomposer->m_lastEndPoint ); @@ -112,12 +111,10 @@ int OUTLINE_DECOMPOSER::cubicTo( const FT_Vector* aFirstControlPoint, GLYPH_POINTS result; decomposer->approximateBezierCurve( result, bezier ); - for( const VECTOR2D& p : result ) decomposer->addContourPoint( p ); - decomposer->m_lastEndPoint.x = aEndPoint->x; - decomposer->m_lastEndPoint.y = aEndPoint->y; + decomposer->m_lastEndPoint = toVector2D( aEndPoint ); return 0; } @@ -177,14 +174,12 @@ bool OUTLINE_DECOMPOSER::approximateCubicBezierCurve( GLYPH_POINTS& aResul { wxASSERT( aCubicBezier.size() == 4 ); + // minimumSegmentLength defines the "smoothness" of the + // curve-to-straight-segments conversion: the larger, the coarser // TODO: find out what the minimum segment length should really be! - static const int minimumSegmentLength = 50; - GLYPH_POINTS tmp; - BEZIER_POLY converter( aCubicBezier ); - converter.GetPoly( tmp, minimumSegmentLength ); - - for( unsigned int i = 0; i < tmp.size(); i++ ) - aResult.push_back( tmp[i] ); + constexpr int minimumSegmentLength = 10; + BEZIER_POLY converter( aCubicBezier ); + converter.GetPoly( aResult, minimumSegmentLength ); return true; } @@ -242,19 +237,8 @@ int OUTLINE_DECOMPOSER::winding( const GLYPH_POINTS& aContour ) const } } - unsigned int i_prev_vertex; - unsigned int i_next_vertex; - - // TODO: this should be done with modulo arithmetic for clarity - if( i_lowest_vertex == 0 ) - i_prev_vertex = aContour.size() - 1; - else - i_prev_vertex = i_lowest_vertex - 1; - - if( i_lowest_vertex == aContour.size() - 1 ) - i_next_vertex = 0; - else - i_next_vertex = i_lowest_vertex + 1; + unsigned int i_prev_vertex = ( i_lowest_vertex + aContour.size() - 1 ) % aContour.size(); + unsigned int i_next_vertex = ( i_lowest_vertex + 1 ) % aContour.size(); const VECTOR2D& lowest = aContour[i_lowest_vertex]; VECTOR2D prev( aContour[i_prev_vertex] ); @@ -268,7 +252,7 @@ int OUTLINE_DECOMPOSER::winding( const GLYPH_POINTS& aContour ) const if( i_prev_vertex == i_lowest_vertex ) { - // ERROR: degenerate contour (all points are equal) + // ERROR: degenerate contour (all points are colinear with equal Y coordinate) // TODO: signal error // for now let's just return something at random return cw; diff --git a/common/font/outline_font.cpp b/common/font/outline_font.cpp index 66616c2d6f..76b7924dcc 100644 --- a/common/font/outline_font.cpp +++ b/common/font/outline_font.cpp @@ -41,21 +41,6 @@ using namespace KIFONT; -// The height of the KiCad stroke font is the distance between stroke endpoints for a vertical -// line of cap-height. So the cap-height of the font is actually stroke-width taller than its -// height. -// Outline fonts are normally scaled on full-height (including ascenders and descenders), so we -// need to compensate to keep them from being much smaller than their stroked counterparts. -constexpr double OUTLINE_FONT_SIZE_COMPENSATION = 1.4; - -// The KiCad stroke font uses a subscript/superscript size ratio of 0.7. This ratio is also -// commonly used in LaTeX, but fonts with designed-in subscript and superscript glyphs are more -// likely to use 0.58. -// For auto-generated subscript and superscript glyphs in outline fonts we split the difference -// with 0.64. -static constexpr double SUBSCRIPT_SUPERSCRIPT_SIZE = 0.64; - - FT_Library OUTLINE_FONT::m_freeType = nullptr; OUTLINE_FONT::OUTLINE_FONT() : @@ -91,9 +76,6 @@ OUTLINE_FONT* OUTLINE_FONT::LoadFont( const wxString& aFontName, bool aBold, boo FT_Error OUTLINE_FONT::loadFace( const wxString& aFontFileName ) { - m_faceScaler = m_faceSize * 64; - int subscriptFaceScaler = KiROUND( m_faceSize * 64 * SUBSCRIPT_SUPERSCRIPT_SIZE ); - // TODO: check that going from wxString to char* with UTF-8 // conversion for filename makes sense on any/all platforms FT_Error e = FT_New_Face( m_freeType, aFontFileName.mb_str( wxConvUTF8 ), 0, &m_face ); @@ -101,15 +83,13 @@ FT_Error OUTLINE_FONT::loadFace( const wxString& aFontFileName ) if( !e ) { FT_Select_Charmap( m_face, FT_Encoding::FT_ENCODING_UNICODE ); - FT_Set_Char_Size( m_face, 0, m_faceScaler, 0, 0 ); - - e = FT_New_Face( m_freeType, aFontFileName.mb_str( wxConvUTF8 ), 0, &m_subscriptFace ); - - if( !e ) - { - FT_Select_Charmap( m_subscriptFace, FT_Encoding::FT_ENCODING_UNICODE ); - FT_Set_Char_Size( m_subscriptFace, 0, subscriptFaceScaler, 0, 0 ); - } + // params: + // m_face = handle to face object + // 0 = char width in 1/64th of points ( 0 = same as char height ) + // faceSize() = char height in 1/64th of points + // GLYPH_RESOLUTION = horizontal device resolution (288dpi, 4x default) + // 0 = vertical device resolution ( 0 = same as horizontal ) + FT_Set_Char_Size( m_face, 0, faceSize(), GLYPH_RESOLUTION, 0 ); } return e; @@ -125,7 +105,7 @@ double OUTLINE_FONT::ComputeOverbarVerticalPosition( double aGlyphHeight ) const // The overbar on actual text is positioned above the bounding box of the glyphs. However, // that's expensive to calculate so we use an estimation here (as this is only used for // calculating bounding boxes). - return aGlyphHeight * OUTLINE_FONT_SIZE_COMPENSATION; + return aGlyphHeight * m_outlineFontSizeCompensation; } @@ -140,7 +120,13 @@ double OUTLINE_FONT::GetInterline( double aGlyphHeight, double aLineSpacing ) co if( GetFace()->units_per_EM ) pitch = GetFace()->height / GetFace()->units_per_EM; - return ( aLineSpacing * aGlyphHeight * pitch * OUTLINE_FONT_SIZE_COMPENSATION ); + double interline = aLineSpacing * aGlyphHeight * pitch * m_outlineFontSizeCompensation; + + // FONT TODO this hack is an attempt to fix interline spacing by eyeballing it + static constexpr double interlineHackMultiplier = 1.2; + interline *= interlineHackMultiplier; + + return interline; } @@ -235,29 +221,32 @@ VECTOR2I OUTLINE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vectorglyph; + FT_Load_Glyph( face, glyphInfo[i].codepoint, FT_LOAD_NO_BITMAP ); // contours is a collection of all outlines in the glyph; // example: glyph for 'o' generally contains 2 contours, // one for the glyph outline and one for the hole CONTOURS contours; - OUTLINE_DECOMPOSER decomposer( faceGlyph->outline ); + OUTLINE_DECOMPOSER decomposer( face->glyph->outline ); decomposer.OutlineToSegments( &contours ); std::unique_ptr glyph = std::make_unique(); @@ -300,9 +284,9 @@ VECTOR2I OUTLINE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vectorHasHoles() ) glyph->Fracture( SHAPE_POLY_SET::PM_FAST ); // FONT TODO verify aFastMode aGlyphs->push_back( std::move( glyph ) ); } - cursor.x += pos.x_advance; - cursor.y += pos.y_advance; + hb_glyph_position_t& pos = glyphPos[i]; + cursor.x += ( pos.x_advance * GLYPH_SIZE_SCALER ); + cursor.y += ( pos.y_advance * GLYPH_SIZE_SCALER ); } if( IsOverbar( aTextStyle ) && aGlyphs ) @@ -354,8 +343,8 @@ VECTOR2I OUTLINE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector m_contourCache; + + // The height of the KiCad stroke font is the distance between stroke endpoints for a vertical + // line of cap-height. So the cap-height of the font is actually stroke-width taller than its + // height. + // Outline fonts are normally scaled on full-height (including ascenders and descenders), so we + // need to compensate to keep them from being much smaller than their stroked counterparts. + static constexpr double m_outlineFontSizeCompensation = 1.4; + + // FT_Set_Char_Size() gets character width and height specified in + // 1/64ths of a point + static constexpr int m_charSizeScaler = 64; + + // The KiCad stroke font uses a subscript/superscript size ratio of 0.7. This ratio is also + // commonly used in LaTeX, but fonts with designed-in subscript and superscript glyphs are more + // likely to use 0.58. + // For auto-generated subscript and superscript glyphs in outline fonts we split the difference + // with 0.64. + static constexpr double m_subscriptSuperscriptSize = 0.64; + + int faceSize( int aSize ) const + { + return aSize * m_charSizeScaler * m_outlineFontSizeCompensation; + }; + int faceSize() const { return faceSize( m_faceSize ); } + + // also for superscripts + int subscriptSize( int aSize ) const + { + return KiROUND( faceSize( aSize ) * m_subscriptSuperscriptSize ); + } + int subscriptSize() const { return subscriptSize( m_faceSize ); } + + static constexpr double m_subscriptVerticalOffset = -0.25; + static constexpr double m_superscriptVerticalOffset = 0.45; + static constexpr double m_overbarOffset = 0.16; + static constexpr double m_overbarHeightMultiplier = 0.07; }; } //namespace KIFONT