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

Add ShapedText::accessTogetherWith and remove ShapedText::access

Since the original function template has been exposed, we can now use it
directly. Also ShapedText::Detail has been removed, because it wouldn't
work across module boundaries.
This commit is contained in:
attila 2025-01-28 17:55:30 +01:00 committed by Attila Szarvas
parent 1b595311d0
commit fab1de34ab
6 changed files with 77 additions and 114 deletions

View file

@ -214,8 +214,8 @@ static float getCrossAxisStartingAnchor (Justification justification,
return minimumTop;
}
JustifiedText::JustifiedText (const SimpleShapedText& t, const ShapedTextOptions& options)
: shapedText (t)
JustifiedText::JustifiedText (const SimpleShapedText* t, const ShapedTextOptions& options)
: shapedText (*t)
{
const auto leading = options.getLeading() - 1.0f;
@ -443,32 +443,26 @@ JustifiedText::JustifiedText (const SimpleShapedText& t, const ShapedTextOptions
realign.extraWhitespaceAdvance);
}
template <typename Callable>
void JustifiedText::access (Callable&& callback) const
{
accessTogetherWith (std::forward<Callable> (callback));
}
void drawJustifiedText (const JustifiedText& text, const Graphics& g, AffineTransform transform)
{
auto& context = g.getInternalContext();
context.saveState();
const ScopeGuard restoreGraphicsContext { [&context] { context.restoreState(); } };
text.access ([&] (auto glyphs, auto positions, auto font, auto, auto)
{
if (context.getFont() != font)
context.setFont (font);
text.accessTogetherWith ([&] (auto glyphs, auto positions, auto font, auto, auto)
{
if (context.getFont() != font)
context.setFont (font);
std::vector<uint16_t> glyphIds (glyphs.size());
std::vector<uint16_t> glyphIds (glyphs.size());
std::transform (glyphs.begin(),
glyphs.end(),
glyphIds.begin(),
[] (auto& glyph) { return (uint16_t) glyph.glyphId; });
std::transform (glyphs.begin(),
glyphs.end(),
glyphIds.begin(),
[] (auto& glyph) { return (uint16_t) glyph.glyphId; });
context.drawGlyphs (glyphIds, positions, transform);
});
context.drawGlyphs (glyphIds, positions, transform);
});
}
} // namespace juce::detail

View file

