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;
 
  241      const double thisLineHeightUsingAscentDescent = format.
lineHeightUnit() == Qgis::RenderUnit::Percentage ? ( format.
lineHeight() * ( maxBlockAscent + maxBlockDescent ) ) : lineHeightPainterUnits;
 
  242      const double thisLineHeightUsingLineSpacing = format.
lineHeightUnit() == Qgis::RenderUnit::Percentage ? ( format.
lineHeight() * maxLineSpacing ) : lineHeightPainterUnits;
 
  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;
 
  266    blockVerticalLineSpacing << ( format.
lineHeightUnit() == Qgis::RenderUnit::Percentage ? ( maxBlockMaxWidth * format.
lineHeight() ) : lineHeightPainterUnits );
 
  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 )
 
  349    case Qgis::TextOrientation::Horizontal:
 
  352        case Qgis::TextLayoutMode::Rectangle:
 
  354          return mDocumentSizePointRectMode;
 
  357          return mDocumentSizeCapHeightMode;
 
  360          return mDocumentSizeAscentMode;
 
  362        case Qgis::TextLayoutMode::Labeling:
 
  363          return mDocumentSizeLabelMode;
 
  367    case Qgis::TextOrientation::Vertical:
 
  368      return mDocumentSizeVerticalOrientation;
 
  369    case Qgis::TextOrientation::RotationBased:
 
  378  switch ( orientation )
 
  380    case Qgis::TextOrientation::Horizontal:
 
  383        case Qgis::TextLayoutMode::Rectangle:
 
  389        case Qgis::TextLayoutMode::Labeling:
 
  390          return mOuterBoundsLabelMode;
 
  394    case Qgis::TextOrientation::Vertical:
 
  395    case Qgis::TextOrientation::RotationBased:
 
  404  return mBlockWidths.value( blockIndex );
 
  409  return mBlockHeights.value( blockIndex );
 
  414  return mFirstLineCapHeight;
 
  421    case Qgis::TextLayoutMode::Rectangle:
 
  422      return mBaselineOffsetsRectMode.value( blockIndex );
 
  424      return mBaselineOffsetsCapHeightMode.value( blockIndex );
 
  426      return mBaselineOffsetsAscentBased.value( blockIndex );
 
  428      return mBaselineOffsetsPointMode.value( blockIndex );
 
  429    case Qgis::TextLayoutMode::Labeling:
 
  430      return mBaselineOffsetsLabelMode.value( blockIndex );
 
  437  return mFragmentHorizontalAdvance.value( blockIndex ).value( fragmentIndex );
 
  444    case Qgis::TextLayoutMode::Rectangle:
 
  447      return mFragmentVerticalOffsetsRectMode.value( blockIndex ).value( fragmentIndex );
 
  449      return mFragmentVerticalOffsetsPointMode.value( blockIndex ).value( fragmentIndex );
 
  450    case Qgis::TextLayoutMode::Labeling:
 
  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.
 
@ 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 ...
 
TextOrientation
Text orientations.
 
@ 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.
 
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