Performance optimizations for the stroke font.

This commit is contained in:
Jeff Young 2019-12-03 17:45:02 +00:00
parent edf23dc5a9
commit 581dc81358
2 changed files with 69 additions and 40 deletions

View File

@ -39,6 +39,11 @@ const double STROKE_FONT::BOLD_FACTOR = 1.3;
const double STROKE_FONT::STROKE_FONT_SCALE = 1.0 / 21.0; const double STROKE_FONT::STROKE_FONT_SCALE = 1.0 / 21.0;
const double STROKE_FONT::ITALIC_TILT = 1.0 / 8; const double STROKE_FONT::ITALIC_TILT = 1.0 / 8;
GLYPH_LIST* g_newStrokeFontGlyphs = nullptr; ///< Glyph list
std::vector<BOX2D>* g_newStrokeFontGlyphBoundingBoxes; ///< Bounding boxes of the glyphs
STROKE_FONT::STROKE_FONT( GAL* aGal ) : STROKE_FONT::STROKE_FONT( GAL* aGal ) :
m_gal( aGal ) m_gal( aGal )
{ {
@ -47,41 +52,63 @@ STROKE_FONT::STROKE_FONT( GAL* aGal ) :
bool STROKE_FONT::LoadNewStrokeFont( const char* const aNewStrokeFont[], int aNewStrokeFontSize ) bool STROKE_FONT::LoadNewStrokeFont( const char* const aNewStrokeFont[], int aNewStrokeFontSize )
{ {
m_glyphs.clear(); if( g_newStrokeFontGlyphs )
m_glyphBoundingBoxes.clear(); {
m_glyphs.resize( aNewStrokeFontSize ); m_glyphs = g_newStrokeFontGlyphs;
m_glyphBoundingBoxes.resize( aNewStrokeFontSize ); m_glyphBoundingBoxes = g_newStrokeFontGlyphBoundingBoxes;
return true;
}
g_newStrokeFontGlyphs = new GLYPH_LIST;
g_newStrokeFontGlyphs->resize( aNewStrokeFontSize );
g_newStrokeFontGlyphBoundingBoxes = new std::vector<BOX2D>;
g_newStrokeFontGlyphBoundingBoxes->resize( aNewStrokeFontSize );
for( int j = 0; j < aNewStrokeFontSize; j++ ) for( int j = 0; j < aNewStrokeFontSize; j++ )
{ {
GLYPH& glyph = m_glyphs[j]; GLYPH& glyph = g_newStrokeFontGlyphs->at( j );
double glyphStartX = 0.0; double glyphStartX = 0.0;
double glyphEndX = 0.0; double glyphEndX = 0.0;
VECTOR2D glyphBoundingX; double glyphWidth;
std::vector<VECTOR2D>* pointList = nullptr; std::vector<VECTOR2D>* pointList = nullptr;
int strokes = 0;
int i = 0; int i = 0;
while( aNewStrokeFont[j][i] )
{
if( aNewStrokeFont[j][i] == ' ' && aNewStrokeFont[j][i+1] == 'R' )
strokes++;
i += 2;
}
glyph.reserve( strokes + 1 );
i = 0;
while( aNewStrokeFont[j][i] ) while( aNewStrokeFont[j][i] )
{ {
VECTOR2D point( 0.0, 0.0 ); VECTOR2D point( 0.0, 0.0 );
char coordinate[2] = { 0, }; char coordinate[2] = { 0, };
for( int k = 0; k < 2; k++ ) for( int k : { 0, 1 } )
{
coordinate[k] = aNewStrokeFont[j][i + k]; coordinate[k] = aNewStrokeFont[j][i + k];
}
if( i < 2 ) if( i < 2 )
{ {
// The first two values contain the width of the char // The first two values contain the width of the char
glyphStartX = ( coordinate[0] - 'R' ) * STROKE_FONT_SCALE; glyphStartX = ( coordinate[0] - 'R' ) * STROKE_FONT_SCALE;
glyphEndX = ( coordinate[1] - 'R' ) * STROKE_FONT_SCALE; glyphEndX = ( coordinate[1] - 'R' ) * STROKE_FONT_SCALE;
glyphBoundingX = VECTOR2D( 0, glyphEndX - glyphStartX ); glyphWidth = glyphEndX - glyphStartX;
} }
else if( ( coordinate[0] == ' ' ) && ( coordinate[1] == 'R' ) ) else if( ( coordinate[0] == ' ' ) && ( coordinate[1] == 'R' ) )
{ {
if( pointList )
pointList->resize( pointList->size() );
// Raise pen // Raise pen
pointList = nullptr; pointList = nullptr;
} }
@ -104,7 +131,7 @@ bool STROKE_FONT::LoadNewStrokeFont( const char* const aNewStrokeFont[], int aNe
if( !pointList ) if( !pointList )
{ {
glyph.emplace_back( std::vector<VECTOR2D>() ); glyph.emplace_back();
pointList = &glyph.back(); pointList = &glyph.back();
} }
@ -114,10 +141,15 @@ bool STROKE_FONT::LoadNewStrokeFont( const char* const aNewStrokeFont[], int aNe
i += 2; i += 2;
} }
if( pointList )
pointList->resize( pointList->size() );
// Compute the bounding box of the glyph // Compute the bounding box of the glyph
m_glyphBoundingBoxes[j] = computeBoundingBox( glyph, glyphBoundingX ); g_newStrokeFontGlyphBoundingBoxes->at( j ) = computeBoundingBox( glyph, glyphWidth );
} }
m_glyphs = g_newStrokeFontGlyphs;
m_glyphBoundingBoxes = g_newStrokeFontGlyphBoundingBoxes;
return true; return true;
} }
@ -131,24 +163,21 @@ double STROKE_FONT::GetInterline( double aGlyphHeight )
} }
BOX2D STROKE_FONT::computeBoundingBox( const GLYPH& aGLYPH, const VECTOR2D& aGLYPHBoundingX ) const BOX2D STROKE_FONT::computeBoundingBox( const GLYPH& aGLYPH, double aGlyphWidth ) const
{ {
BOX2D boundingBox; VECTOR2D min( 0, 0 );
VECTOR2D max( aGlyphWidth, 0 );
std::vector<VECTOR2D> boundingPoints;
boundingPoints.emplace_back( VECTOR2D( aGLYPHBoundingX.x, 0 ) );
boundingPoints.emplace_back( VECTOR2D( aGLYPHBoundingX.y, 0 ) );
for( const std::vector<VECTOR2D>& pointList : aGLYPH ) for( const std::vector<VECTOR2D>& pointList : aGLYPH )
{ {
for( const VECTOR2D& point : pointList ) for( const VECTOR2D& point : pointList )
boundingPoints.emplace_back( aGLYPHBoundingX.x, point.y ); {
min.y = std::min( min.y, point.y );
max.y = std::max( max.y, point.y );
}
} }
boundingBox.Compute( boundingPoints ); return BOX2D( min, max - min );
return boundingBox;
} }
@ -306,7 +335,7 @@ void STROKE_FONT::drawSingleLineText( const UTF8& aText, int markupFlags )
// The choice of spaces is somewhat arbitrary but sufficient for aligning text // The choice of spaces is somewhat arbitrary but sufficient for aligning text
if( *chIt == '\t' ) if( *chIt == '\t' )
{ {
double space = glyphSize.x * m_glyphBoundingBoxes[0].GetEnd().x; double space = glyphSize.x * m_glyphBoundingBoxes->at( 0 ).GetEnd().x;
// We align to the 4th column (fmod) but only need to account for 3 of // We align to the 4th column (fmod) but only need to account for 3 of
// the four spaces here with the extra. This ensures that we have at // the four spaces here with the extra. This ensures that we have at
@ -388,14 +417,14 @@ void STROKE_FONT::drawSingleLineText( const UTF8& aText, int markupFlags )
// Index into bounding boxes table // Index into bounding boxes table
int dd = (signed) *chIt - ' '; int dd = (signed) *chIt - ' ';
if( dd >= (int) m_glyphBoundingBoxes.size() || dd < 0 ) if( dd >= (int) m_glyphBoundingBoxes->size() || dd < 0 )
{ {
int substitute = *chIt == '\t' ? ' ' : '?'; int substitute = *chIt == '\t' ? ' ' : '?';
dd = substitute - ' '; dd = substitute - ' ';
} }
GLYPH& glyph = m_glyphs[dd]; const GLYPH& glyph = m_glyphs->at( dd );
BOX2D& bbox = m_glyphBoundingBoxes[dd]; const BOX2D& bbox = m_glyphBoundingBoxes->at( dd );
if( in_overbar ) if( in_overbar )
{ {
@ -422,11 +451,11 @@ void STROKE_FONT::drawSingleLineText( const UTF8& aText, int markupFlags )
last_had_overbar = false; last_had_overbar = false;
} }
for( std::vector<VECTOR2D>& ptList : glyph ) for( const std::vector<VECTOR2D>& ptList : glyph )
{ {
std::deque<VECTOR2D> ptListScaled; std::deque<VECTOR2D> ptListScaled;
for( VECTOR2D& pt : ptList ) for( const VECTOR2D& pt : ptList )
{ {
VECTOR2D scaledPt( pt.x * glyphSize.x + xOffset, pt.y * glyphSize.y + yOffset ); VECTOR2D scaledPt( pt.x * glyphSize.x + xOffset, pt.y * glyphSize.y + yOffset );
@ -501,7 +530,7 @@ VECTOR2D STROKE_FONT::ComputeStringBoundaryLimits( const UTF8& aText, const VECT
// The choice of spaces is somewhat arbitrary but sufficient for aligning text // The choice of spaces is somewhat arbitrary but sufficient for aligning text
if( *it == '\t' ) if( *it == '\t' )
{ {
double spaces = m_glyphBoundingBoxes[0].GetEnd().x; double spaces = m_glyphBoundingBoxes->at( 0 ).GetEnd().x;
double addlSpace = 3.0 * spaces - std::fmod( curX, 4.0 * spaces ); double addlSpace = 3.0 * spaces - std::fmod( curX, 4.0 * spaces );
// Add the remaining space (between 0 and 3 spaces) // Add the remaining space (between 0 and 3 spaces)
@ -576,13 +605,13 @@ VECTOR2D STROKE_FONT::ComputeStringBoundaryLimits( const UTF8& aText, const VECT
// Index in the bounding boxes table // Index in the bounding boxes table
int dd = (signed) *it - ' '; int dd = (signed) *it - ' ';
if( dd >= (int) m_glyphBoundingBoxes.size() || dd < 0 ) if( dd >= (int) m_glyphBoundingBoxes->size() || dd < 0 )
{ {
int substitute = *it == '\t' ? ' ' : '?'; int substitute = *it == '\t' ? ' ' : '?';
dd = substitute - ' '; dd = substitute - ' ';
} }
const BOX2D& box = m_glyphBoundingBoxes[dd]; const BOX2D& box = m_glyphBoundingBoxes->at( dd );
curX += box.GetEnd().x * curScale; curX += box.GetEnd().x * curScale;
} }

View File

@ -121,8 +121,8 @@ public:
private: private:
GAL* m_gal; ///< Pointer to the GAL GAL* m_gal; ///< Pointer to the GAL
GLYPH_LIST m_glyphs; ///< Glyph list const GLYPH_LIST* m_glyphs; ///< Glyph list
std::vector<BOX2D> m_glyphBoundingBoxes; ///< Bounding boxes of the glyphs const std::vector<BOX2D>* m_glyphBoundingBoxes; ///< Bounding boxes of the glyphs
/** /**
* @brief Compute the X and Y size of a given text. The text is expected to be * @brief Compute the X and Y size of a given text. The text is expected to be
@ -145,10 +145,10 @@ private:
* @brief Compute the bounding box of a given glyph. * @brief Compute the bounding box of a given glyph.
* *
* @param aGlyph is the glyph. * @param aGlyph is the glyph.
* @param aGlyphBoundingX is the x-component of the bounding box size. * @param aGlyphWidth is the x-component of the bounding box size.
* @return is the complete bounding box size. * @return is the complete bounding box size.
*/ */
BOX2D computeBoundingBox( const GLYPH& aGlyph, const VECTOR2D& aGlyphBoundingX ) const; BOX2D computeBoundingBox( const GLYPH& aGlyph, double aGlyphWidth ) const;
/** /**
* @brief Draws a single line of text. Multiline texts should be split before using the * @brief Draws a single line of text. Multiline texts should be split before using the