diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 0714ca165b..2915ef9fb4 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -303,7 +303,6 @@ set( FONT_SRCS font/stroke_font.cpp font/outline_font.cpp font/outline_decomposer.cpp - font/triangulate.cpp font/fontconfig.cpp ) diff --git a/common/eda_text.cpp b/common/eda_text.cpp index d14b2fa28f..c407f5212b 100644 --- a/common/eda_text.cpp +++ b/common/eda_text.cpp @@ -107,7 +107,8 @@ GR_TEXT_V_ALIGN_T EDA_TEXT::MapVertJustify( int aVertJustify ) EDA_TEXT::EDA_TEXT( const wxString& text ) : - m_text( text ) + m_text( text ), + m_bounding_box_cache_valid( false ) { int sz = Mils2iu( DEFAULT_SIZE_TEXT ); SetTextSize( wxSize( sz, sz ) ); @@ -134,6 +135,9 @@ EDA_TEXT::EDA_TEXT( const EDA_TEXT& aText ) KIFONT::OUTLINE_GLYPH* outline_glyph = static_cast( glyph.get() ); m_render_cache.emplace_back( std::make_unique( *outline_glyph ) ); } + + m_bounding_box_cache_valid = aText.m_bounding_box_cache_valid; + m_bounding_box_cache = aText.m_bounding_box_cache; } @@ -162,6 +166,9 @@ EDA_TEXT& EDA_TEXT::operator=( const EDA_TEXT& aText ) m_render_cache.emplace_back( std::make_unique( *outline_glyph ) ); } + m_bounding_box_cache_valid = aText.m_bounding_box_cache_valid; + m_bounding_box_cache = aText.m_bounding_box_cache; + return *this; } @@ -169,7 +176,11 @@ EDA_TEXT& EDA_TEXT::operator=( const EDA_TEXT& aText ) void EDA_TEXT::SetText( const wxString& aText ) { m_text = aText; + cacheShownText(); + + ClearRenderCache(); + m_bounding_box_cache_valid = false; } @@ -179,77 +190,87 @@ void EDA_TEXT::CopyText( const EDA_TEXT& aSrc ) m_shown_text = aSrc.m_shown_text; m_shown_text_has_text_var_refs = aSrc.m_shown_text_has_text_var_refs; - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } void EDA_TEXT::SetTextThickness( int aWidth ) { m_attributes.m_StrokeWidth = aWidth; - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } void EDA_TEXT::SetTextAngle( const EDA_ANGLE& aAngle ) { m_attributes.m_Angle = aAngle; - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } void EDA_TEXT::SetItalic( bool aItalic ) { m_attributes.m_Italic = aItalic; - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } void EDA_TEXT::SetBold( bool aBold ) { m_attributes.m_Bold = aBold; - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } void EDA_TEXT::SetVisible( bool aVisible ) { m_attributes.m_Visible = aVisible; - m_render_cache.clear(); + ClearRenderCache(); } void EDA_TEXT::SetMirrored( bool isMirrored ) { m_attributes.m_Mirrored = isMirrored; - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } void EDA_TEXT::SetMultilineAllowed( bool aAllow ) { m_attributes.m_Multiline = aAllow; - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } void EDA_TEXT::SetHorizJustify( GR_TEXT_H_ALIGN_T aType ) { m_attributes.m_Halign = aType; - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } void EDA_TEXT::SetVertJustify( GR_TEXT_V_ALIGN_T aType ) { m_attributes.m_Valign = aType; - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } void EDA_TEXT::SetKeepUpright( bool aKeepUpright ) { m_attributes.m_KeepUpright = aKeepUpright; - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } @@ -257,7 +278,8 @@ void EDA_TEXT::SetAttributes( const EDA_TEXT& aSrc ) { m_attributes = aSrc.m_attributes; m_pos = aSrc.m_pos; - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } @@ -267,7 +289,8 @@ void EDA_TEXT::SwapText( EDA_TEXT& aTradingPartner ) std::swap( m_shown_text, aTradingPartner.m_shown_text ); std::swap( m_shown_text_has_text_var_refs, aTradingPartner.m_shown_text_has_text_var_refs ); - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } @@ -276,7 +299,11 @@ void EDA_TEXT::SwapAttributes( EDA_TEXT& aTradingPartner ) std::swap( m_attributes, aTradingPartner.m_attributes ); std::swap( m_pos, aTradingPartner.m_pos ); - m_render_cache.clear(); + ClearRenderCache(); + aTradingPartner.ClearRenderCache(); + + m_bounding_box_cache_valid = false; + aTradingPartner.m_bounding_box_cache_valid = false; } @@ -304,8 +331,12 @@ int EDA_TEXT::GetEffectiveTextPenWidth( int aDefaultWidth ) const bool EDA_TEXT::Replace( const wxFindReplaceData& aSearchData ) { bool retval = EDA_ITEM::Replace( aSearchData, m_text ); + cacheShownText(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; + return retval; } @@ -313,35 +344,40 @@ bool EDA_TEXT::Replace( const wxFindReplaceData& aSearchData ) void EDA_TEXT::SetFont( KIFONT::FONT* aFont ) { m_attributes.m_Font = aFont; - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } void EDA_TEXT::SetLineSpacing( double aLineSpacing ) { m_attributes.m_LineSpacing = aLineSpacing; - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } void EDA_TEXT::SetTextSize( const wxSize& aNewSize ) { m_attributes.m_Size = aNewSize; - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } void EDA_TEXT::SetTextWidth( int aWidth ) { m_attributes.m_Size.x = aWidth; - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } void EDA_TEXT::SetTextHeight( int aHeight ) { m_attributes.m_Size.y = aHeight; - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } @@ -368,17 +404,17 @@ void EDA_TEXT::Offset( const VECTOR2I& aOffset ) m_pos += aOffset; for( std::unique_ptr& glyph : m_render_cache ) - { - KIFONT::OUTLINE_GLYPH* outline_glyph = static_cast( glyph.get() ); - outline_glyph->Move( aOffset ); - } + static_cast( glyph.get() )->Move( aOffset ); + + m_bounding_box_cache.Move( aOffset ); } void EDA_TEXT::Empty() { m_text.Empty(); - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } @@ -395,7 +431,8 @@ void EDA_TEXT::cacheShownText() m_shown_text_has_text_var_refs = m_shown_text.Contains( wxT( "${" ) ); } - m_render_cache.clear(); + ClearRenderCache(); + m_bounding_box_cache_valid = false; } @@ -410,6 +447,19 @@ KIFONT::FONT* EDA_TEXT::GetDrawFont() const } + +void EDA_TEXT::ClearRenderCache() +{ + m_render_cache.clear(); +} + + +void EDA_TEXT::ClearBoundingBoxCache() +{ + m_bounding_box_cache_valid = false; +} + + std::vector>* EDA_TEXT::GetRenderCache( const wxString& forResolvedText ) const { @@ -424,7 +474,7 @@ EDA_TEXT::GetRenderCache( const wxString& forResolvedText ) const m_render_cache.clear(); KIFONT::OUTLINE_FONT* font = static_cast( GetFont() ); - font->GetLinesAsGlyphs( m_render_cache, this ); + font->GetLinesAsGlyphs( &m_render_cache, this ); m_render_cache_angle = resolvedAngle; m_render_cache_text = forResolvedText; @@ -474,6 +524,9 @@ int EDA_TEXT::GetInterline() const EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const { + if( m_bounding_box_cache_valid && aLine < 0 && !aInvertY ) + return m_bounding_box_cache; + EDA_RECT rect; wxArrayString strings; wxString text = GetShownText(); @@ -498,8 +551,7 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const double penWidth( thickness ); bool bold = IsBold(); bool italic = IsItalic(); - VECTOR2D extents = font->StringBoundaryLimits( text, fontSize, penWidth, bold, italic ); - int dx = KiROUND( extents.x ); + int dx = font->StringBoundaryLimits( text, fontSize, penWidth, bold, italic ).x; int dy = GetInterline(); // Creates bounding box (rectangle) for horizontal, left and top justified text. The @@ -521,7 +573,7 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const for( unsigned ii = 1; ii < strings.GetCount(); ii++ ) { text = strings.Item( ii ); - dx = KiROUND( font->StringBoundaryLimits( text, fontSize, penWidth, bold, italic ).x ); + dx = font->StringBoundaryLimits( text, fontSize, penWidth, bold, italic ).x; textsize.x = std::max( textsize.x, dx ); textsize.y += dy; } @@ -561,6 +613,12 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const rect.Normalize(); // Make h and v sizes always >= 0 + if( aLine < 0 && !aInvertY ) + { + m_bounding_box_cache_valid = true; + m_bounding_box_cache = rect; + } + return rect; } @@ -797,25 +855,18 @@ std::shared_ptr EDA_TEXT::GetEffectiveTextShape( ) const { KIFONT::OUTLINE_GLYPH* glyph = static_cast( baseGlyph.get() ); - glyph->CacheTriangulation(); + glyph->Triangulate( + [&]( int aPolygonIndex, const VECTOR2D& aVertex1, const VECTOR2D& aVertex2, + const VECTOR2D& aVertex3 ) + { + SHAPE_SIMPLE* triShape = new SHAPE_SIMPLE; - for( unsigned int ii = 0; ii < glyph->TriangulatedPolyCount(); ++ii ) - { - const SHAPE_POLY_SET::TRIANGULATED_POLYGON* tri = glyph->TriangulatedPolygon( ii ); + triShape->Append( aVertex1 ); + triShape->Append( aVertex2 ); + triShape->Append( aVertex3 ); - for( size_t jj = 0; jj < tri->GetTriangleCount(); ++jj ) - { - VECTOR2I a, b, c; - tri->GetTriangle( jj, a, b, c ); - SHAPE_SIMPLE* triShape = new SHAPE_SIMPLE; - - triShape->Append( a ); - triShape->Append( b ); - triShape->Append( c ); - - shape->AddShape( triShape ); - } - } + shape->AddShape( triShape ); + } ); } } else diff --git a/common/font/font.cpp b/common/font/font.cpp index 5e86f0e453..30742586a9 100644 --- a/common/font/font.cpp +++ b/common/font/font.cpp @@ -104,72 +104,9 @@ bool FONT::IsStroke( const wxString& aFontName ) } -/** - * Draw a string. - * - * @param aGal - * @param aTextItem is the underlying text item - * @param aPosition is the text position - * @return bounding box width/height - */ -VECTOR2D FONT::doDrawString( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition, - bool aParse, const TEXT_ATTRIBUTES& aAttrs ) const -{ - if( aText.empty() ) - return VECTOR2D( 0.0, 0.0 ); - - wxArrayString strings; - std::vector positions; - VECTOR2D boundingBox; - std::vector lineBoundingBoxes; - - getLinePositions( aText, aPosition, strings, positions, lineBoundingBoxes, aAttrs ); - - for( size_t i = 0; i < strings.GetCount(); i++ ) - { - VECTOR2D lineBoundingBox; - - if( aParse ) - { - MARKUP::MARKUP_PARSER markupParser( std::string( strings.Item( i ) ) ); - //auto parse_result = markupParser.Parse(); - VECTOR2I cursor = positions[i]; - - std::function& )> nodeHandler = - [&]( const std::unique_ptr& aNode ) - { - if( !aNode->is_root() && aNode->has_content() ) - { - VECTOR2D itemBoundingBox = Draw( aGal, aNode->string(), cursor, - aPosition, aAttrs ); - lineBoundingBox += itemBoundingBox; - cursor += itemBoundingBox; - } - - for( const auto& child : aNode->children ) - nodeHandler( child ); - }; - - nodeHandler( markupParser.Parse() ); - } - else - { - lineBoundingBox = Draw( aGal, strings.Item( i ), positions[i], aPosition, aAttrs ); - } - - boundingBox.x = fmax( boundingBox.x, lineBoundingBox.x ); - } - - boundingBox.y = ( strings.GetCount() + 1 ) * GetInterline( aAttrs.m_Size.y ); - - return boundingBox; -} - - void FONT::getLinePositions( const UTF8& aText, const VECTOR2I& aPosition, wxArrayString& aTextLines, std::vector& aPositions, - std::vector& aBoundingBoxes, - const TEXT_ATTRIBUTES& aAttrs ) const + std::vector& aExtents, const TEXT_ATTRIBUTES& aAttrs ) const { wxStringSplit( aText, aTextLines, '\n' ); int lineCount = aTextLines.Count(); @@ -180,12 +117,12 @@ void FONT::getLinePositions( const UTF8& aText, const VECTOR2I& aPosition, for( int i = 0; i < lineCount; i++ ) { - VECTOR2D pos( aPosition.x, aPosition.y + i * interline ); - VECTOR2D end = boundingBoxSingleLine( nullptr, aTextLines[i], pos, aAttrs.m_Size, + VECTOR2I pos( aPosition.x, aPosition.y + i * interline ); + VECTOR2I end = boundingBoxSingleLine( nullptr, aTextLines[i], pos, aAttrs.m_Size, aAttrs.m_Italic ); - VECTOR2D bBox( end - pos ); + VECTOR2I bBox( end - pos ); - aBoundingBoxes.push_back( bBox ); + aExtents.push_back( bBox ); if( i == 0 ) height += aAttrs.m_Size.y; @@ -205,7 +142,7 @@ void FONT::getLinePositions( const UTF8& aText, const VECTOR2I& aPosition, for( int i = 0; i < lineCount; i++ ) { - VECTOR2I lineSize = aBoundingBoxes.at( i ); + VECTOR2I lineSize = aExtents.at( i ); wxPoint lineOffset( offset ); lineOffset.y += i * interline; @@ -247,46 +184,35 @@ void FONT::DrawText( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosit * object, such as a run of superscript characters) * @param aAttrs are the styling attributes of the text, including its rotation */ -VECTOR2D FONT::Draw( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition, - const VECTOR2I& aCursor, const TEXT_ATTRIBUTES& aAttrs ) const +void FONT::Draw( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition, + const VECTOR2I& aCursor, const TEXT_ATTRIBUTES& aAttrs ) const { if( !aGal || aText.empty() ) - return VECTOR2D( 0, 0 ); + return; - VECTOR2D position( aPosition - aCursor ); + VECTOR2I position( aPosition - aCursor ); // Split multiline strings into separate ones and draw them line by line wxArrayString strings_list; std::vector positions; - std::vector boundingBoxes; + std::vector extents; - getLinePositions( aText, position, strings_list, positions, boundingBoxes, aAttrs ); - - VECTOR2D boundingBox( 0, 0 ); - BOX2I lineBoundingBox; + getLinePositions( aText, position, strings_list, positions, extents, aAttrs ); aGal->SetLineWidth( aAttrs.m_StrokeWidth ); for( size_t i = 0; i < strings_list.GetCount(); i++ ) { - (void) drawSingleLineText( aGal, &lineBoundingBox, strings_list[i], positions[i], - aAttrs.m_Size, aAttrs.m_Angle, aAttrs.m_Mirrored, aPosition, - aAttrs.m_Italic ); - // expand bounding box of whole text - boundingBox.x = std::max( boundingBox.x, (double) lineBoundingBox.GetWidth() ); - - double lineHeight = GetInterline( aAttrs.m_Size.y, aAttrs.m_LineSpacing ); - boundingBox.y += lineHeight; + drawSingleLineText( aGal, nullptr, strings_list[i], positions[i], aAttrs.m_Size, + aAttrs.m_Angle, aAttrs.m_Mirrored, aPosition, aAttrs.m_Italic ); } - - return boundingBox; } /** * @return position of cursor for drawing next substring */ -VECTOR2D drawMarkup( BOX2I* aBoundingBox, std::vector>& aGlyphs, +VECTOR2I drawMarkup( BOX2I* aBoundingBox, std::vector>* aGlyphs, const std::unique_ptr& aNode, const VECTOR2I& aPosition, const KIFONT::FONT* aFont, const VECTOR2D& aSize, const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin, TEXT_STYLE_FLAGS aTextStyle ) @@ -328,7 +254,7 @@ VECTOR2D drawMarkup( BOX2I* aBoundingBox, std::vector>& a } -VECTOR2D FONT::drawMarkup( BOX2I* aBoundingBox, std::vector>& aGlyphs, +VECTOR2I FONT::drawMarkup( BOX2I* aBoundingBox, std::vector>* aGlyphs, const UTF8& aText, const VECTOR2I& aPosition, const VECTOR2D& aSize, const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin, TEXT_STYLE_FLAGS aTextStyle ) const @@ -341,16 +267,13 @@ VECTOR2D FONT::drawMarkup( BOX2I* aBoundingBox, std::vector> glyphs; - VECTOR2D nextPosition = drawMarkup( aBoundingBox, glyphs, aText, aPosition, aSize, aAngle, - aMirror, aOrigin, textStyle ); + + (void) drawMarkup( aBoundingBox, &glyphs, aText, aPosition, aSize, aAngle, aMirror, aOrigin, + textStyle ); for( const std::unique_ptr& glyph : glyphs ) aGal->DrawGlyph( *glyph.get() ); - - return nextPosition; } -VECTOR2D FONT::StringBoundaryLimits( const UTF8& aText, const VECTOR2D& aSize, int aThickness, +VECTOR2I FONT::StringBoundaryLimits( const UTF8& aText, const VECTOR2D& aSize, int aThickness, bool aBold, bool aItalic ) const { // TODO do we need to parse every time - have we already parsed? - std::vector> glyphs; // ignored - BOX2I boundingBox; - TEXT_STYLE_FLAGS textStyle = 0; + BOX2I boundingBox; + TEXT_STYLE_FLAGS textStyle = 0; if( aBold ) textStyle |= TEXT_STYLE::BOLD; @@ -382,8 +303,8 @@ VECTOR2D FONT::StringBoundaryLimits( const UTF8& aText, const VECTOR2D& aSize, i if( aItalic ) textStyle |= TEXT_STYLE::ITALIC; - (void) drawMarkup( &boundingBox, glyphs, aText, VECTOR2D(), aSize, EDA_ANGLE::ANGLE_0, - false, VECTOR2D(), textStyle ); + (void) drawMarkup( &boundingBox, nullptr, aText, VECTOR2I(), aSize, EDA_ANGLE::ANGLE_0, false, + VECTOR2I(), textStyle ); if( IsStroke() ) { @@ -399,18 +320,16 @@ VECTOR2D FONT::StringBoundaryLimits( const UTF8& aText, const VECTOR2D& aSize, i } -VECTOR2D FONT::boundingBoxSingleLine( BOX2I* aBoundingBox, const UTF8& aText, - const VECTOR2I& aPosition, const VECTOR2D& aSize, - bool aItalic ) const +VECTOR2I FONT::boundingBoxSingleLine( BOX2I* aBBox, const UTF8& aText, const VECTOR2I& aPosition, + const VECTOR2D& aSize, bool aItalic ) const { TEXT_STYLE_FLAGS textStyle = 0; if( aItalic ) textStyle |= TEXT_STYLE::ITALIC; - std::vector> glyphs; // ignored - VECTOR2D nextPosition = drawMarkup( aBoundingBox, glyphs, aText, aPosition, aSize, - EDA_ANGLE::ANGLE_0, false, VECTOR2I(), textStyle ); + VECTOR2I extents = drawMarkup( aBBox, nullptr, aText, aPosition, aSize, EDA_ANGLE::ANGLE_0, + false, VECTOR2I(), textStyle ); - return nextPosition; + return extents; } diff --git a/common/font/glyph.cpp b/common/font/glyph.cpp index 59f7a37a59..546f041944 100644 --- a/common/font/glyph.cpp +++ b/common/font/glyph.cpp @@ -108,3 +108,23 @@ BOX2D OUTLINE_GLYPH::BoundingBox() BOX2I bbox = BBox(); return BOX2D( bbox.GetOrigin(), bbox.GetSize() ); } + + +void OUTLINE_GLYPH::Triangulate( TRIANGULATE_CALLBACK aCallback ) const +{ + const_cast( this )->CacheTriangulation(); + + for( unsigned int i = 0; i < TriangulatedPolyCount(); i++ ) + { + const SHAPE_POLY_SET::TRIANGULATED_POLYGON* polygon = TriangulatedPolygon( i ); + + for ( size_t j = 0; j < polygon->GetTriangleCount(); j++ ) + { + VECTOR2I a, b, c; + polygon->GetTriangle( j, a, b, c ); + aCallback( i, a, b, c ); + } + } +} + + diff --git a/common/font/outline_font.cpp b/common/font/outline_font.cpp index 79c5b97614..8b51f99b48 100644 --- a/common/font/outline_font.cpp +++ b/common/font/outline_font.cpp @@ -227,35 +227,43 @@ BOX2I OUTLINE_FONT::getBoundingBox( const std::vector>& a } -VECTOR2I OUTLINE_FONT::GetLinesAsGlyphs( std::vector>& aGlyphs, - const EDA_TEXT* aText ) const +void OUTLINE_FONT::GetLinesAsGlyphs( std::vector>* aGlyphs, + const EDA_TEXT* aText ) const { wxArrayString strings; std::vector positions; - VECTOR2I ret; - std::vector boundingBoxes; + std::vector extents; TEXT_ATTRIBUTES attrs = aText->GetAttributes(); - TEXT_STYLE_FLAGS textStyle = 0; attrs.m_Angle = aText->GetDrawRotation(); - if( aText->IsItalic() ) - textStyle |= TEXT_STYLE::ITALIC; - - getLinePositions( aText->GetShownText(), aText->GetTextPos(), strings, positions, boundingBoxes, - attrs ); - - for( size_t i = 0; i < strings.GetCount(); i++ ) - { - ret = drawMarkup( nullptr, aGlyphs, UTF8( strings.Item( i ) ), positions[i], attrs.m_Size, - attrs.m_Angle, attrs.m_Mirrored, aText->GetTextPos(), textStyle ); - } - - return ret; + return GetLinesAsGlyphs( aGlyphs, aText->GetShownText(), aText->GetTextPos(), attrs ); } -VECTOR2I OUTLINE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector>& aGlyphs, +void OUTLINE_FONT::GetLinesAsGlyphs( std::vector>* aGlyphs, + const UTF8& aText, const VECTOR2I& aPosition, + const TEXT_ATTRIBUTES& aAttrs ) const +{ + wxArrayString strings; + std::vector positions; + std::vector extents; + TEXT_STYLE_FLAGS textStyle = 0; + + if( aAttrs.m_Italic ) + textStyle |= TEXT_STYLE::ITALIC; + + getLinePositions( aText, aPosition, strings, positions, extents, aAttrs ); + + for( size_t i = 0; i < strings.GetCount(); i++ ) + { + (void) drawMarkup( nullptr, aGlyphs, UTF8( strings.Item( i ) ), positions[i], + aAttrs.m_Size, aAttrs.m_Angle, aAttrs.m_Mirrored, aPosition, textStyle ); + } +} + + +VECTOR2I OUTLINE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector>* aGlyphs, const UTF8& aText, const VECTOR2D& aSize, const VECTOR2I& aPosition, const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin, @@ -294,104 +302,88 @@ VECTOR2I OUTLINE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vectorglyph; - - // 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 ); - decomposer.OutlineToSegments( &contours ); - - std::unique_ptr glyph = std::make_unique(); - std::vector holes; - std::vector outlines; - - for( CONTOUR& c : contours ) + if( aGlyphs ) { - GLYPH_POINTS points = c.points; - SHAPE_LINE_CHAIN shape; + FT_Load_Glyph( face, codepoint, FT_LOAD_NO_BITMAP ); - for( const VECTOR2D& v : points ) + FT_GlyphSlot faceGlyph = face->glyph; + + // 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 ); + decomposer.OutlineToSegments( &contours ); + + std::unique_ptr glyph = std::make_unique(); + std::vector holes; + + for( CONTOUR& c : contours ) { - VECTOR2D pt( v + cursor ); + GLYPH_POINTS points = c.points; + SHAPE_LINE_CHAIN shape; - topLeft.x = std::min( topLeft.x, pt.x ); - topLeft.y = std::max( topLeft.y, pt.y ); - topRight.x = std::max( topRight.x, pt.x ); - topRight.y = std::max( topRight.y, pt.y ); - - if( IsSubscript( aTextStyle ) ) - pt.y -= 0.25 * scaler; - else if( IsSuperscript( aTextStyle ) ) - pt.y += 0.45 * scaler; - - pt *= scaleFactor; - pt += aPosition; - - if( aMirror ) - pt.x = aOrigin.x - ( pt.x - aOrigin.x ); - - if( !aAngle.IsZero() ) - RotatePoint( pt, aOrigin, aAngle ); - - shape.Append( pt.x, pt.y ); - } - - shape.SetClosed( true ); - - if( contourIsHole( c ) ) - holes.push_back( std::move( shape ) ); - else - outlines.push_back( std::move( shape ) ); - } - - for( SHAPE_LINE_CHAIN& outline : outlines ) - { - if( outline.PointCount() ) - glyph->AddOutline( outline ); - } - - int nthHole = 0; - - for( SHAPE_LINE_CHAIN& hole : holes ) - { - if( hole.PointCount() ) - { - VECTOR2I firstPoint = hole.GetPoint( 0 ); - int nthOutline = -1; - int n = 0; - - for( SHAPE_LINE_CHAIN& outline : outlines ) + for( const VECTOR2D& v : points ) { - if( outline.PointInside( firstPoint ) ) - { - nthOutline = n; - break; - } + VECTOR2D pt( v + cursor ); - n++; + topLeft.x = std::min( topLeft.x, pt.x ); + topLeft.y = std::max( topLeft.y, pt.y ); + topRight.x = std::max( topRight.x, pt.x ); + topRight.y = std::max( topRight.y, pt.y ); + + if( IsSubscript( aTextStyle ) ) + pt.y -= 0.25 * scaler; + else if( IsSuperscript( aTextStyle ) ) + pt.y += 0.45 * scaler; + + pt *= scaleFactor; + pt += aPosition; + + if( aMirror ) + pt.x = aOrigin.x - ( pt.x - aOrigin.x ); + + if( !aAngle.IsZero() ) + RotatePoint( pt, aOrigin, aAngle ); + + shape.Append( pt.x, pt.y ); } - if( nthOutline > -1 ) - glyph->AddHole( hole, n ); + shape.SetClosed( true ); + + if( contourIsHole( c ) ) + holes.push_back( std::move( shape ) ); + else + glyph->AddOutline( std::move( shape ) ); } - nthHole++; - } + for( SHAPE_LINE_CHAIN& hole : holes ) + { + if( hole.PointCount() ) + { + for( int ii = 0; ii < glyph->OutlineCount(); ++ii ) + { + if( glyph->Outline( ii ).PointInside( hole.GetPoint( 0 ) ) ) + { + glyph->AddHole( std::move( hole ), ii ); + break; + } + } + } + } - aGlyphs.push_back( std::move( glyph ) ); + if( glyph->HasHoles() ) + 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; } - VECTOR2I cursorEnd( cursor ); - - if( IsOverbar( aTextStyle ) ) + if( IsOverbar( aTextStyle ) && aGlyphs ) { topLeft *= scaleFactor; topRight *= scaleFactor; @@ -415,12 +407,12 @@ VECTOR2I OUTLINE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector overbarGlyph = std::make_unique( overbar ); - aGlyphs.push_back( std::move( overbarGlyph ) ); + aGlyphs->push_back( std::move( overbarGlyph ) ); } hb_buffer_destroy( buf ); - VECTOR2I cursorDisplacement( cursorEnd.x * scaleFactor.x, -cursorEnd.y * scaleFactor.y ); + VECTOR2I cursorDisplacement( cursor.x * scaleFactor.x, -cursor.y * scaleFactor.y ); if( aBBox ) { diff --git a/common/font/stroke_font.cpp b/common/font/stroke_font.cpp index aa856d8067..bb89eb714e 100644 --- a/common/font/stroke_font.cpp +++ b/common/font/stroke_font.cpp @@ -195,7 +195,7 @@ double STROKE_FONT::ComputeOverbarVerticalPosition( double aGlyphHeight ) const } -VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector>& aGlyphs, +VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector>* aGlyphs, const UTF8& aText, const VECTOR2D& aSize, const VECTOR2I& aPosition, const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin, @@ -252,10 +252,20 @@ VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector( m_glyphs->at( dd ).get() ); - aGlyphs.push_back( source->Transform( glyphSize, cursor, tilt, aAngle, aMirror, - aOrigin ) ); + if( aGlyphs ) + { + aGlyphs->push_back( source->Transform( glyphSize, cursor, tilt, aAngle, aMirror, + aOrigin ) ); + } - cursor.x = aGlyphs.back()->BoundingBox().GetEnd().x; + VECTOR2D glyphExtents = source->BoundingBox().GetEnd(); + + glyphExtents *= glyphSize; + + if( tilt ) + glyphExtents.x -= glyphExtents.y * tilt; + + cursor.x += glyphExtents.x; } } @@ -263,8 +273,6 @@ VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector overbarGlyph = std::make_unique(); - barOffset.y = ComputeOverbarVerticalPosition( glyphSize.y ); if( aTextStyle & TEXT_STYLE::ITALIC ) @@ -279,11 +287,16 @@ VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vectorAddPoint( barStart ); - overbarGlyph->AddPoint( barEnd ); - overbarGlyph->Finalize(); + if( aGlyphs ) + { + std::unique_ptr overbarGlyph = std::make_unique(); - aGlyphs.push_back( std::move( overbarGlyph ) ); + overbarGlyph->AddPoint( barStart ); + overbarGlyph->AddPoint( barEnd ); + overbarGlyph->Finalize(); + + aGlyphs->push_back( std::move( overbarGlyph ) ); + } } if( aBBox ) diff --git a/common/font/triangulate.cpp b/common/font/triangulate.cpp deleted file mode 100644 index 49441c502f..0000000000 --- a/common/font/triangulate.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2021 Ola Rinta-Koski - * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include -#include - -void Triangulate( const SHAPE_POLY_SET& aPolylist, TRIANGULATE_CALLBACK aCallback, - void* aCallbackData ) -{ - SHAPE_POLY_SET polys( aPolylist ); - - polys.Fracture( SHAPE_POLY_SET::PM_FAST ); // TODO verify aFastMode - polys.CacheTriangulation(); - - for( unsigned int i = 0; i < polys.TriangulatedPolyCount(); i++ ) - { - const SHAPE_POLY_SET::TRIANGULATED_POLYGON* polygon = polys.TriangulatedPolygon( i ); - for ( size_t j = 0; j < polygon->GetTriangleCount(); j++ ) - { - VECTOR2I a; - VECTOR2I b; - VECTOR2I c; - - polygon->GetTriangle( j, a, b, c ); - aCallback( i, a, b, c, aCallbackData ); - } - } -} - - diff --git a/common/gal/cairo/cairo_gal.cpp b/common/gal/cairo/cairo_gal.cpp index 4e6703b768..ca2874686e 100644 --- a/common/gal/cairo/cairo_gal.cpp +++ b/common/gal/cairo/cairo_gal.cpp @@ -1786,44 +1786,44 @@ void CAIRO_GAL_BASE::DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth, int aTota // eventually glyphs should not be drawn as polygons at all, // but as bitmaps with antialiasing, this is just a stopgap measure // of getting some form of outline font display - auto triangleCallback = [&]( int aPolygonIndex, const VECTOR2D& aVertex1, - const VECTOR2D& aVertex2, const VECTOR2D& aVertex3, - void* aCallbackData ) - { - #if 1 - syncLineWidth(); + auto triangleCallback = + [&]( int aPolygonIndex, const VECTOR2D& aVertex1, const VECTOR2D& aVertex2, + const VECTOR2D& aVertex3, void* aCallbackData ) + { +#if 1 + syncLineWidth(); - const auto p0 = roundp( xform( aVertex1 ) ); - const auto p1 = roundp( xform( aVertex2 ) ); - const auto p2 = roundp( xform( aVertex3 ) ); + const auto p0 = roundp( xform( aVertex1 ) ); + const auto p1 = roundp( xform( aVertex2 ) ); + const auto p2 = roundp( xform( aVertex3 ) ); - /* - cairo_move_to( currentContext, aVertex1.x, aVertex1.y ); - cairo_line_to( currentContext, aVertex2.x, aVertex2.y ); - cairo_line_to( currentContext, aVertex3.x, aVertex3.y ); - cairo_line_to( currentContext, aVertex1.x, aVertex1.y ); - */ - cairo_move_to( m_currentContext, p0.x, p0.y ); - cairo_line_to( m_currentContext, p1.x, p1.y ); - cairo_line_to( m_currentContext, p2.x, p2.y ); - cairo_close_path( m_currentContext ); - /* - setSourceRgba( currentContext, fillColor ); - SetIsFill( true ); - cairo_set_fill_rule( currentContext, CAIRO_FILL_RULE_EVEN_ODD ); - flushPath(); - */ - //cairo_fill( currentContext ); - #else - // just a silly test - /* - DrawRectangle(aVertex1, aVertex2); - DrawRectangle(aVertex2, aVertex3); - DrawRectangle(aVertex3, aVertex1); - */ - DrawTriangle( aVertex1, aVertex2, aVertex3 ); - #endif - }; + /* + cairo_move_to( currentContext, aVertex1.x, aVertex1.y ); + cairo_line_to( currentContext, aVertex2.x, aVertex2.y ); + cairo_line_to( currentContext, aVertex3.x, aVertex3.y ); + cairo_line_to( currentContext, aVertex1.x, aVertex1.y ); + */ + cairo_move_to( m_currentContext, p0.x, p0.y ); + cairo_line_to( m_currentContext, p1.x, p1.y ); + cairo_line_to( m_currentContext, p2.x, p2.y ); + cairo_close_path( m_currentContext ); + /* + setSourceRgba( currentContext, fillColor ); + SetIsFill( true ); + cairo_set_fill_rule( currentContext, CAIRO_FILL_RULE_EVEN_ODD ); + flushPath(); + */ + //cairo_fill( currentContext ); +#else + // just a silly test + /* + DrawRectangle(aVertex1, aVertex2); + DrawRectangle(aVertex2, aVertex3); + DrawRectangle(aVertex3, aVertex1); + */ + DrawTriangle( aVertex1, aVertex2, aVertex3 ); +#endif + }; Triangulate( aGlyph, triangleCallback ); diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index 40c35d8b9d..fbdf4076b6 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -44,7 +44,6 @@ #include #include // for KiROUND #include -#include #include @@ -2425,24 +2424,16 @@ void OPENGL_GAL::DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth, int aTotal ) { const auto& outlineGlyph = static_cast( aGlyph ); - fillPolygonAsTriangles( outlineGlyph ); + m_currentManager->Shader( SHADER_NONE ); + m_currentManager->Color( m_fillColor ); + + outlineGlyph.Triangulate( + [&]( int aPolygonIndex, const VECTOR2D& aVertex1, const VECTOR2D& aVertex2, + const VECTOR2D& aVertex3 ) + { + m_currentManager->Vertex( aVertex1.x, aVertex1.y, m_layerDepth ); + m_currentManager->Vertex( aVertex2.x, aVertex2.y, m_layerDepth ); + m_currentManager->Vertex( aVertex3.x, aVertex3.y, m_layerDepth ); + } ); } } - - -void OPENGL_GAL::fillPolygonAsTriangles( const SHAPE_POLY_SET& aPolyList ) -{ - m_currentManager->Shader( SHADER_NONE ); - m_currentManager->Color( m_fillColor ); - - auto triangleCallback = [&]( int aPolygonIndex, const VECTOR2D& aVertex1, - const VECTOR2D& aVertex2, const VECTOR2D& aVertex3, - void* aCallbackData ) - { - m_currentManager->Vertex( aVertex1.x, aVertex1.y, m_layerDepth ); - m_currentManager->Vertex( aVertex2.x, aVertex2.y, m_layerDepth ); - m_currentManager->Vertex( aVertex3.x, aVertex3.y, m_layerDepth ); - }; - - Triangulate( aPolyList, triangleCallback ); -} diff --git a/eeschema/lib_pin.cpp b/eeschema/lib_pin.cpp index 10c41e707e..6af6a932f4 100644 --- a/eeschema/lib_pin.cpp +++ b/eeschema/lib_pin.cpp @@ -1118,10 +1118,10 @@ const EDA_RECT LIB_PIN::GetBoundingBox( bool aIncludeInvisibles, bool aPinOnly ) if( showNum ) { VECTOR2D fontSize( m_numTextSize, m_numTextSize ); - VECTOR2D numSize = font->StringBoundaryLimits( number, fontSize, penWidth, false, false ); + VECTOR2I numSize = font->StringBoundaryLimits( number, fontSize, penWidth, false, false ); - numberTextLength = KiROUND( numSize.x ); - numberTextHeight = KiROUND( numSize.y ); + numberTextLength = numSize.x; + numberTextHeight = numSize.y; } if( m_shape == GRAPHIC_PINSHAPE::INVERTED || m_shape == GRAPHIC_PINSHAPE::INVERTED_CLOCK ) @@ -1136,10 +1136,10 @@ const EDA_RECT LIB_PIN::GetBoundingBox( bool aIncludeInvisibles, bool aPinOnly ) if( showName ) { VECTOR2D fontSize( m_nameTextSize, m_nameTextSize ); - VECTOR2D nameSize = font->StringBoundaryLimits( name, fontSize, penWidth, false, false ); + VECTOR2I nameSize = font->StringBoundaryLimits( name, fontSize, penWidth, false, false ); - nameTextLength = KiROUND( nameSize.x ) + nameTextOffset; - nameTextHeight = KiROUND( nameSize.y ) + Mils2iu( PIN_TEXT_MARGIN ); + nameTextLength = nameSize.x + nameTextOffset; + nameTextHeight = nameSize.y + Mils2iu( PIN_TEXT_MARGIN ); } if( nameTextOffset ) // for values > 0, pin name is inside the body diff --git a/eeschema/lib_symbol.cpp b/eeschema/lib_symbol.cpp index 2ff0cdf4bd..7862364f2e 100644 --- a/eeschema/lib_symbol.cpp +++ b/eeschema/lib_symbol.cpp @@ -432,6 +432,19 @@ std::unique_ptr< LIB_SYMBOL > LIB_SYMBOL::Flatten() const } +void LIB_SYMBOL::ClearCaches() +{ + for( LIB_ITEM& item : m_drawings ) + { + if( EDA_TEXT* eda_text = dynamic_cast( &item ) ) + { + eda_text->ClearBoundingBoxCache(); + eda_text->ClearRenderCache(); + } + } +} + + const wxString LIB_SYMBOL::GetLibraryName() const { if( m_library ) diff --git a/eeschema/lib_symbol.h b/eeschema/lib_symbol.h index eb02212f88..5c353bb38b 100644 --- a/eeschema/lib_symbol.h +++ b/eeschema/lib_symbol.h @@ -126,6 +126,8 @@ public: LIB_SYMBOL_REF& GetParent() { return m_parent; } const LIB_SYMBOL_REF& GetParent() const { return m_parent; } + void ClearCaches(); + virtual wxString GetClass() const override { return wxT( "LIB_SYMBOL" ); diff --git a/eeschema/sch_base_frame.h b/eeschema/sch_base_frame.h index 385bb79037..bf22c1ab6f 100644 --- a/eeschema/sch_base_frame.h +++ b/eeschema/sch_base_frame.h @@ -213,7 +213,8 @@ public: /** * Mark an item for refresh. */ - void UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete = false, bool aUpdateRtree = false ); + virtual void UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete = false, + bool aUpdateRtree = false ); /** * Mark selected items for refresh. diff --git a/eeschema/sch_edit_frame.cpp b/eeschema/sch_edit_frame.cpp index 689ea75a72..e58495b014 100644 --- a/eeschema/sch_edit_frame.cpp +++ b/eeschema/sch_edit_frame.cpp @@ -649,6 +649,14 @@ void SCH_EDIT_FRAME::SetCurrentSheet( const SCH_SHEET_PATH& aSheet ) void SCH_EDIT_FRAME::HardRedraw() { + SCH_SCREEN* screen = GetCurrentSheet().LastScreen(); + + for( SCH_ITEM* item : screen->Items() ) + item->ClearCaches(); + + for( std::pair& libSymbol : screen->GetLibSymbols() ) + libSymbol.second->ClearCaches(); + RecalculateConnections( LOCAL_CLEANUP ); FocusOnItem( nullptr ); @@ -1752,3 +1760,12 @@ void SCH_EDIT_FRAME::SaveSymbolToSchematic( const LIB_SYMBOL& aSymbol, GetCanvas()->Refresh(); OnModify(); } + + +void SCH_EDIT_FRAME::UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete, bool aUpdateRtree ) +{ + SCH_BASE_FRAME::UpdateItem( aItem, isAddOrDelete, aUpdateRtree ); + + if( SCH_ITEM* sch_item = dynamic_cast( aItem ) ) + sch_item->ClearCaches(); +} \ No newline at end of file diff --git a/eeschema/sch_edit_frame.h b/eeschema/sch_edit_frame.h index 04247cc9c3..9a7d586ddc 100644 --- a/eeschema/sch_edit_frame.h +++ b/eeschema/sch_edit_frame.h @@ -429,6 +429,9 @@ public: void SetCurrentSheet( const SCH_SHEET_PATH& aSheet ); + void UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete = false, + bool aUpdateRtree = false ) override; + /** * Rebuild the GAL and redraw the screen. Call when something went wrong. */ diff --git a/eeschema/sch_field.cpp b/eeschema/sch_field.cpp index 46bed51079..b6c070e406 100644 --- a/eeschema/sch_field.cpp +++ b/eeschema/sch_field.cpp @@ -52,13 +52,16 @@ #include #include #include +#include + SCH_FIELD::SCH_FIELD( const VECTOR2I& aPos, int aFieldId, SCH_ITEM* aParent, const wxString& aName ) : SCH_ITEM( aParent, SCH_FIELD_T ), EDA_TEXT( wxEmptyString ), m_id( 0 ), - m_name( aName ) + m_name( aName ), + m_renderCacheValid( false ) { SetTextPos( aPos ); SetId( aFieldId ); // will also set the layer @@ -66,11 +69,53 @@ SCH_FIELD::SCH_FIELD( const VECTOR2I& aPos, int aFieldId, SCH_ITEM* aParent, } +SCH_FIELD::SCH_FIELD( const SCH_FIELD& aField ) : + SCH_ITEM( aField ), + EDA_TEXT( aField ) +{ + m_id = aField.m_id; + m_name = aField.m_name; + + m_renderCache.clear(); + + for( const std::unique_ptr& glyph : aField.m_renderCache ) + { + KIFONT::OUTLINE_GLYPH* outline_glyph = static_cast( glyph.get() ); + m_renderCache.emplace_back( std::make_unique( *outline_glyph ) ); + } + + m_renderCacheValid = aField.m_renderCacheValid; + m_renderCachePos = aField.m_renderCachePos; +} + + SCH_FIELD::~SCH_FIELD() { } +SCH_FIELD& SCH_FIELD::operator=( const SCH_FIELD& aField ) +{ + EDA_TEXT::operator=( aField ); + + m_id = aField.m_id; + m_name = aField.m_name; + + m_renderCache.clear(); + + for( const std::unique_ptr& glyph : aField.m_renderCache ) + { + KIFONT::OUTLINE_GLYPH* outline_glyph = static_cast( glyph.get() ); + m_renderCache.emplace_back( std::make_unique( *outline_glyph ) ); + } + + m_renderCacheValid = aField.m_renderCacheValid; + m_renderCachePos = aField.m_renderCachePos; + + return *this; +} + + EDA_ITEM* SCH_FIELD::Clone() const { return new SCH_FIELD( *this ); @@ -226,6 +271,54 @@ KIFONT::FONT* SCH_FIELD::GetDrawFont() const } +void SCH_FIELD::ClearCaches() +{ + ClearRenderCache(); + EDA_TEXT::ClearBoundingBoxCache(); +} + + +void SCH_FIELD::ClearRenderCache() +{ + EDA_TEXT::ClearRenderCache(); + m_renderCacheValid = false; +} + + +std::vector>* +SCH_FIELD::GetRenderCache( const wxString& forResolvedText, const VECTOR2I& forPosition, + TEXT_ATTRIBUTES& aAttrs ) const +{ + if( GetDrawFont()->IsOutline() ) + { + if( m_renderCache.empty() || !m_renderCacheValid ) + { + m_renderCache.clear(); + + KIFONT::OUTLINE_FONT* font = static_cast( GetDrawFont() ); + font->GetLinesAsGlyphs( &m_renderCache, forResolvedText, forPosition, aAttrs ); + + m_renderCachePos = forPosition; + m_renderCacheValid = true; + } + + if( m_renderCachePos != forPosition ) + { + VECTOR2I delta = forPosition - m_renderCachePos; + + for( std::unique_ptr& glyph : m_renderCache ) + static_cast( glyph.get() )->Move( delta ); + + m_renderCachePos = forPosition; + } + + return &m_renderCache; + } + + return nullptr; +} + + void SCH_FIELD::Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset ) { wxDC* DC = aSettings->GetPrintDC(); diff --git a/eeschema/sch_field.h b/eeschema/sch_field.h index 6e63b38f9b..02dac77dfd 100644 --- a/eeschema/sch_field.h +++ b/eeschema/sch_field.h @@ -52,10 +52,12 @@ public: SCH_FIELD( const VECTOR2I& aPos, int aFieldId, SCH_ITEM* aParent, const wxString& aName = wxEmptyString ); - // Do not create a copy constructor. The one generated by the compiler is adequate. + SCH_FIELD( const SCH_FIELD& aText ); ~SCH_FIELD(); + SCH_FIELD& operator=( const SCH_FIELD& aField ); + static inline bool ClassOf( const EDA_ITEM* aItem ) { return aItem && SCH_FIELD_T == aItem->Type(); @@ -156,6 +158,13 @@ public: KIFONT::FONT* GetDrawFont() const override; + void ClearCaches() override; + void ClearRenderCache() override; + + std::vector>* + GetRenderCache( const wxString& forResolvedText, const VECTOR2I& forPosition, + TEXT_ATTRIBUTES& aAttrs ) const; + void Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset ) override; void Move( const VECTOR2I& aMoveVector ) override @@ -222,6 +231,10 @@ private: int m_id; ///< Field index, @see enum MANDATORY_FIELD_T wxString m_name; + + mutable bool m_renderCacheValid; + mutable VECTOR2I m_renderCachePos; + mutable std::vector> m_renderCache; }; diff --git a/eeschema/sch_item.cpp b/eeschema/sch_item.cpp index 7333a19b3a..f5556c86e7 100644 --- a/eeschema/sch_item.cpp +++ b/eeschema/sch_item.cpp @@ -230,6 +230,26 @@ void SCH_ITEM::SwapData( SCH_ITEM* aItem ) } +void SCH_ITEM::ClearCaches() +{ + auto clearTextCaches = + []( SCH_ITEM* aItem ) + { + EDA_TEXT* text = dynamic_cast( aItem ); + + if( text ) + { + text->ClearBoundingBoxCache(); + text->ClearRenderCache(); + } + }; + + clearTextCaches( this ); + + RunOnChildren( clearTextCaches ); +} + + bool SCH_ITEM::operator < ( const SCH_ITEM& aItem ) const { if( Type() != aItem.Type() ) diff --git a/eeschema/sch_item.h b/eeschema/sch_item.h index ac75ef5329..b3a23aaafe 100644 --- a/eeschema/sch_item.h +++ b/eeschema/sch_item.h @@ -429,6 +429,8 @@ public: virtual void RunOnChildren( const std::function& aFunction ) { } + virtual void ClearCaches(); + /** * Check if this schematic item has line stoke properties. * diff --git a/eeschema/sch_painter.cpp b/eeschema/sch_painter.cpp index 6f0d03137c..cd2fd00365 100644 --- a/eeschema/sch_painter.cpp +++ b/eeschema/sch_painter.cpp @@ -464,7 +464,7 @@ void SCH_PAINTER::boxText( const wxString& aText, const VECTOR2D& aPosition, aAttrs.m_Italic ); } - VECTOR2D extents = font->StringBoundaryLimits( aText, aAttrs.m_Size, aAttrs.m_StrokeWidth, + VECTOR2I extents = font->StringBoundaryLimits( aText, aAttrs.m_Size, aAttrs.m_StrokeWidth, aAttrs.m_Bold, aAttrs.m_Italic ); EDA_RECT box( (VECTOR2I) aPosition, wxSize( extents.x, aAttrs.m_Size.y ) ); @@ -718,11 +718,10 @@ void SCH_PAINTER::draw( const LIB_FIELD *aField, int aLayer ) if( drawingShadows && eeconfig()->m_Selection.text_as_box ) { - bbox.RevertYAxis(); m_gal->SetIsStroke( true ); m_gal->SetIsFill( true ); m_gal->SetLineWidth( getTextThickness( aField, drawingShadows ) ); - m_gal->DrawRectangle( mapCoords( bbox.GetPosition() ), mapCoords( bbox.GetEnd() ) ); + m_gal->DrawRectangle( bbox.GetPosition(), bbox.GetEnd() ); } else { @@ -765,18 +764,27 @@ void SCH_PAINTER::draw( const LIB_TEXT *aText, int aLayer ) } EDA_RECT bBox = aText->GetBoundingBox(); - bBox.RevertYAxis(); - VECTOR2D pos = mapCoords( bBox.Centre() ); + VECTOR2D pos = bBox.Centre(); m_gal->SetFillColor( color ); m_gal->SetStrokeColor( color ); - TEXT_ATTRIBUTES attrs( aText->GetAttributes() ); - attrs.m_Halign = GR_TEXT_H_ALIGN_CENTER; - attrs.m_Valign = GR_TEXT_V_ALIGN_CENTER; - attrs.m_StrokeWidth = getTextThickness( aText, drawingShadows ); + if( drawingShadows && eeconfig()->m_Selection.text_as_box ) + { + m_gal->SetIsStroke( true ); + m_gal->SetIsFill( true ); + m_gal->SetLineWidth( getTextThickness( aText, drawingShadows ) ); + m_gal->DrawRectangle( bBox.GetPosition(), bBox.GetEnd() ); + } + else + { + TEXT_ATTRIBUTES attrs( aText->GetAttributes() ); + attrs.m_Halign = GR_TEXT_H_ALIGN_CENTER; + attrs.m_Valign = GR_TEXT_V_ALIGN_CENTER; + attrs.m_StrokeWidth = getTextThickness( aText, drawingShadows ); - strokeText( aText->GetText(), pos, attrs ); + strokeText( aText->GetText(), pos, attrs ); + } } @@ -1477,7 +1485,6 @@ void SCH_PAINTER::draw( const SCH_TEXT *aText, int aLayer ) if( drawingShadows && eeconfig()->m_Selection.text_as_box ) { EDA_RECT bBox = aText->GetBoundingBox(); - bBox.Offset( text_offset.x, text_offset.y ); bBox.RevertYAxis(); m_gal->SetIsStroke( true ); m_gal->SetIsFill( true ); @@ -1503,7 +1510,7 @@ void SCH_PAINTER::draw( const SCH_TEXT *aText, int aLayer ) } else { - strokeText( shownText, aText->GetTextPos(), attrs ); + strokeText( shownText, aText->GetTextPos() + text_offset, attrs ); } } } @@ -1705,13 +1712,27 @@ void SCH_PAINTER::draw( const SCH_FIELD *aField, int aLayer ) } else { + wxString shownText = aField->GetShownText(); TEXT_ATTRIBUTES attributes = aField->GetAttributes(); + attributes.m_Halign = GR_TEXT_H_ALIGN_CENTER; attributes.m_Valign = GR_TEXT_V_ALIGN_CENTER; attributes.m_StrokeWidth = getTextThickness( aField, drawingShadows ); attributes.m_Angle = orient; - strokeText( aField->GetShownText(), textpos, attributes ); + std::vector>* cache = nullptr; + + cache = aField->GetRenderCache( shownText, textpos, attributes ); + + if( cache ) + { + for( const std::unique_ptr& glyph : *cache ) + m_gal->DrawGlyph( *glyph.get() ); + } + else + { + strokeText( shownText, textpos, attributes ); + } } // Draw the umbilical line diff --git a/eeschema/sch_text.cpp b/eeschema/sch_text.cpp index f8edbe46cd..2ea021755a 100644 --- a/eeschema/sch_text.cpp +++ b/eeschema/sch_text.cpp @@ -1049,7 +1049,10 @@ const EDA_RECT SCH_LABEL_BASE::GetBoundingBox() const EDA_RECT box( GetBodyBoundingBox() ); for( const SCH_FIELD& field : m_fields ) - box.Merge( field.GetBoundingBox() ); + { + if( field.IsVisible() ) + box.Merge( field.GetBoundingBox() ); + } box.Normalize(); diff --git a/eeschema/symbol_editor/symbol_edit_frame.cpp b/eeschema/symbol_editor/symbol_edit_frame.cpp index 7d54ca79aa..42794fbd4c 100644 --- a/eeschema/symbol_editor/symbol_edit_frame.cpp +++ b/eeschema/symbol_editor/symbol_edit_frame.cpp @@ -1165,6 +1165,8 @@ void SYMBOL_EDIT_FRAME::HardRedraw() else item.SetSelected(); } + + m_symbol->ClearCaches(); } RebuildView(); @@ -1482,3 +1484,15 @@ bool SYMBOL_EDIT_FRAME::IsSymbolEditable() const { return m_symbol && ( !IsSymbolFromLegacyLibrary() || IsSymbolFromSchematic() ); } + + +void SYMBOL_EDIT_FRAME::UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete, bool aUpdateRtree ) +{ + SCH_BASE_FRAME::UpdateItem( aItem, isAddOrDelete, aUpdateRtree ); + + if( EDA_TEXT* eda_text = dynamic_cast( aItem ) ) + { + eda_text->ClearBoundingBoxCache(); + eda_text->ClearRenderCache(); + } +} \ No newline at end of file diff --git a/eeschema/symbol_editor/symbol_edit_frame.h b/eeschema/symbol_editor/symbol_edit_frame.h index 756ef24c45..96bd1bde67 100644 --- a/eeschema/symbol_editor/symbol_edit_frame.h +++ b/eeschema/symbol_editor/symbol_edit_frame.h @@ -323,6 +323,9 @@ public: void RebuildView(); + void UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete = false, + bool aUpdateRtree = false ) override; + /** * Rebuild the GAL and redraw the screen. Call when something went wrong. */ diff --git a/include/eda_text.h b/include/eda_text.h index c351ff28c9..a6b7f0998d 100644 --- a/include/eda_text.h +++ b/include/eda_text.h @@ -342,7 +342,8 @@ public: virtual GR_TEXT_H_ALIGN_T GetDrawHorizJustify() const { return GetHorizJustify(); }; virtual GR_TEXT_V_ALIGN_T GetDrawVertJustify() const { return GetVertJustify(); }; - void ClearRenderCache() { m_render_cache.clear(); } + virtual void ClearRenderCache(); + virtual void ClearBoundingBoxCache(); std::vector>* GetRenderCache( const wxString& forResolvedText ) const; @@ -369,16 +370,19 @@ private: const COLOR4D& aColor, OUTLINE_MODE aFillMode, const wxString& aText, const VECTOR2I& aPos ); - wxString m_text; - wxString m_shown_text; // Cache of unescaped text for efficient access - bool m_shown_text_has_text_var_refs; + wxString m_text; + wxString m_shown_text; // Cache of unescaped text for efficient access + bool m_shown_text_has_text_var_refs; mutable wxString m_render_cache_text; mutable EDA_ANGLE m_render_cache_angle; mutable std::vector> m_render_cache; - TEXT_ATTRIBUTES m_attributes; - VECTOR2I m_pos; + mutable bool m_bounding_box_cache_valid; + mutable EDA_RECT m_bounding_box_cache; + + TEXT_ATTRIBUTES m_attributes; + VECTOR2I m_pos; }; diff --git a/include/font/font.h b/include/font/font.h index 2ede59f125..efcfe804de 100644 --- a/include/font/font.h +++ b/include/font/font.h @@ -122,15 +122,14 @@ public: * @param aCursor is the current text position (for multiple text blocks within a single text * object, such as a run of superscript characters) * @param aAttrs are the styling attributes of the text, including its rotation - * @return bounding box */ - VECTOR2D Draw( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition, - const VECTOR2I& aCursor, const TEXT_ATTRIBUTES& aAttrs ) const; + void Draw( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition, + const VECTOR2I& aCursor, const TEXT_ATTRIBUTES& aAttrs ) const; - VECTOR2D Draw( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition, - const TEXT_ATTRIBUTES& aAttributes ) const + void Draw( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition, + const TEXT_ATTRIBUTES& aAttributes ) const { - return Draw( aGal, aText, aPosition, VECTOR2I( 0, 0 ), aAttributes ); + Draw( aGal, aText, aPosition, VECTOR2I( 0, 0 ), aAttributes ); } virtual void DrawText( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition, @@ -141,7 +140,7 @@ public: * * @return a VECTOR2D giving the width and height of text. */ - VECTOR2D StringBoundaryLimits( const UTF8& aText, const VECTOR2D& aSize, int aThickness, + VECTOR2I StringBoundaryLimits( const UTF8& aText, const VECTOR2D& aSize, int aThickness, bool aBold, bool aItalic ) const; /** @@ -170,7 +169,7 @@ public: * @param aTextStyle text style flags * @return text cursor position after this text */ - virtual VECTOR2I GetTextAsGlyphs( BOX2I* aBBox, std::vector>& aGlyphs, + virtual VECTOR2I GetTextAsGlyphs( BOX2I* aBBox, std::vector>* aGlyphs, const UTF8& aText, const VECTOR2D& aSize, const VECTOR2I& aPosition, const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin, @@ -206,10 +205,10 @@ protected: * @param aOrigin is the point around which the text should be rotated, mirrored, etc. * @return new cursor position in non-rotated, non-mirrored coordinates */ - VECTOR2D drawSingleLineText( KIGFX::GAL* aGal, BOX2I* aBoundingBox, const UTF8& aText, - const VECTOR2I& aPosition, const VECTOR2D& aSize, - const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin, - bool aItalic ) const; + void drawSingleLineText( KIGFX::GAL* aGal, BOX2I* aBoundingBox, const UTF8& aText, + const VECTOR2I& aPosition, const VECTOR2D& aSize, + const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin, + bool aItalic ) const; /** * Computes the bounding box for a single line of text. @@ -221,15 +220,14 @@ protected: * @param aSize is the cap-height and em-width of the text. * @return new cursor position */ - VECTOR2D boundingBoxSingleLine( BOX2I* aBBox, const UTF8& aText, const VECTOR2I& aPosition, + VECTOR2I boundingBoxSingleLine( BOX2I* aBBox, const UTF8& aText, const VECTOR2I& aPosition, const VECTOR2D& aSize, bool aItalic ) const; void getLinePositions( const UTF8& aText, const VECTOR2I& aPosition, wxArrayString& aTextLines, std::vector& aPositions, - std::vector& aBoundingBoxes, - const TEXT_ATTRIBUTES& aAttributes ) const; + std::vector& aExtents, const TEXT_ATTRIBUTES& aAttrs ) const; - VECTOR2D drawMarkup( BOX2I* aBoundingBox, std::vector>& aGlyphs, + VECTOR2I drawMarkup( BOX2I* aBoundingBox, std::vector>* aGlyphs, const UTF8& aText, const VECTOR2I& aPosition, const VECTOR2D& aSize, const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin, TEXT_STYLE_FLAGS aTextStyle ) const; @@ -240,9 +238,6 @@ protected: private: static FONT* getDefaultFont(); - VECTOR2D doDrawString( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition, - bool aParse, const TEXT_ATTRIBUTES& aAttrs ) const; - protected: wxString m_fontName; ///< Font name wxString m_fontFileName; ///< Font file name diff --git a/include/font/glyph.h b/include/font/glyph.h index 38d218e622..951586d9a0 100644 --- a/include/font/glyph.h +++ b/include/font/glyph.h @@ -31,6 +31,10 @@ #include #include +typedef std::function + TRIANGULATE_CALLBACK; + namespace KIFONT { class GLYPH @@ -64,6 +68,8 @@ public: bool IsOutline() const override { return true; } BOX2D BoundingBox() override; + + void Triangulate( TRIANGULATE_CALLBACK aCallback ) const; }; diff --git a/include/font/outline_font.h b/include/font/outline_font.h index 58d88d6ded..fb4c3e1285 100644 --- a/include/font/outline_font.h +++ b/include/font/outline_font.h @@ -93,7 +93,7 @@ public: */ double GetInterline( double aGlyphHeight = 0.0, double aLineSpacing = 1.0 ) const override; - VECTOR2I GetTextAsGlyphs( BOX2I* aBoundingBox, std::vector>& aGlyphs, + VECTOR2I GetTextAsGlyphs( BOX2I* aBoundingBox, std::vector>* aGlyphs, const UTF8& aText, const VECTOR2D& aSize, const VECTOR2I& aPosition, const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin, TEXT_STYLE_FLAGS aTextStyle ) const override; @@ -106,8 +106,11 @@ public: * @param aGlyphs returns text glyphs * @param aText the text item */ - VECTOR2I GetLinesAsGlyphs( std::vector>& aGlyphs, - const EDA_TEXT* aText ) const; + void GetLinesAsGlyphs( std::vector>* aGlyphs, + const EDA_TEXT* aText ) const; + + void GetLinesAsGlyphs( std::vector>* aGlyphs, const UTF8& aText, + const VECTOR2I& aPosition, const TEXT_ATTRIBUTES& aAttrs ) const; const FT_Face& GetFace() const { return m_face; } diff --git a/include/font/stroke_font.h b/include/font/stroke_font.h index 653f78cb26..d7a8bfe991 100644 --- a/include/font/stroke_font.h +++ b/include/font/stroke_font.h @@ -76,7 +76,7 @@ public: */ double GetInterline( double aGlyphHeight, double aLineSpacing = 1.0 ) const override; - VECTOR2I GetTextAsGlyphs( BOX2I* aBoundingBox, std::vector>& aGlyphs, + VECTOR2I GetTextAsGlyphs( BOX2I* aBoundingBox, std::vector>* aGlyphs, const UTF8& aText, const VECTOR2D& aSize, const VECTOR2I& aPosition, const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin, TEXT_STYLE_FLAGS aTextStyle ) const override; diff --git a/include/font/triangulate.h b/include/font/triangulate.h deleted file mode 100644 index ce6ca207ef..0000000000 --- a/include/font/triangulate.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2021 Ola Rinta-Koski - * Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef TRIANGULATE_H -#define TRIANGULATE_H - -#include -#include -#include -#include - - -typedef std::function - TRIANGULATE_CALLBACK; - -void Triangulate( const SHAPE_POLY_SET& aPolylist, TRIANGULATE_CALLBACK aCallback, - void* aCallbackData = nullptr ); - -#endif // TRIANGULATE_H diff --git a/include/gal/opengl/opengl_gal.h b/include/gal/opengl/opengl_gal.h index bff6cbefa0..4c96639fee 100644 --- a/include/gal/opengl/opengl_gal.h +++ b/include/gal/opengl/opengl_gal.h @@ -524,8 +524,6 @@ private: VECTOR2D getScreenPixelSize() const; - void fillPolygonAsTriangles( const SHAPE_POLY_SET& aPolyList ); - /** * Basic OpenGL initialization and feature checks. *