Don't punt on TrueType char thickness; analyze it.

Fixes https://gitlab.com/kicad/code/kicad/issues/10740
This commit is contained in:
Jeff Young 2022-02-08 14:02:55 +00:00
parent 137edbe3f3
commit 3b5474f190
2 changed files with 181 additions and 127 deletions

View File

@ -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;

View File

@ -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;
}; };