1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Graphics: Use cached glyph shaping when only the position of text changes

This commit is contained in:
Anthony Nicholls 2024-12-13 14:41:26 +00:00
parent 4f474d97f4
commit 880b76983e

View file

@ -55,17 +55,6 @@ static auto operator< (const Justification& a, const Justification& b)
//==============================================================================
namespace
{
struct ConfiguredArrangement
{
void draw (const Graphics& g) const
{
arrangement.draw (g, transform);
}
GlyphArrangement arrangement;
AffineTransform transform;
};
template <typename ArrangementArgs>
class GlyphArrangementCache final : public DeletedAtShutdown
{
@ -81,14 +70,14 @@ namespace
[[nodiscard]] auto get (ArrangementArgs&& args, ConfigureArrangement&& configureArrangement)
{
const ScopedTryLock stl (lock);
return stl.isLocked() ? cache.get (args, std::forward<ConfigureArrangement> (configureArrangement))
return stl.isLocked() ? cache.get (std::forward<ArrangementArgs> (args), std::forward<ConfigureArrangement> (configureArrangement))
: configureArrangement (args);
}
JUCE_DECLARE_SINGLETON_INLINE (GlyphArrangementCache<ArrangementArgs>, false)
private:
LruCache<ArrangementArgs, ConfiguredArrangement> cache;
LruCache<ArrangementArgs, GlyphArrangement> cache;
CriticalSection lock;
};
@ -336,36 +325,41 @@ void Graphics::drawSingleLineText (const String& text, const int startX, const i
struct ArrangementArgs
{
auto tie() const noexcept { return std::tie (font, text, startX, baselineY); }
auto tie() const noexcept { return std::tie (font, text); }
bool operator< (const ArrangementArgs& other) const { return tie() < other.tie(); }
const Font font;
const String text;
const int startX, baselineY, flags;
};
auto configureArrangement = [] (const ArrangementArgs& args)
{
AffineTransform transform;
GlyphArrangement arrangement;
arrangement.addLineOfText (args.font, args.text, (float) args.startX, (float) args.baselineY);
if (args.flags != Justification::left)
{
auto w = arrangement.getBoundingBox (0, -1, true).getWidth();
if ((args.flags & (Justification::horizontallyCentred | Justification::horizontallyJustified)) != 0)
w /= 2.0f;
transform = AffineTransform::translation (-w, 0);
}
return ConfiguredArrangement { std::move (arrangement), std::move (transform) };
arrangement.addLineOfText (args.font, args.text, 0.0f, 0.0f);
return arrangement;
};
GlyphArrangementCache<ArrangementArgs>::getInstance()->get ({ context.getFont(), text, startX, baselineY, flags },
std::move (configureArrangement))
.draw (*this);
using Cache = GlyphArrangementCache<ArrangementArgs>;
ArrangementArgs args { context.getFont(), text };
const auto arrangement = Cache::getInstance()->get (std::move (args), std::move (configureArrangement));
const auto transform = std::invoke ([&]
{
const auto t = AffineTransform::translation ((float) startX,
(float) baselineY);
if (flags == Justification::left)
return t;
auto w = arrangement.getBoundingBox (0, -1, true).getWidth();
if ((flags & (Justification::horizontallyCentred | Justification::horizontallyJustified)) != 0)
w /= 2.0f;
return t.followedBy (AffineTransform::translation (-w, 0));
});
arrangement.draw (*this, transform);
}
void Graphics::drawMultiLineText (const String& text, const int startX,
@ -377,12 +371,12 @@ void Graphics::drawMultiLineText (const String& text, const int startX,
struct ArrangementArgs
{
auto tie() const noexcept { return std::tie (font, text, startX, baselineY, maximumLineWidth, justification, leading); }
auto tie() const noexcept { return std::tie (font, text, maximumLineWidth, justification, leading); }
bool operator< (const ArrangementArgs& other) const { return tie() < other.tie(); }
const Font font;
const String text;
const int startX, baselineY, maximumLineWidth;
const int maximumLineWidth;
const Justification justification;
const float leading;
};
@ -391,14 +385,21 @@ void Graphics::drawMultiLineText (const String& text, const int startX,
{
GlyphArrangement arrangement;
arrangement.addJustifiedText (args.font, args.text,
(float) args.startX, (float) args.baselineY, (float) args.maximumLineWidth,
0.0f, 0.0f, (float) args.maximumLineWidth,
args.justification, args.leading);
return ConfiguredArrangement { std::move (arrangement), {} };
return arrangement;
};
GlyphArrangementCache<ArrangementArgs>::getInstance()->get ({ context.getFont(), text, startX, baselineY, maximumLineWidth, justification, leading },
std::move (configureArrangement))
.draw (*this);
ArrangementArgs args { context.getFont(),
text,
maximumLineWidth,
justification,
leading };
using Cache = GlyphArrangementCache<ArrangementArgs>;
Cache::getInstance()->get (std::move (args), std::move (configureArrangement))
.draw (*this, AffineTransform::translation ((float) startX,
(float) baselineY));
}
void Graphics::drawText (const String& text, Rectangle<float> area,
@ -409,12 +410,13 @@ void Graphics::drawText (const String& text, Rectangle<float> area,
struct ArrangementArgs
{
auto tie() const noexcept { return std::tie (font, text, area, justificationType, useEllipsesIfTooBig); }
auto tie() const noexcept { return std::tie (font, text, width, height, justificationType, useEllipsesIfTooBig); }
bool operator< (const ArrangementArgs& other) const { return tie() < other.tie(); }
const Font font;
const String text;
const Rectangle<float> area;
const float width;
const float height;
const Justification justificationType;
const bool useEllipsesIfTooBig;
};
@ -423,17 +425,25 @@ void Graphics::drawText (const String& text, Rectangle<float> area,
{
GlyphArrangement arrangement;
arrangement.addCurtailedLineOfText (args.font, args.text, 0.0f, 0.0f,
args.area.getWidth(), args.useEllipsesIfTooBig);
args.width, args.useEllipsesIfTooBig);
arrangement.justifyGlyphs (0, arrangement.getNumGlyphs(),
args.area.getX(), args.area.getY(), args.area.getWidth(), args.area.getHeight(),
0.0f, 0.0f,
args.width, args.height,
args.justificationType);
return ConfiguredArrangement { std::move (arrangement), {} };
return arrangement;
};
GlyphArrangementCache<ArrangementArgs>::getInstance()->get ({ context.getFont(), text, area, justificationType, useEllipsesIfTooBig },
std::move (configureArrangement))
.draw (*this);
ArrangementArgs args { context.getFont(),
text,
area.getWidth(),
area.getHeight(),
justificationType,
useEllipsesIfTooBig };
using Cache = GlyphArrangementCache<ArrangementArgs>;
Cache::getInstance()->get (std::move (args), std::move (configureArrangement))
.draw (*this, AffineTransform::translation (area.getX(), area.getY()));
}
void Graphics::drawText (const String& text, Rectangle<int> area,
@ -458,12 +468,13 @@ void Graphics::drawFittedText (const String& text, Rectangle<int> area,
struct ArrangementArgs
{
auto tie() const noexcept { return std::tie (font, text, area, justification, maximumNumberOfLines, minimumHorizontalScale); }
auto tie() const noexcept { return std::tie (font, text, width, height, justification, maximumNumberOfLines, minimumHorizontalScale); }
bool operator< (const ArrangementArgs& other) const noexcept { return tie() < other.tie(); }
const Font font;
const String text;
const Rectangle<float> area;
const float width;
const float height;
const Justification justification;
const int maximumNumberOfLines;
const float minimumHorizontalScale;
@ -473,17 +484,26 @@ void Graphics::drawFittedText (const String& text, Rectangle<int> area,
{
GlyphArrangement arrangement;
arrangement.addFittedText (args.font, args.text,
args.area.getX(), args.area.getY(),
args.area.getWidth(), args.area.getHeight(),
0.0f, 0.0f,
args.width, args.height,
args.justification,
args.maximumNumberOfLines,
args.minimumHorizontalScale);
return ConfiguredArrangement { std::move (arrangement), {} };
return arrangement;
};
GlyphArrangementCache<ArrangementArgs>::getInstance()->get ({ context.getFont(), text, area.toFloat(), justification, maximumNumberOfLines, minimumHorizontalScale },
std::move (configureArrangement))
.draw (*this);
ArrangementArgs args { context.getFont(),
text,
(float) area.getWidth(),
(float) area.getHeight(),
justification,
maximumNumberOfLines,
minimumHorizontalScale };
using Cache = GlyphArrangementCache<ArrangementArgs>;
Cache::getInstance()->get (std::move (args), std::move (configureArrangement))
.draw (*this, AffineTransform::translation ((float) area.getX(),
(float) area.getY()));
}
void Graphics::drawFittedText (const String& text, int x, int y, int width, int height,