@ -57,8 +57,26 @@ private:
};
public:
JustifiedText (const SimpleShapedText& t, const ShapedTextOptions& options);
JustifiedText (const SimpleShapedText* t, const ShapedTextOptions& options);
/* Provides access to the data stored in the ShapedText.
The provided callable will be called multiple times for "uniform glyph runs", for which all
callback parameters are the same.
Between each subsequent callback at least one of the provided parameters will be different.
The callbacks happen in visual order i.e. left to right, which is irrespective of the
underlying text's writing direction.
The callback parameters in order are:
- the glyphs
- the positions for each glyph in the previous parameter
- the Font with which these glyphs should be rendered
- the range in all glyphs this ShapedText object holds, that correspond to the current glyphs
- a line number which increases by one for each new line
- followed by any number of ValueType parameters for the supplied RangedValues<ValueType> arguments
*/
template <typename Callable, typename... RangedValues>
void accessTogetherWith (Callable&& callback, RangedValues&&... rangedValues) const
{
@ -115,17 +133,6 @@ public:
}
}
/* The callback receives (Span<const ShapedGlyph> glyphs,
Span<Point<float>> positions,
Font font,
Range<int64> glyphRange,
int64 lineNumber) // So far this has been indexed from 0 per SimpleShapedText
// object, but maybe we'll find we want global text level
// line numbers, so only assume they are increasing by one
*/
template <typename Callable>
void access (Callable&& callback) const;
/* This is how much cumulative widths glyphs take up in each line. Whether the trailing
whitespace is included depends on the ShapedTextOptions::getWhitespaceShouldFitInLine()
setting.

View file

@ -44,11 +44,6 @@ public:
{
}
void access (const std::function<void (Span<const ShapedGlyph>, Span<Point<float>>, Font, Range<int64>, int64)>& cb) const
{
justifiedText.access (cb);
}
void draw (const Graphics& g, AffineTransform transform) const
{
drawJustifiedText (justifiedText, g, transform);
@ -78,7 +73,7 @@ private:
ShapedTextOptions options;
String text;
SimpleShapedText simpleShapedText { &text, options };
JustifiedText justifiedText { simpleShapedText, options };
JustifiedText justifiedText { &simpleShapedText, options };
};
ShapedText::ShapedText() : ShapedText ("", {})
@ -94,11 +89,6 @@ ShapedText::ShapedText (String text, Options options)
impl = std::make_shared<Impl> (std::move (text), std::move (options));
}
void ShapedText::access (const std::function<void (Span<const ShapedGlyph>, Span<Point<float>>, Font, Range<int64>, int64)>& cb) const
{
impl->access (cb);
}
void ShapedText::draw (const Graphics& g, AffineTransform transform) const
{
impl->draw (g, transform);
@ -119,24 +109,8 @@ Span<const float> ShapedText::getMinimumRequiredWidthForLines() const
return impl->getMinimumRequiredWidthForLines();
}
class ShapedText::Detail
{
public:
explicit Detail (const ShapedText* shapedTextIn)
: shapedText (*shapedTextIn)
{}
const JustifiedText& ShapedText::getJustifiedText() const { return impl->getJustifiedText(); }
auto& getJustifiedText() const { return shapedText.impl->getJustifiedText(); }
auto& getSimpleShapedText() const { return shapedText.impl->getSimpleShapedText(); }
private:
const ShapedText& shapedText;
};
ShapedText::Detail ShapedText::getDetail() const
{
return Detail { this };
}
const SimpleShapedText& ShapedText::getSimpleShapedText() const { return impl->getSimpleShapedText(); }
} // namespace juce::detail

View file

@ -35,7 +35,7 @@
namespace juce::detail
{
/** Class that can visually shape a Unicode string provided a list of Fonts corresponding to
/* Class that can visually shape a Unicode string provided a list of Fonts corresponding to
sub-ranges of the string.
*/
class JUCE_API ShapedText
@ -49,17 +49,17 @@ public:
ShapedText (String text, Options options);
/** Returns the text which was used to construct this object. */
/* Returns the text which was used to construct this object. */
const String& getText() const;
/** Returns the text's codepoint range, to which the glyph under the provided index belongs.
/* Returns the text's codepoint range, to which the glyph under the provided index belongs.
This range will have a length of at least one, and potentially more than one if ligatures
are enabled.
*/
Range<int64> getTextRange (int64 glyphIndex) const;
/** Returns the widths for each line, that the glyphs would require to be rendered without being
/* Returns the widths for each line, that the glyphs would require to be rendered without being
truncated. This will or will not include the space required by trailing whitespaces in the
line based on the ShapedTextOptions::withTrailingWhitespacesShouldFit() value.
@ -68,33 +68,22 @@ public:
*/
Span<const float> getMinimumRequiredWidthForLines() const;
/** Provides access to the data stored in the ShapedText.
/* @see JustifiedText::accessTogetherWith */
template <typename Callable, typename... RangedValues>
void accessTogetherWith (Callable&& callback, RangedValues&&... rangedValues) const
{
getJustifiedText().accessTogetherWith (std::forward<Callable> (callback),
std::forward<RangedValues> (rangedValues)...);
}
The provided function callback will be called multiple times for "uniform glyph runs", for which all
callback parameters are the same.
Between each subsequent callback at least one of the provided parameters will be different.
The callbacks happen in visual order i.e. left to right, which is irrespective of the
underlying text's writing direction.
The callback parameters in order are:
- the glyphs
- the positions for each glyph in the previous parameter
- the Font with which these glyphs should be rendered
- the range in all glyphs this ShapedText object holds, that correspond to the current glyphs
- a line number which increases by one for each new line
*/
void access (const std::function<void (Span<const ShapedGlyph>, Span<Point<float>>, Font, Range<int64>, int64)>&) const;
/** Draws the text. */
/* Draws the text. */
void draw (const Graphics& g, AffineTransform transform) const;
/** @internal */
class Detail;
/* @internal */
const JustifiedText& getJustifiedText() const;
/** @internal */
Detail getDetail() const;
/* @internal */
const SimpleShapedText& getSimpleShapedText() const;
private:
class Impl;

View file

@ -173,26 +173,26 @@ void GlyphArrangement::addLineOfText (const Font& font, const String& text, floa
static void addGlyphsFromShapedText (GlyphArrangement& ga, const detail::ShapedText& st, float x, float y)
{
st.access ([&] (auto shapedGlyphs, auto positions, auto font, auto glyphRange, auto)
{
for (size_t i = 0; i < shapedGlyphs.size(); ++i)
{
const auto glyphIndex = (int64) i + glyphRange.getStart();
st.accessTogetherWith ([&] (auto shapedGlyphs, auto positions, auto font, auto glyphRange, auto)
{
for (size_t i = 0; i < shapedGlyphs.size(); ++i)
{
const auto glyphIndex = (int64) i + glyphRange.getStart();
auto& glyph = shapedGlyphs[i];
auto& position = positions[i];
auto& glyph = shapedGlyphs[i];
auto& position = positions[i];
PositionedGlyph pg { font,
st.getText()[(int) st.getTextRange (glyphIndex).getStart()],
(int) glyph.glyphId,
position.getX() + x,
position.getY() + y,
glyph.advance.getX(),
glyph.whitespace };
PositionedGlyph pg { font,
st.getText()[(int) st.getTextRange (glyphIndex).getStart()],
(int) glyph.glyphId,
position.getX() + x,
position.getY() + y,
glyph.advance.getX(),
glyph.whitespace };
ga.addGlyph (std::move (pg));
}
});
ga.addGlyph (std::move (pg));
}
});
}
void GlyphArrangement::addCurtailedLineOfText (const Font& font, const String& text,

View file

@ -362,9 +362,9 @@ static Range<int64> getLineInputRange (const detail::ShapedText& st, int64 lineN
{
using namespace detail;
return getInputRange (st, ShapedText::Detail { &st }.getSimpleShapedText()
.getLineNumbers()
.getItem ((size_t) lineNumber).range);
return getInputRange (st, st.getSimpleShapedText()
.getLineNumbers()
.getItem ((size_t) lineNumber).range);
}
struct MaxFontAscentAndDescent
@ -375,7 +375,7 @@ struct MaxFontAscentAndDescent
static MaxFontAscentAndDescent getMaxFontAscentAndDescentInEnclosingLine (const detail::ShapedText& st,
Range<int64> lineChunkRange)
{
const auto sst = detail::ShapedText::Detail { &st }.getSimpleShapedText();
const auto sst = st.getSimpleShapedText();
const auto lineRange = sst.getLineNumbers()
.getItemWithEnclosingRange (lineChunkRange.getStart())->range;
@ -435,13 +435,12 @@ void TextLayout::createStandardLayout (const AttributedString& text)
if (text.getWordWrap() != AttributedString::none)
shapedTextOptions = shapedTextOptions.withMaxWidth (width);
ShapedText shapedText { text.getText(), shapedTextOptions };
ShapedText st { text.getText(), shapedTextOptions };
std::optional<int64> lastLineNumber;
std::unique_ptr<Line> line;
auto& jt = ShapedText::Detail { &shapedText }.getJustifiedText();
jt.accessTogetherWith ([&] (Span<const ShapedGlyph> glyphs,
st.accessTogetherWith ([&] (Span<const ShapedGlyph> glyphs,
Span<Point<float>> positions,
Font font,
Range<int64> glyphRange,
@ -453,10 +452,10 @@ void TextLayout::createStandardLayout (const AttributedString& text)
if (line != nullptr)
addLine (std::move (line));
const auto ascentAndDescent = getMaxFontAscentAndDescentInEnclosingLine (shapedText,
const auto ascentAndDescent = getMaxFontAscentAndDescentInEnclosingLine (st,
glyphRange);
line = std::make_unique<Line> (castTo<int> (getLineInputRange (shapedText, lineNumber)),
line = std::make_unique<Line> (castTo<int> (getLineInputRange (st, lineNumber)),
positions[0],
ascentAndDescent.ascent,
ascentAndDescent.descent,
@ -464,7 +463,7 @@ void TextLayout::createStandardLayout (const AttributedString& text)
0);
}
auto run = std::make_unique<Run> (castTo<int> (getInputRange (shapedText, glyphRange)), 0);
auto run = std::make_unique<Run> (castTo<int> (getInputRange (st, glyphRange)), 0);
run->font = font;
run->colour = colour;