Fix PDF plotting of text containing tab characters

The PDF plotter's renderWord function now properly handles tab characters
within text. Previously, tabs were passed to HarfBuzz or the stroke font
encoder which would render them as zero-width or small-width glyphs,
causing text alignment issues.

The fix splits text at tab boundaries and calculates proper tab stop
positions using the same algorithm as the font rendering code (TAB_WIDTH
= 4 * 0.6 font units), advancing the cursor to the next tab stop for
each tab character encountered.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/22606
This commit is contained in:
Seth Hillbrand
2026-01-09 18:09:47 -08:00
parent 0d6074e2b2
commit 5364eeb718
2 changed files with 89 additions and 2 deletions
+41
View File
@@ -415,4 +415,45 @@ BOOST_AUTO_TEST_CASE( PlotOutlineFontEmbedding )
MaybeRemoveFile( pdfPath );
}
// Test tab handling in PDF text output (issue #22606).
// When text contains tab characters, each tab should advance to the next tab stop.
// We verify that text with tabs produces different glyph positions than without tabs.
BOOST_AUTO_TEST_CASE( PlotTextWithTabs )
{
wxString pdfPath = getTempPdfPath( "kicad_pdf_tabs" );
PDF_PLOTTER plotter;
SIMPLE_RENDER_SETTINGS renderSettings;
plotter.SetRenderSettings( &renderSettings );
BOOST_REQUIRE( plotter.OpenFile( pdfPath ) );
plotter.SetViewport( VECTOR2I( 0, 0 ), 1.0, 1.0, false );
BOOST_REQUIRE( plotter.StartPlot( wxT( "1" ), wxT( "TabTest" ) ) );
TEXT_ATTRIBUTES attrs = BuildTextAttributes( 3000, 300, false, false );
auto strokeFont = LoadStrokeFontUnique();
KIFONT::METRICS metrics;
wxString textWithTab = wxT( "Before\tAfter" );
wxString textWithoutTab = wxT( "BeforeAfter" );
plotter.PlotText( VECTOR2I( 50000, 60000 ), COLOR4D( 0, 0, 0, 1 ), textWithTab, attrs,
strokeFont.get(), metrics );
plotter.PlotText( VECTOR2I( 50000, 50000 ), COLOR4D( 0, 0, 0, 1 ), textWithoutTab, attrs,
strokeFont.get(), metrics );
plotter.EndPlot();
std::string buffer;
BOOST_REQUIRE( ReadPdfWithDecompressedStreams( pdfPath, buffer ) );
BOOST_CHECK( buffer.rfind( "%PDF", 0 ) == 0 );
// The PDF should contain text content. Tabs should not produce visible tab glyphs but should
// create proper spacing. We verify the PDF is valid and contains our text characters.
BOOST_CHECK_MESSAGE( PdfContains( buffer, "0041" ) || PdfContains( buffer, "A" ),
"PDF should contain 'A' from 'After'" );
MaybeRemoveFile( pdfPath );
}
BOOST_AUTO_TEST_SUITE_END()