1
0
Fork 0
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:
jules 2017-10-31 17:30:50 +00:00
parent 85d9a4cf90
commit 0933ce4be8
2 changed files with 59 additions and 34 deletions

View file

@ -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)
{

View file

@ -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. */