Skip to content

Commit

Permalink
Use precalculated horizontal advance and fragment fonts from text met…
Browse files Browse the repository at this point in the history
…rics instead of

recalculating
  • Loading branch information
nyalldawson committed Nov 10, 2022
1 parent 894a938 commit e478a52
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 18 deletions.
Expand Up @@ -57,6 +57,13 @@ Returns the height of the block at the specified index.
double baselineOffset( int blockIndex, Qgis::TextLayoutMode mode ) const;
%Docstring
Returns the offset from the top of the document to the text baseline for the given block index.
%End

double fragmentHorizontalAdvance( int blockIndex, int fragmentIndex, Qgis::TextLayoutMode mode ) const;
%Docstring
Returns the horizontal advance of the fragment at the specified block and fragment index.

.. versionadded:: 3.30
%End

double verticalOrientationXOffset( int blockIndex ) const;
Expand Down
14 changes: 13 additions & 1 deletion src/core/textrenderer/qgstextdocumentmetrics.cpp
Expand Up @@ -67,15 +67,21 @@ QgsTextDocumentMetrics QgsTextDocumentMetrics::calculateMetrics( const QgsTextDo

QList< QFont > fragmentFonts;
fragmentFonts.reserve( fragmentSize );
QList< double >fragmentHorizontalAdvance;
fragmentHorizontalAdvance.reserve( fragmentSize );
for ( int fragmentIndex = 0; fragmentIndex < fragmentSize; ++fragmentIndex )
{
const QgsTextFragment &fragment = block.at( fragmentIndex );
const QgsTextCharacterFormat &fragmentFormat = fragment.characterFormat();

QFont updatedFont = font;
fragment.characterFormat().updateFontForFormat( updatedFont, context, scaleFactor );
fragmentFormat.updateFontForFormat( updatedFont, context, scaleFactor );
const QFontMetricsF fm( updatedFont );

const double fragmentWidth = fm.horizontalAdvance( fragment.text() ) / scaleFactor;

fragmentHorizontalAdvance << fragmentWidth;

const double fragmentHeightUsingAscentDescent = ( fm.ascent() + fm.descent() ) / scaleFactor;
const double fragmentHeightUsingLineSpacing = fm.lineSpacing() / scaleFactor;

Expand Down Expand Up @@ -149,6 +155,7 @@ QgsTextDocumentMetrics QgsTextDocumentMetrics::calculateMetrics( const QgsTextDo
res.mBaselineOffsetsRectMode << currentRectBaseline;
res.mBlockMaxDescent << maxBlockDescent;
res.mBlockMaxCharacterWidth << maxBlockMaxWidth;
res.mFragmentHorizontalAdvance << fragmentHorizontalAdvance;

if ( blockIndex > 0 )
lastLineLeading = maxBlockLeading;
Expand Down Expand Up @@ -250,6 +257,11 @@ double QgsTextDocumentMetrics::baselineOffset( int blockIndex, Qgis::TextLayoutM
BUILTIN_UNREACHABLE
}

double QgsTextDocumentMetrics::fragmentHorizontalAdvance( int blockIndex, int fragmentIndex, Qgis::TextLayoutMode ) const
{
return mFragmentHorizontalAdvance.value( blockIndex ).value( fragmentIndex );
}

double QgsTextDocumentMetrics::verticalOrientationXOffset( int blockIndex ) const
{
return mVerticalOrientationXOffsets.value( blockIndex );
Expand Down
10 changes: 10 additions & 0 deletions src/core/textrenderer/qgstextdocumentmetrics.h
Expand Up @@ -72,6 +72,13 @@ class CORE_EXPORT QgsTextDocumentMetrics
*/
double baselineOffset( int blockIndex, Qgis::TextLayoutMode mode ) const;

/**
* Returns the horizontal advance of the fragment at the specified block and fragment index.
*
* \since QGIS 3.30
*/
double fragmentHorizontalAdvance( int blockIndex, int fragmentIndex, Qgis::TextLayoutMode mode ) const;

/**
* Returns the vertical orientation x offset for the specified block.
*/
Expand Down Expand Up @@ -109,6 +116,9 @@ class CORE_EXPORT QgsTextDocumentMetrics
QList< double > mBaselineOffsetsLabelMode;
QList< double > mBaselineOffsetsPointMode;
QList< double > mBaselineOffsetsRectMode;

QList< QList< double > > mFragmentHorizontalAdvance;

QList< double > mVerticalOrientationXOffsets;
QList< double > mBlockMaxDescent;
QList< double > mBlockMaxCharacterWidth;
Expand Down
39 changes: 22 additions & 17 deletions src/core/textrenderer/qgstextrenderer.cpp
Expand Up @@ -358,17 +358,19 @@ double QgsTextRenderer::drawBuffer( QgsRenderContext &context, const QgsTextRend
case Qgis::TextOrientation::Horizontal:
{
double xOffset = 0;
int fragmentIndex = 0;
for ( const QgsTextFragment &fragment : component.block )
{
QFont fragmentFont = font;
fragment.characterFormat().updateFontForFormat( fragmentFont, context, scaleFactor );
QFont fragmentFont = metrics.fragmentFont( component.blockIndex, fragmentIndex );

if ( component.extraWordSpacing || component.extraLetterSpacing )
applyExtraSpacingForLineJustification( fragmentFont, component.extraWordSpacing, component.extraLetterSpacing );

path.addText( xOffset, 0, fragmentFont, fragment.text() );

xOffset += fragment.horizontalAdvance( fragmentFont, context, true, scaleFactor );
xOffset += metrics.fragmentHorizontalAdvance( component.blockIndex, fragmentIndex, mode );

fragmentIndex++;
}
advance = xOffset;
break;
Expand All @@ -382,10 +384,11 @@ double QgsTextRenderer::drawBuffer( QgsRenderContext &context, const QgsTextRend
const double blockMaximumCharacterWidth = metrics.blockMaximumCharacterWidth( component.blockIndex );
double partLastDescent = 0;

int fragmentIndex = 0;
for ( const QgsTextFragment &fragment : component.block )
{
QFont fragmentFont = font;
fragment.characterFormat().updateFontForFormat( fragmentFont, context, scaleFactor );
const QFont fragmentFont = metrics.fragmentFont( component.blockIndex, fragmentIndex );

const double letterSpacing = fragmentFont.letterSpacing() / scaleFactor;

const QFontMetricsF fragmentMetrics( fragmentFont );
Expand All @@ -399,6 +402,7 @@ double QgsTextRenderer::drawBuffer( QgsRenderContext &context, const QgsTextRend
partYOffset += letterSpacing;
}
partLastDescent = fragmentMetrics.descent() / scaleFactor;
fragmentIndex++;
}
height = partYOffset + partLastDescent;
advance = partYOffset - component.offset.y() * scaleFactor;
Expand Down Expand Up @@ -480,7 +484,7 @@ double QgsTextRenderer::drawBuffer( QgsRenderContext &context, const QgsTextRend
return advance / scaleFactor;
}

void QgsTextRenderer::drawMask( QgsRenderContext &context, const QgsTextRenderer::Component &component, const QgsTextFormat &format,
void QgsTextRenderer::drawMask( QgsRenderContext &context, const QgsTextRenderer::Component &component, const QgsTextFormat &format, const QgsTextDocumentMetrics &metrics,
Qgis::TextLayoutMode mode )
{
QgsTextMaskSettings mask = format.mask();
Expand Down Expand Up @@ -520,14 +524,15 @@ void QgsTextRenderer::drawMask( QgsRenderContext &context, const QgsTextRenderer
referenceScaleOverride.reset();

double xOffset = 0;
int fragmentIndex = 0;
for ( const QgsTextFragment &fragment : component.block )
{
QFont fragmentFont = font;
fragment.characterFormat().updateFontForFormat( fragmentFont, context, scaleFactor );
const QFont fragmentFont = metrics.fragmentFont( component.blockIndex, fragmentIndex );

path.addText( xOffset, 0, fragmentFont, fragment.text() );

xOffset += fragment.horizontalAdvance( fragmentFont, context, true, scaleFactor );
xOffset += metrics.fragmentHorizontalAdvance( component.blockIndex, fragmentIndex, mode );
fragmentIndex++;
}

QColor bufferColor( Qt::gray );
Expand Down Expand Up @@ -1581,7 +1586,7 @@ void QgsTextRenderer::drawTextInternalHorizontal( QgsRenderContext &context, con
// draw the mask below the text (for preview)
if ( format.mask().enabled() )
{
QgsTextRenderer::drawMask( context, subComponent, format, mode );
QgsTextRenderer::drawMask( context, subComponent, format, metrics, mode );
}

if ( drawType == Qgis::TextComponent::Buffer )
Expand Down Expand Up @@ -1612,14 +1617,14 @@ void QgsTextRenderer::drawTextInternalHorizontal( QgsRenderContext &context, con
textp.scale( 1 / fontScale, 1 / fontScale );

double xOffset = 0;
int fragmentIndex = 0;
for ( const QgsTextFragment &fragment : block )
{
// draw text, QPainterPath method
QPainterPath path;
path.setFillRule( Qt::WindingFill );

QFont fragmentFont = font;
fragment.characterFormat().updateFontForFormat( fragmentFont, context, fontScale );
QFont fragmentFont = metrics.fragmentFont( blockIndex, fragmentIndex );

if ( extraWordSpace || extraLetterSpace )
applyExtraSpacingForLineJustification( fragmentFont, extraWordSpace * fontScale, extraLetterSpace * fontScale );
Expand All @@ -1631,7 +1636,8 @@ void QgsTextRenderer::drawTextInternalHorizontal( QgsRenderContext &context, con
textp.setBrush( textColor );
textp.drawPath( path );

xOffset += fragment.horizontalAdvance( fragmentFont, context, true, fontScale );
xOffset += metrics.fragmentHorizontalAdvance( blockIndex, fragmentIndex, mode );
fragmentIndex ++;
}
textp.end();
}
Expand Down Expand Up @@ -1667,10 +1673,10 @@ void QgsTextRenderer::drawTextInternalHorizontal( QgsRenderContext &context, con
case Qgis::TextRenderFormat::AlwaysText:
{
double xOffset = 0;
int fragmentIndex = 0;
for ( const QgsTextFragment &fragment : block )
{
QFont fragmentFont = font;
fragment.characterFormat().updateFontForFormat( fragmentFont, context, fontScale );
QFont fragmentFont = metrics.fragmentFont( blockIndex, fragmentIndex );

if ( extraWordSpace || extraLetterSpace )
applyExtraSpacingForLineJustification( fragmentFont, extraWordSpace * fontScale, extraLetterSpace * fontScale );
Expand Down Expand Up @@ -1839,8 +1845,7 @@ void QgsTextRenderer::drawTextInternalVertical( QgsRenderContext &context, const
// apply some character replacement to draw symbols in vertical presentation
const QString line = QgsStringUtils::substituteVerticalCharacters( fragment.text() );

QFont fragmentFont( font );
fragment.characterFormat().updateFontForFormat( fragmentFont, context, fontScale );
const QFont fragmentFont = metrics.fragmentFont( blockIndex, fragmentIndex );

QFontMetricsF fragmentMetrics( fragmentFont );

Expand Down
1 change: 1 addition & 0 deletions src/core/textrenderer/qgstextrenderer.h
Expand Up @@ -336,6 +336,7 @@ class CORE_EXPORT QgsTextRenderer
static void drawMask( QgsRenderContext &context,
const Component &component,
const QgsTextFormat &format,
const QgsTextDocumentMetrics &metrics,
Qgis::TextLayoutMode mode );

static void drawText( QgsRenderContext &context,
Expand Down

0 comments on commit e478a52

Please sign in to comment.