mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Optimisation for drawing of large TextLayouts that go beyond the top and bottom of the graphics clip region
This commit is contained in:
parent
85d9a4cf90
commit
0933ce4be8
2 changed files with 59 additions and 34 deletions
|
|
@ -27,7 +27,7 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
TextLayout::Glyph::Glyph (const int glyph, Point<float> anch, float w) noexcept
|
||||
TextLayout::Glyph::Glyph (int glyph, Point<float> anch, float w) noexcept
|
||||
: glyphCode (glyph), anchor (anch), width (w)
|
||||
{
|
||||
}
|
||||
|
|
@ -69,6 +69,29 @@ TextLayout::Run::Run (const Run& other)
|
|||
|
||||
TextLayout::Run::~Run() noexcept {}
|
||||
|
||||
Range<float> TextLayout::Run::getRunBoundsX() const noexcept
|
||||
{
|
||||
Range<float> range;
|
||||
bool isFirst = true;
|
||||
|
||||
for (auto& glyph : glyphs)
|
||||
{
|
||||
Range<float> r (glyph.anchor.x, glyph.anchor.x + glyph.width);
|
||||
|
||||
if (isFirst)
|
||||
{
|
||||
isFirst = false;
|
||||
range = r;
|
||||
}
|
||||
else
|
||||
{
|
||||
range = range.getUnionWith (r);
|
||||
}
|
||||
}
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
TextLayout::Line::Line() noexcept
|
||||
: ascent (0.0f), descent (0.0f), leading (0.0f)
|
||||
|
|
@ -101,19 +124,16 @@ Range<float> TextLayout::Line::getLineBoundsX() const noexcept
|
|||
|
||||
for (auto* run : runs)
|
||||
{
|
||||
for (auto& glyph : run->glyphs)
|
||||
{
|
||||
Range<float> runRange (glyph.anchor.x, glyph.anchor.x + glyph.width);
|
||||
auto runRange = run->getRunBoundsX();
|
||||
|
||||
if (isFirst)
|
||||
{
|
||||
isFirst = false;
|
||||
range = runRange;
|
||||
}
|
||||
else
|
||||
{
|
||||
range = range.getUnionWith (runRange);
|
||||
}
|
||||
if (isFirst)
|
||||
{
|
||||
isFirst = false;
|
||||
range = runRange;
|
||||
}
|
||||
else
|
||||
{
|
||||
range = range.getUnionWith (runRange);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -177,7 +197,7 @@ TextLayout::~TextLayout()
|
|||
{
|
||||
}
|
||||
|
||||
TextLayout::Line& TextLayout::getLine (const int index) const
|
||||
TextLayout::Line& TextLayout::getLine (int index) const noexcept
|
||||
{
|
||||
return *lines.getUnchecked (index);
|
||||
}
|
||||
|
|
@ -194,12 +214,23 @@ void TextLayout::addLine (Line* line)
|
|||
|
||||
void TextLayout::draw (Graphics& g, Rectangle<float> area) const
|
||||
{
|
||||
auto origin = justification.appliedToRectangle (Rectangle<float> (width, getHeight()), area).getPosition();
|
||||
auto origin = justification.appliedToRectangle ({ width, getHeight() }, area).getPosition();
|
||||
|
||||
auto& context = g.getInternalContext();
|
||||
auto& context = g.getInternalContext();
|
||||
auto clip = context.getClipBounds();
|
||||
auto clipTop = (float) clip.getY();
|
||||
auto clipBottom = (float) clip.getBottom();
|
||||
|
||||
for (auto* line : lines)
|
||||
{
|
||||
auto lineRangeY = line->getLineBoundsY();
|
||||
|
||||
if (lineRangeY.getEnd() < clipTop)
|
||||
continue;
|
||||
|
||||
if (lineRangeY.getStart() > clipBottom)
|
||||
break;
|
||||
|
||||
auto lineOrigin = origin + line->lineOrigin;
|
||||
|
||||
for (auto* run : line->runs)
|
||||
|
|
@ -213,16 +244,7 @@ void TextLayout::draw (Graphics& g, Rectangle<float> area) const
|
|||
|
||||
if (run->font.isUnderlined())
|
||||
{
|
||||
Range<float> runExtent;
|
||||
|
||||
for (auto& glyph : run->glyphs)
|
||||
{
|
||||
Range<float> glyphRange (glyph.anchor.x, glyph.anchor.x + glyph.width);
|
||||
|
||||
runExtent = runExtent.isEmpty() ? glyphRange
|
||||
: runExtent.getUnionWith (glyphRange);
|
||||
}
|
||||
|
||||
auto runExtent = run->getRunBoundsX();
|
||||
auto lineThickness = run->font.getDescent() * 0.3f;
|
||||
|
||||
context.fillRect ({ runExtent.getStart() + lineOrigin.x, lineOrigin.y + lineThickness * 2.0f,
|
||||
|
|
@ -385,7 +407,7 @@ namespace TextLayoutHelpers
|
|||
currentRun = new TextLayout::Run();
|
||||
|
||||
addRun (*currentLine, currentRun.release(), t, runStartPosition, charPosition);
|
||||
currentLine->stringRange = Range<int> (lineStartPosition, charPosition);
|
||||
currentLine->stringRange = { lineStartPosition, charPosition };
|
||||
|
||||
if (! needToSetLineOrigin)
|
||||
layout.addLine (currentLine.release());
|
||||
|
|
@ -398,7 +420,7 @@ namespace TextLayoutHelpers
|
|||
else
|
||||
{
|
||||
addRun (*currentLine, currentRun.release(), t, runStartPosition, charPosition);
|
||||
currentLine->stringRange = Range<int> (lineStartPosition, charPosition);
|
||||
currentLine->stringRange = { lineStartPosition, charPosition };
|
||||
|
||||
if (! needToSetLineOrigin)
|
||||
layout.addLine (currentLine.release());
|
||||
|
|
@ -426,7 +448,7 @@ namespace TextLayoutHelpers
|
|||
|
||||
private:
|
||||
static void addRun (TextLayout::Line& glyphLine, TextLayout::Run* glyphRun,
|
||||
const Token& t, const int start, const int end)
|
||||
const Token& t, int start, int end)
|
||||
{
|
||||
glyphRun->stringRange = { start, end };
|
||||
glyphRun->font = t.font;
|
||||
|
|
@ -436,7 +458,7 @@ namespace TextLayoutHelpers
|
|||
glyphLine.runs.add (glyphRun);
|
||||
}
|
||||
|
||||
static int getCharacterType (const juce_wchar c) noexcept
|
||||
static int getCharacterType (juce_wchar c) noexcept
|
||||
{
|
||||
if (c == '\r' || c == '\n')
|
||||
return 0;
|
||||
|
|
@ -482,7 +504,7 @@ namespace TextLayoutHelpers
|
|||
tokens.add (new Token (currentString, font, colour, lastCharType == 2));
|
||||
}
|
||||
|
||||
void layoutRuns (const float maxWidth, const float extraLineSpacing, const AttributedString::WordWrap wordWrap)
|
||||
void layoutRuns (float maxWidth, float extraLineSpacing, AttributedString::WordWrap wordWrap)
|
||||
{
|
||||
float x = 0, y = 0, h = 0;
|
||||
int i;
|
||||
|
|
@ -500,7 +522,7 @@ namespace TextLayoutHelpers
|
|||
if (nextTok == nullptr)
|
||||
break;
|
||||
|
||||
const bool tokenTooLarge = (x + nextTok->area.getWidth() > maxWidth);
|
||||
bool tokenTooLarge = (x + nextTok->area.getWidth() > maxWidth);
|
||||
|
||||
if (t.isNewLine || ((! nextTok->isWhitespace) && (tokenTooLarge && wordWrap != AttributedString::none)))
|
||||
{
|
||||
|
|
@ -516,7 +538,7 @@ namespace TextLayoutHelpers
|
|||
++totalLines;
|
||||
}
|
||||
|
||||
void setLastLineHeight (int i, const float height) noexcept
|
||||
void setLastLineHeight (int i, float height) noexcept
|
||||
{
|
||||
while (--i >= 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -119,6 +119,9 @@ public:
|
|||
Run (Range<int> stringRange, int numGlyphsToPreallocate);
|
||||
~Run() noexcept;
|
||||
|
||||
/** Returns the X position range which contains all the glyphs in this run. */
|
||||
Range<float> getRunBoundsX() const noexcept;
|
||||
|
||||
Font font; /**< The run's font. */
|
||||
Colour colour; /**< The run's colour. */
|
||||
Array<Glyph> glyphs; /**< The glyphs in this run. */
|
||||
|
|
@ -171,7 +174,7 @@ public:
|
|||
int getNumLines() const noexcept { return lines.size(); }
|
||||
|
||||
/** Returns one of the lines. */
|
||||
Line& getLine (int index) const;
|
||||
Line& getLine (int index) const noexcept;
|
||||
|
||||
/** Adds a line to the layout. The layout will take ownership of this line object
|
||||
and will delete it when it is no longer needed. */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue