AttributedString: Character Counting Bug with Font Ligatures

Here’s a fun one! In JUCE 8 I am experiencing what looks like a bug to do with font ligatures (e.g., a combined ‘ff’ into a single shape in some fonts). I’ve narrowed it down to this example using Proxima Nova:

#include <JuceHeader.h>

class MainComponent : public Component
{
public:
    MainComponent()
    {
        auto fonts = Font::findAllTypefaceNames();

        if (! fonts.contains ("Proxima Nova"))
            throw std::runtime_error (
                "\nPlease install the 'Proxima Nova Regular.otf' font to reproduce this example. See: \n"
                "https://github.com/roshinthomas/Proximanova-fonts/blob/master/Proxima%20Nova%20Regular.otf");

        Font font ("Proxima Nova", 18.0f, Font::plain);

        string.append ("Hello, World!\n", font.withHeight (36.0f).withStyle (Font::bold), Colours::black);
        string.append ("Different, World!\n", font, Colours::red);
        string.append ("Why is 'W' in 'Why' red?\n", [font] () mutable{ font.setTypefaceName ("Arial"); return font; }(), Colours::blue);
        string.append ("Is it the 'ff' ligature throwing off the counting?\n", font, Colours::red);

        setSize (320, 240);
    }

    ~MainComponent() override = default;

    void paint (Graphics& g) override
    {
        g.fillAll (Colours::lightgrey);
        string.draw (g, getLocalBounds().reduced (20).toFloat());
    }

private:
    AttributedString string;
};

I’m testing this with JUCE 8 using latest develop.

(I’m deliberately using the deprecated Font constructor so I can show this doesn’t happen in JUCE 7, using the FontOptions constructors yields the same results in JUCE 8.)

As the text suggest, the ‘W’ in the first ‘Why’ on line 3 is carried on in red from the previous line (and ‘I’ on the last line continues in blue):

Using JUCE 7.0.12 it renders correctly:

Thank you reporting this issue and providing the example code. This is indeed a problem caused by mishandling the ligature. We are working on a fix.

I see some related commits on develop today, is it worth giving this a try or is this still in progress?

Yes, these changes should also fix the problem described in this thread. Although you might want to wait for a C++20 fix that’s arriving soon. I’ll update this thread when it’s out.

1 Like

Great thanks, yeah I had to change the lamdba arguments for std::accumulate() to auto, const auto& in two places for our build system…

diff --git forkSrcPrefix/modules/juce_gui_basics/widgets/juce_TextEditor.cpp forkDstPrefix/modules/juce_gui_basics/widgets/juce_TextEditor.cpp
index 37742feea7f9ea1a979b1a36b21aeb27176a4151..5140fd839b4b21622935efa115f4079a52dc49b1 100644
--- forkSrcPrefix/modules/juce_gui_basics/widgets/juce_TextEditor.cpp
+++ forkDstPrefix/modules/juce_gui_basics/widgets/juce_TextEditor.cpp
@@ -106,7 +106,7 @@ struct TextEditor::RemoveAction final : public UndoableAction
         return std::accumulate (removedText.texts.begin(),
                                 removedText.texts.end(),
                                 0,
-                                [] (auto& sum, auto& value)
+                                [] (auto sum, const auto& value)
                                 {
                                     return sum + (int) value.getNumBytesAsUTF8();
                                 });
diff --git forkSrcPrefix/modules/juce_graphics/detail/juce_SimpleShapedText.cpp forkDstPrefix/modules/juce_graphics/detail/juce_SimpleShapedText.cpp
index 227edd00d36ab1fa46505d05944b49a820c9ee71..e560cab37955c1aa2e60a0d077df2da114d7176e 100644
--- forkSrcPrefix/modules/juce_graphics/detail/juce_SimpleShapedText.cpp
+++ forkDstPrefix/modules/juce_graphics/detail/juce_SimpleShapedText.cpp
@@ -1320,7 +1320,7 @@ void SimpleShapedText::shape (const String& data,
                                                         glyphSpansInLine.end(),
                                                         std::make_pair (std::numeric_limits<int64>::max(),
                                                                         std::numeric_limits<int64>::min()),
-                                                        [&] (auto& sum, auto& elem) -> std::pair<int64, int64>
+                                                        [&] (auto sum, const auto& elem) -> std::pair<int64, int64>
                                                         {
                                                             const auto r = elem.textRange + lineRange.getStart();
 

A fix is out on develop

1 Like