Don't punt on TrueType char thickness; analyze it.
Fixes https://gitlab.com/kicad/code/kicad/issues/10740
This commit is contained in:
parent
137edbe3f3
commit
3b5474f190
|
@ -446,7 +446,7 @@ void EDA_TEXT::ClearBoundingBoxCache()
|
||||||
std::vector<std::unique_ptr<KIFONT::GLYPH>>*
|
std::vector<std::unique_ptr<KIFONT::GLYPH>>*
|
||||||
EDA_TEXT::GetRenderCache( const wxString& forResolvedText ) const
|
EDA_TEXT::GetRenderCache( const wxString& forResolvedText ) const
|
||||||
{
|
{
|
||||||
if( GetFont() && GetFont()->IsOutline() )
|
if( GetDrawFont()->IsOutline() )
|
||||||
{
|
{
|
||||||
EDA_ANGLE resolvedAngle = GetDrawRotation();
|
EDA_ANGLE resolvedAngle = GetDrawRotation();
|
||||||
|
|
||||||
|
@ -456,7 +456,7 @@ EDA_TEXT::GetRenderCache( const wxString& forResolvedText ) const
|
||||||
{
|
{
|
||||||
m_render_cache.clear();
|
m_render_cache.clear();
|
||||||
|
|
||||||
KIFONT::OUTLINE_FONT* font = static_cast<KIFONT::OUTLINE_FONT*>( GetFont() );
|
KIFONT::OUTLINE_FONT* font = static_cast<KIFONT::OUTLINE_FONT*>( GetDrawFont() );
|
||||||
TEXT_ATTRIBUTES attrs = GetAttributes();
|
TEXT_ATTRIBUTES attrs = GetAttributes();
|
||||||
|
|
||||||
attrs.m_Angle = resolvedAngle;
|
attrs.m_Angle = resolvedAngle;
|
||||||
|
|
|
@ -95,20 +95,181 @@ bool DRC_TEST_PROVIDER_TEXT_DIMS::Run()
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto checkTextHeight =
|
||||||
|
[&]( BOARD_ITEM* item, EDA_TEXT* text ) -> bool
|
||||||
|
{
|
||||||
|
if( m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_HEIGHT ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( TEXT_HEIGHT_CONSTRAINT, item,
|
||||||
|
nullptr, item->GetLayer() );
|
||||||
|
|
||||||
|
if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
int actualHeight = text->GetTextSize().y;
|
||||||
|
|
||||||
|
if( constraint.Value().HasMin() && actualHeight < constraint.Value().Min() )
|
||||||
|
{
|
||||||
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_HEIGHT );
|
||||||
|
|
||||||
|
m_msg.Printf( _( "(%s min height %s; actual %s)" ),
|
||||||
|
constraint.GetName(),
|
||||||
|
MessageTextFromValue( userUnits(), constraint.Value().Min() ),
|
||||||
|
MessageTextFromValue( userUnits(), actualHeight ) );
|
||||||
|
|
||||||
|
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
|
||||||
|
drcItem->SetItems( item );
|
||||||
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
|
reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( constraint.Value().HasMax() && actualHeight > constraint.Value().Max() )
|
||||||
|
{
|
||||||
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_HEIGHT );
|
||||||
|
|
||||||
|
m_msg.Printf( _( "(%s max height %s; actual %s)" ),
|
||||||
|
constraint.GetName(),
|
||||||
|
MessageTextFromValue( userUnits(), constraint.Value().Max() ),
|
||||||
|
MessageTextFromValue( userUnits(), actualHeight ) );
|
||||||
|
|
||||||
|
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
|
||||||
|
drcItem->SetItems( item );
|
||||||
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
|
reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto checkTextThickness =
|
||||||
|
[&]( BOARD_ITEM* item, EDA_TEXT* text ) -> bool
|
||||||
|
{
|
||||||
|
DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( TEXT_THICKNESS_CONSTRAINT, item,
|
||||||
|
nullptr, item->GetLayer() );
|
||||||
|
|
||||||
|
if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
KIFONT::FONT* font = text->GetDrawFont();
|
||||||
|
|
||||||
|
if( font->IsOutline() )
|
||||||
|
{
|
||||||
|
if( !constraint.Value().HasMin() )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
auto* glyphs = text->GetRenderCache( text->GetShownText() );
|
||||||
|
bool collapsedStroke = false;
|
||||||
|
bool collapsedArea = false;
|
||||||
|
|
||||||
|
for( const std::unique_ptr<KIFONT::GLYPH>& glyph : *glyphs )
|
||||||
|
{
|
||||||
|
auto outlineGlyph = static_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() );
|
||||||
|
int outlineCount = outlineGlyph->OutlineCount();
|
||||||
|
int holeCount = 0;
|
||||||
|
|
||||||
|
if( outlineCount == 0 )
|
||||||
|
continue; // ignore spaces
|
||||||
|
|
||||||
|
for( int ii = 0; ii < outlineCount; ++ii )
|
||||||
|
holeCount += outlineGlyph->HoleCount( ii );
|
||||||
|
|
||||||
|
SHAPE_POLY_SET poly = *outlineGlyph;
|
||||||
|
poly.Deflate( constraint.Value().Min() / 2, 16 );
|
||||||
|
poly.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||||
|
|
||||||
|
int resultingOutlineCount = poly.OutlineCount();
|
||||||
|
int resultingHoleCount = 0;
|
||||||
|
|
||||||
|
for( int ii = 0; ii < resultingOutlineCount; ++ii )
|
||||||
|
resultingHoleCount += poly.HoleCount( ii );
|
||||||
|
|
||||||
|
if( ( resultingOutlineCount != outlineCount )
|
||||||
|
|| ( resultingHoleCount != holeCount ) )
|
||||||
|
{
|
||||||
|
collapsedStroke = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
double glyphArea = outlineGlyph->Area();
|
||||||
|
|
||||||
|
if( glyphArea == 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
poly.Inflate( constraint.Value().Min() / 2, 16 );
|
||||||
|
poly.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||||
|
double resultingGlyphArea = poly.Area();
|
||||||
|
|
||||||
|
if( ( std::abs( resultingGlyphArea - glyphArea ) / glyphArea ) > 0.1 )
|
||||||
|
{
|
||||||
|
collapsedArea = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( collapsedStroke || collapsedArea )
|
||||||
|
{
|
||||||
|
auto drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
|
||||||
|
|
||||||
|
m_msg = _( "(TrueType font characters with insufficient stroke weight)" );
|
||||||
|
|
||||||
|
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
|
||||||
|
drcItem->SetItems( item );
|
||||||
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
|
reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int actualThickness = text->GetTextThickness();
|
||||||
|
|
||||||
|
if( constraint.Value().HasMin() && actualThickness < constraint.Value().Min() )
|
||||||
|
{
|
||||||
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
|
||||||
|
|
||||||
|
m_msg.Printf( _( "(%s min thickness %s; actual %s)" ),
|
||||||
|
constraint.GetName(),
|
||||||
|
MessageTextFromValue( userUnits(), constraint.Value().Min() ),
|
||||||
|
MessageTextFromValue( userUnits(), actualThickness ) );
|
||||||
|
|
||||||
|
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
|
||||||
|
drcItem->SetItems( item );
|
||||||
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
|
reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( constraint.Value().HasMax() && actualThickness > constraint.Value().Max() )
|
||||||
|
{
|
||||||
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
|
||||||
|
|
||||||
|
m_msg.Printf( _( "(%s max thickness %s; actual %s)" ),
|
||||||
|
constraint.GetName(),
|
||||||
|
MessageTextFromValue( userUnits(), constraint.Value().Max() ),
|
||||||
|
MessageTextFromValue( userUnits(), actualThickness ) );
|
||||||
|
|
||||||
|
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
|
||||||
|
drcItem->SetItems( item );
|
||||||
|
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
|
reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
auto checkTextDims =
|
auto checkTextDims =
|
||||||
[&]( BOARD_ITEM* item ) -> bool
|
[&]( BOARD_ITEM* item ) -> bool
|
||||||
{
|
{
|
||||||
if( m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_HEIGHT )
|
|
||||||
&& m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_THICKNESS ) )
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !reportProgress( ii++, count, delta ) )
|
if( !reportProgress( ii++, count, delta ) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DRC_CONSTRAINT constraint;
|
EDA_TEXT* text = nullptr;
|
||||||
EDA_TEXT* text = nullptr;
|
int strikes = 0;
|
||||||
|
|
||||||
switch( item->Type() )
|
switch( item->Type() )
|
||||||
{
|
{
|
||||||
|
@ -122,125 +283,18 @@ bool DRC_TEST_PROVIDER_TEXT_DIMS::Run()
|
||||||
if( !text || !text->IsVisible() )
|
if( !text || !text->IsVisible() )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
VECTOR2I size = text->GetTextSize();
|
if( m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_THICKNESS ) )
|
||||||
KIFONT::FONT* font = text->GetDrawFont();
|
strikes++;
|
||||||
|
else
|
||||||
|
checkTextThickness( item, text );
|
||||||
|
|
||||||
int actualH = size.y;
|
if( m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_HEIGHT ) )
|
||||||
int actualT = text->GetTextThickness();
|
strikes++;
|
||||||
|
else
|
||||||
|
checkTextHeight( item, text );
|
||||||
|
|
||||||
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_HEIGHT ) )
|
if( strikes >= 2 )
|
||||||
{
|
return false;
|
||||||
constraint = m_drcEngine->EvalRules( TEXT_HEIGHT_CONSTRAINT, item, nullptr,
|
|
||||||
item->GetLayer() );
|
|
||||||
bool fail_min = false;
|
|
||||||
bool fail_max = false;
|
|
||||||
int constraintHeight;
|
|
||||||
|
|
||||||
if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE )
|
|
||||||
{
|
|
||||||
if( constraint.Value().HasMin() && actualH < constraint.Value().Min() )
|
|
||||||
{
|
|
||||||
fail_min = true;
|
|
||||||
constraintHeight = constraint.Value().Min();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( constraint.Value().HasMax() && actualH > constraint.Value().Max() )
|
|
||||||
{
|
|
||||||
fail_max = true;
|
|
||||||
constraintHeight = constraint.Value().Max();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( fail_min || fail_max )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_HEIGHT );
|
|
||||||
|
|
||||||
if( fail_min )
|
|
||||||
{
|
|
||||||
m_msg.Printf( _( "(%s min height %s; actual %s)" ),
|
|
||||||
constraint.GetName(),
|
|
||||||
MessageTextFromValue( userUnits(), constraintHeight ),
|
|
||||||
MessageTextFromValue( userUnits(), actualH ) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_msg.Printf( _( "(%s max height %s; actual %s)" ),
|
|
||||||
constraint.GetName(),
|
|
||||||
MessageTextFromValue( userUnits(), constraintHeight ),
|
|
||||||
MessageTextFromValue( userUnits(), actualH ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
|
|
||||||
drcItem->SetItems( item );
|
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
|
||||||
|
|
||||||
reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_THICKNESS ) )
|
|
||||||
{
|
|
||||||
if( font->IsOutline() )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
|
|
||||||
|
|
||||||
m_msg = _( "(TrueType font characters can have variable thickness)" );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
|
|
||||||
drcItem->SetItems( item );
|
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
|
||||||
|
|
||||||
reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
constraint = m_drcEngine->EvalRules( TEXT_THICKNESS_CONSTRAINT, item, nullptr,
|
|
||||||
item->GetLayer() );
|
|
||||||
bool fail_min = false;
|
|
||||||
bool fail_max = false;
|
|
||||||
int constraintThickness;
|
|
||||||
|
|
||||||
if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE )
|
|
||||||
{
|
|
||||||
if( constraint.Value().HasMin() && actualT < constraint.Value().Min() )
|
|
||||||
{
|
|
||||||
fail_min = true;
|
|
||||||
constraintThickness = constraint.Value().Min();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( constraint.Value().HasMax() && actualT > constraint.Value().Max() )
|
|
||||||
{
|
|
||||||
fail_max = true;
|
|
||||||
constraintThickness = constraint.Value().Max();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( fail_min || fail_max )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TEXT_THICKNESS );
|
|
||||||
|
|
||||||
if( fail_min )
|
|
||||||
{
|
|
||||||
m_msg.Printf( _( "(%s min thickness %s; actual %s)" ),
|
|
||||||
constraint.GetName(),
|
|
||||||
MessageTextFromValue( userUnits(), constraintThickness ),
|
|
||||||
MessageTextFromValue( userUnits(), actualT ) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_msg.Printf( _( "(%s max thickness %s; actual %s)" ),
|
|
||||||
constraint.GetName(),
|
|
||||||
MessageTextFromValue( userUnits(), constraintThickness ),
|
|
||||||
MessageTextFromValue( userUnits(), actualT ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
|
|
||||||
drcItem->SetItems( item );
|
|
||||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
|
||||||
|
|
||||||
reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue