Bug: setDefaultMinimumHorizontalScaleFactor is ignored for juce::TextLayout

I’m using the following code to compute the height for my label:

int computeHeight(const juce::Font& font, juce::String text, int width)
{
    const auto factor = juce::Font::getDefaultMinimumHorizontalScaleFactor();
    juce::Font::setDefaultMinimumHorizontalScaleFactor(1.0);
    
    juce::AttributedString string(text);
    string.setFont(font);
    
    juce::TextLayout descriptionLayout;
    descriptionLayout.createLayout(string, static_cast<float>(width));
    
    const auto height =  descriptionLayout.getHeight();
    
    juce::Font::setDefaultMinimumHorizontalScaleFactor(factor);
    
    return height;
}

And using the resulting height to set the bounds for a Label with .setMinimumHorizontalScale(1.0f);. As you can see, I’ve also set Font::setDefaultMinimumHorizontalScaleFactor() to 1.0, which the documentation explicitly states is used when creating a text layout.

Yet, when running this (on Mac), my label looks like this:

image

Seems like the minimum scale factor simply isn’t taken into account, because when I don’t set it on my label, the text does fit in the same three lines, but is of course squashed.

image

Label is drawn using a GlyphArrangement rather than a TextLayout, which may be why you’re seeing different results here.

If you look at the implementation of Label::paint, you can see that it delegates to LnF::drawLabel. Then, the LnF computes the text area (which is smaller than the total area of the label, as the label has internal padding), and calls Graphics::drawFittedText using this area. drawFittedText is implemented using a GlyphArrangement.

I think it should be possible to query the necessary height for a label with something like this. Note that for custom LnF implementations, this may need to be revised.

int findHeight (const juce::Label& label)
{
    const auto textBounds = label.getBorderSize()
                                 .subtractedFrom (label.getBounds())
                                 .toFloat();

    const auto layout = [&]
    {
        juce::GlyphArrangement arrangement;
        arrangement.addFittedText (label.getFont(),
                                   label.getText(),
                                   textBounds.getX(),
                                   textBounds.getY(),
                                   textBounds.getWidth(),
                                   10000.0f,
                                   label.getJustificationType(),
                                   std::numeric_limits<int>::max(),
                                   label.getMinimumHorizontalScale());
        return arrangement;
    }();

    return label.getBorderSize()
                .addedTo (layout.getBoundingBox (0, layout.getNumGlyphs(), false)
                                .getSmallestIntegerContainer())
                .getHeight();
}

Ah, thank you so much @reuk! I think I’ll resort to using TextLayout to draw this “label” then, but I wouldn’t have gotten there without the distinction with GlyphArrangement.