25#include <QFontMetricsF>
35 const QFont font = format.
scaledFont( context, scaleFactor, &res.mIsNullSize );
43 double heightLabelMode = 0;
44 double heightPointRectMode = 0;
45 double heightCapHeightMode = 0;
46 double heightAscentMode = 0;
47 const int blockSize = document.
size();
48 res.mFragmentFonts.reserve( blockSize );
49 double currentLabelBaseline = 0;
50 double currentPointBaseline = 0;
51 double currentRectBaseline = 0;
52 double currentCapHeightBasedBaseline = 0;
53 double currentAscentBasedBaseline = 0;
54 double lastLineLeading = 0;
56 double heightVerticalOrientation = 0;
58 QVector < double > blockVerticalLineSpacing;
62 double outerYMinLabel = 0;
63 double outerYMaxLabel = 0;
65 for (
int blockIndex = 0; blockIndex < blockSize; blockIndex++ )
71 double blockYMaxAdjustLabel = 0;
73 double blockHeightUsingAscentDescent = 0;
74 double blockHeightUsingLineSpacing = 0;
75 double blockHeightVerticalOrientation = 0;
77 double blockHeightUsingAscentAccountingForVerticalOffset = 0;
79 const int fragmentSize = block.
size();
81 double maxBlockAscent = 0;
82 double maxBlockDescent = 0;
83 double maxLineSpacing = 0;
84 double maxBlockLeading = 0;
85 double maxBlockMaxWidth = 0;
86 double maxBlockCapHeight = 0;
88 QList< double > fragmentVerticalOffsets;
89 fragmentVerticalOffsets.reserve( fragmentSize );
91 QList< QFont > fragmentFonts;
92 fragmentFonts.reserve( fragmentSize );
96 QFont previousNonSuperSubScriptFont;
98 for (
int fragmentIndex = 0; fragmentIndex < fragmentSize; ++fragmentIndex )
103 double fragmentHeightForVerticallyOffsetText = 0;
104 double fragmentYMaxAdjust = 0;
106 QFont updatedFont = font;
109 QFontMetricsF fm( updatedFont );
111 if ( fragmentIndex == 0 )
112 previousNonSuperSubScriptFont = updatedFont;
120 previousNonSuperSubScriptFont = updatedFont;
125 const QFontMetricsF previousFM( previousNonSuperSubScriptFont );
135 fm = QFontMetricsF( updatedFont );
149 const QFontMetricsF previousFM( previousNonSuperSubScriptFont );
155 fm = QFontMetricsF( updatedFont );
168 previousNonSuperSubScriptFont = updatedFont;
172 const double fragmentWidth = fm.horizontalAdvance( fragment.
text() ) / scaleFactor;
176 const double fragmentHeightUsingAscentDescent = ( fm.ascent() + fm.descent() ) / scaleFactor;
177 const double fragmentHeightUsingLineSpacing = fm.lineSpacing() / scaleFactor;
180 blockXMax += fragmentWidth;
181 blockHeightUsingAscentDescent = std::max( blockHeightUsingAscentDescent, fragmentHeightUsingAscentDescent );
183 blockHeightUsingLineSpacing = std::max( blockHeightUsingLineSpacing, fragmentHeightUsingLineSpacing );
184 maxBlockAscent = std::max( maxBlockAscent, fm.ascent() / scaleFactor );
186 maxBlockCapHeight = std::max( maxBlockCapHeight, fm.capHeight() / scaleFactor );
188 blockHeightUsingAscentAccountingForVerticalOffset = std::max( std::max( maxBlockAscent, fragmentHeightForVerticallyOffsetText ), blockHeightUsingAscentAccountingForVerticalOffset );
190 maxBlockDescent = std::max( maxBlockDescent, fm.descent() / scaleFactor );
191 maxBlockMaxWidth = std::max( maxBlockMaxWidth, fm.maxWidth() / scaleFactor );
193 blockYMaxAdjustLabel = std::max( blockYMaxAdjustLabel, fragmentYMaxAdjust );
195 if ( ( fm.lineSpacing() / scaleFactor ) > maxLineSpacing )
197 maxLineSpacing = fm.lineSpacing() / scaleFactor;
198 maxBlockLeading = fm.leading() / scaleFactor;
201 fragmentFonts << updatedFont;
203 const double verticalOrientationFragmentHeight = fragmentIndex == 0 ? ( fm.ascent() / scaleFactor * fragment.
text().size() + ( fragment.
text().size() - 1 ) * updatedFont.letterSpacing() / scaleFactor )
204 : ( fragment.
text().size() * ( fm.ascent() / scaleFactor + updatedFont.letterSpacing() / scaleFactor ) );
205 blockHeightVerticalOrientation += verticalOrientationFragmentHeight;
208 if ( blockIndex == 0 )
212 res.mFirstLineAscentOffset = 0.25 * maxBlockAscent;
213 res.mLastLineAscentOffset = res.mFirstLineAscentOffset;
214 res.mFirstLineCapHeight = maxBlockCapHeight;
215 const double lineHeight = ( maxBlockAscent + maxBlockDescent );
220 currentLabelBaseline = -res.mFirstLineAscentOffset;
222 if ( blockHeightUsingAscentAccountingForVerticalOffset > maxBlockAscent )
223 outerYMinLabel = maxBlockAscent - blockHeightUsingAscentAccountingForVerticalOffset;
226 currentRectBaseline = -res.mFirstLineAscentOffset + lineHeight - 1 ;
228 currentCapHeightBasedBaseline = res.mFirstLineCapHeight;
229 currentAscentBasedBaseline = maxBlockAscent;
232 currentPointBaseline = 0;
234 heightLabelMode += blockHeightUsingAscentDescent;
235 heightPointRectMode += blockHeightUsingAscentDescent;
236 heightCapHeightMode += maxBlockCapHeight;
237 heightAscentMode += maxBlockAscent;
244 currentLabelBaseline += thisLineHeightUsingAscentDescent;
245 currentRectBaseline += thisLineHeightUsingLineSpacing;
246 currentPointBaseline += thisLineHeightUsingLineSpacing;
248 currentCapHeightBasedBaseline += thisLineHeightUsingLineSpacing;
250 currentAscentBasedBaseline += thisLineHeightUsingLineSpacing;
252 heightLabelMode += thisLineHeightUsingAscentDescent;
253 heightPointRectMode += thisLineHeightUsingLineSpacing;
254 heightCapHeightMode += thisLineHeightUsingLineSpacing;
255 heightAscentMode += thisLineHeightUsingLineSpacing;
256 if ( blockIndex == blockSize - 1 )
257 res.mLastLineAscentOffset = 0.25 * maxBlockAscent;
260 if ( blockIndex == blockSize - 1 )
262 if ( blockYMaxAdjustLabel > maxBlockDescent )
263 outerYMaxLabel = blockYMaxAdjustLabel - maxBlockDescent;
268 res.mBlockHeights << blockHeightUsingLineSpacing;
271 outerXMax = std::max( outerXMax, blockXMax );
273 heightVerticalOrientation = std::max( heightVerticalOrientation, blockHeightVerticalOrientation );
275 res.mFragmentFonts << fragmentFonts;
276 res.mBaselineOffsetsLabelMode << currentLabelBaseline;
277 res.mBaselineOffsetsPointMode << currentPointBaseline;
278 res.mBaselineOffsetsRectMode << currentRectBaseline;
279 res.mBaselineOffsetsCapHeightMode << currentCapHeightBasedBaseline;
280 res.mBaselineOffsetsAscentBased << currentAscentBasedBaseline;
281 res.mBlockMaxDescent << maxBlockDescent;
282 res.mBlockMaxCharacterWidth << maxBlockMaxWidth;
283 res.mFragmentVerticalOffsetsLabelMode << fragmentVerticalOffsets;
284 res.mFragmentVerticalOffsetsRectMode << fragmentVerticalOffsets;
285 res.mFragmentVerticalOffsetsPointMode << fragmentVerticalOffsets;
288 if ( blockIndex > 0 )
289 lastLineLeading = maxBlockLeading;
292 heightLabelMode -= lastLineLeading;
293 heightPointRectMode -= lastLineLeading;
295 res.mDocumentSizeLabelMode = QSizeF( width, heightLabelMode );
296 res.mDocumentSizePointRectMode = QSizeF( width, heightPointRectMode );
297 res.mDocumentSizeCapHeightMode = QSizeF( width, heightCapHeightMode );
298 res.mDocumentSizeAscentMode = QSizeF( width, heightAscentMode );
301 if ( !res.mBaselineOffsetsLabelMode.isEmpty() )
303 const double labelModeBaselineAdjust = res.mBaselineOffsetsLabelMode.constLast() + res.mLastLineAscentOffset;
304 const double pointModeBaselineAdjust = res.mBaselineOffsetsPointMode.constLast();
305 for (
int i = 0; i < blockSize; ++i )
307 res.mBaselineOffsetsLabelMode[i] -= labelModeBaselineAdjust;
308 res.mBaselineOffsetsPointMode[i] -= pointModeBaselineAdjust;
312 if ( !res.mBlockMaxCharacterWidth.isEmpty() )
314 QList< double > adjustedRightToLeftXOffsets;
315 double currentOffset = 0;
316 const int size = res.mBlockMaxCharacterWidth.size();
318 double widthVerticalOrientation = 0;
319 for (
int i = 0; i < size; ++i )
321 const double rightToLeftBlockMaxCharacterWidth = res.mBlockMaxCharacterWidth[size - 1 - i ];
322 const double rightToLeftLineSpacing = blockVerticalLineSpacing[ size - 1 - i ];
324 adjustedRightToLeftXOffsets << currentOffset;
325 currentOffset += rightToLeftLineSpacing;
328 widthVerticalOrientation += rightToLeftBlockMaxCharacterWidth;
330 widthVerticalOrientation += rightToLeftLineSpacing;
332 std::reverse( adjustedRightToLeftXOffsets.begin(), adjustedRightToLeftXOffsets.end() );
333 res.mVerticalOrientationXOffsets = adjustedRightToLeftXOffsets;
335 res.mDocumentSizeVerticalOrientation = QSizeF( widthVerticalOrientation, heightVerticalOrientation );
338 res.mOuterBoundsLabelMode = QRectF( outerXMin, -outerYMaxLabel,
339 outerXMax - outerXMin,
340 heightLabelMode - outerYMinLabel + outerYMaxLabel );
347 switch ( orientation )
354 return mDocumentSizePointRectMode;
357 return mDocumentSizeCapHeightMode;
360 return mDocumentSizeAscentMode;
363 return mDocumentSizeLabelMode;
368 return mDocumentSizeVerticalOrientation;
378 switch ( orientation )
390 return mOuterBoundsLabelMode;
404 return mBlockWidths.value( blockIndex );
409 return mBlockHeights.value( blockIndex );
414 return mFirstLineCapHeight;
422 return mBaselineOffsetsRectMode.value( blockIndex );
424 return mBaselineOffsetsCapHeightMode.value( blockIndex );
426 return mBaselineOffsetsAscentBased.value( blockIndex );
428 return mBaselineOffsetsPointMode.value( blockIndex );
430 return mBaselineOffsetsLabelMode.value( blockIndex );
437 return mFragmentHorizontalAdvance.value( blockIndex ).value( fragmentIndex );
447 return mFragmentVerticalOffsetsRectMode.value( blockIndex ).value( fragmentIndex );
449 return mFragmentVerticalOffsetsPointMode.value( blockIndex ).value( fragmentIndex );
451 return mFragmentVerticalOffsetsLabelMode.value( blockIndex ).value( fragmentIndex );
458 return mVerticalOrientationXOffsets.value( blockIndex );
463 return mBlockMaxCharacterWidth.value( blockIndex );
468 return mBlockMaxDescent.value( blockIndex );
473 return mFragmentFonts.value( blockIndex ).value( fragmentIndex );
TextLayoutMode
Text layout modes.
@ Labeling
Labeling-specific layout mode.
@ Point
Text at point of origin layout mode.
@ RectangleAscentBased
Similar to Rectangle mode, but uses ascents only when calculating font and line heights....
@ RectangleCapHeightBased
Similar to Rectangle mode, but uses cap height only when calculating font heights for the first line ...
@ Rectangle
Text within rectangle layout mode.
TextOrientation
Text orientations.
@ Vertical
Vertically oriented text.
@ RotationBased
Horizontally or vertically oriented text based on rotation (only available for map labeling)
@ Horizontal
Horizontally oriented text.
@ Normal
Adjacent characters are positioned in the standard way for text in the writing system in use.
@ SubScript
Characters are placed below the base line for normal text.
@ SuperScript
Characters are placed above the base line for normal text.
@ Percentage
Percentage of another measurement (e.g., canvas size, feature size)
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
Represents a block of text consisting of one or more QgsTextFragment objects.
int size() const
Returns the number of fragments in the block.
const QgsTextFragment & at(int index) const
Returns the fragment at the specified index.
Stores information relating to individual character formatting.
void updateFontForFormat(QFont &font, const QgsRenderContext &context, double scaleFactor=1.0) const
Updates the specified font in place, applying character formatting options which are applicable on a ...
Qgis::TextCharacterVerticalAlignment verticalAlignment() const
Returns the format vertical alignment.
bool hasVerticalAlignmentSet() const
Returns true if the format has an explicit vertical alignment set.
double fontPointSize() const
Returns the font point size, or -1 if the font size is not set and should be inherited.
Contains pre-calculated metrics of a QgsTextDocument.
double verticalOrientationXOffset(int blockIndex) const
Returns the vertical orientation x offset for the specified block.
double fragmentVerticalOffset(int blockIndex, int fragmentIndex, Qgis::TextLayoutMode mode) const
Returns the vertical offset from a text block's baseline which should be applied to the fragment at t...
double blockMaximumDescent(int blockIndex) const
Returns the maximum descent encountered in the specified block.
QSizeF documentSize(Qgis::TextLayoutMode mode, Qgis::TextOrientation orientation) const
Returns the overall size of the document.
double firstLineCapHeight() const
Returns the cap height for the first line of text.
QFont fragmentFont(int blockIndex, int fragmentIndex) const
Returns the calculated font for the fragment at the specified block and fragment indices.
double blockMaximumCharacterWidth(int blockIndex) const
Returns the maximum character width for the specified block.
double baselineOffset(int blockIndex, Qgis::TextLayoutMode mode) const
Returns the offset from the top of the document to the text baseline for the given block index.
QRectF outerBounds(Qgis::TextLayoutMode mode, Qgis::TextOrientation orientation) const
Returns the outer bounds of the document, which is the documentSize() adjusted to account for any tex...
static QgsTextDocumentMetrics calculateMetrics(const QgsTextDocument &document, const QgsTextFormat &format, const QgsRenderContext &context, double scaleFactor=1.0)
Returns precalculated text metrics for a text document, when rendered using the given base format and...
double blockHeight(int blockIndex) const
Returns the height of the block at the specified index.
double fragmentHorizontalAdvance(int blockIndex, int fragmentIndex, Qgis::TextLayoutMode mode) const
Returns the horizontal advance of the fragment at the specified block and fragment index.
bool isNullFontSize() const
Returns true if the metrics could not be calculated because the text format has a null font size.
double blockWidth(int blockIndex) const
Returns the width of the block at the specified index.
Represents a document consisting of one or more QgsTextBlock objects.
const QgsTextBlock & at(int index) const
Returns the block at the specified index.
int size() const
Returns the number of blocks in the document.
Container for all settings relating to text rendering.
double lineHeight() const
Returns the line height for text.
QFont scaledFont(const QgsRenderContext &context, double scaleFactor=1.0, bool *isZeroSize=nullptr) const
Returns a font with the size scaled to match the format's size settings (including units and map unit...
Qgis::RenderUnit lineHeightUnit() const
Returns the units for the line height for text.
Stores a fragment of text along with formatting overrides to be used when rendering the fragment.
QString text() const
Returns the text content of the fragment.
const QgsTextCharacterFormat & characterFormat() const
Returns the character formatting for the fragment.
static constexpr double SUPERSCRIPT_SUBSCRIPT_FONT_SIZE_SCALING_FACTOR
Scale factor to use for super or subscript text which doesn't have an explicit font size set.
#define BUILTIN_UNREACHABLE
constexpr double SUPERSCRIPT_VERTICAL_BASELINE_ADJUSTMENT_FACTOR
constexpr double SUBSCRIPT_VERTICAL_BASELINE_ADJUSTMENT_FACTOR