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

TextLayout: Fixed some bugs setting stringRanges

This commit is contained in:
reuk 2019-08-08 17:00:42 +01:00 committed by Tom Poole
parent 76f3aec386
commit edf99d171f
4 changed files with 170 additions and 31 deletions

View file

@ -27,6 +27,11 @@
namespace juce
{
static String substring (const String& text, Range<int> range)
{
return text.substring (range.getStart(), range.getEnd());
}
TextLayout::Glyph::Glyph (int glyph, Point<float> anch, float w) noexcept
: glyphCode (glyph), anchor (anch), width (w)
{
@ -207,9 +212,9 @@ void TextLayout::ensureStorageAllocated (int numLinesNeeded)
lines.ensureStorageAllocated (numLinesNeeded);
}
void TextLayout::addLine (Line* line)
void TextLayout::addLine (std::unique_ptr<Line> line)
{
lines.add (line);
lines.add (line.release());
}
void TextLayout::draw (Graphics& g, Rectangle<float> area) const
@ -221,9 +226,9 @@ void TextLayout::draw (Graphics& g, Rectangle<float> area) const
auto clipTop = clip.getY() - origin.y;
auto clipBottom = clip.getBottom() - origin.y;
for (auto* line : lines)
for (auto& line : *this)
{
auto lineRangeY = line->getLineBoundsY();
auto lineRangeY = line.getLineBoundsY();
if (lineRangeY.getEnd() < clipTop)
continue;
@ -231,9 +236,9 @@ void TextLayout::draw (Graphics& g, Rectangle<float> area) const
if (lineRangeY.getStart() > clipBottom)
break;
auto lineOrigin = origin + line->lineOrigin;
auto lineOrigin = origin + line.lineOrigin;
for (auto* run : line->runs)
for (auto* run : line.runs)
{
context.setFont (run->font);
context.setFill (run->colour);
@ -363,8 +368,8 @@ namespace TextLayoutHelpers
Array<float> xOffsets;
t.font.getGlyphPositions (getTrimmedEndIfNotAllWhitespace (t.text), newGlyphs, xOffsets);
if (currentRun == nullptr) currentRun .reset (new TextLayout::Run());
if (currentLine == nullptr) currentLine.reset (new TextLayout::Line());
if (currentRun == nullptr) currentRun = std::make_unique<TextLayout::Run>();
if (currentLine == nullptr) currentLine = std::make_unique<TextLayout::Line>();
if (newGlyphs.size() > 0)
{
@ -389,9 +394,10 @@ namespace TextLayoutHelpers
charPosition += newGlyphs.size();
}
if (t.isWhitespace || t.isNewLine)
else if (t.isWhitespace || t.isNewLine)
{
++charPosition;
}
if (auto* nextToken = tokens[i + 1])
{
@ -404,13 +410,13 @@ namespace TextLayoutHelpers
if (t.line != nextToken->line)
{
if (currentRun == nullptr)
currentRun.reset (new TextLayout::Run());
currentRun = std::make_unique<TextLayout::Run>();
addRun (*currentLine, currentRun.release(), t, runStartPosition, charPosition);
currentLine->stringRange = { lineStartPosition, charPosition };
if (! needToSetLineOrigin)
layout.addLine (currentLine.release());
layout.addLine (std::move (currentLine));
runStartPosition = charPosition;
lineStartPosition = charPosition;
@ -423,7 +429,7 @@ namespace TextLayoutHelpers
currentLine->stringRange = { lineStartPosition, charPosition };
if (! needToSetLineOrigin)
layout.addLine (currentLine.release());
layout.addLine (std::move (currentLine));
needToSetLineOrigin = true;
}
@ -434,14 +440,14 @@ namespace TextLayoutHelpers
auto totalW = layout.getWidth();
bool isCentred = (text.getJustification().getFlags() & Justification::horizontallyCentred) != 0;
for (int i = 0; i < layout.getNumLines(); ++i)
for (auto& line : layout)
{
auto dx = totalW - layout.getLine(i).getLineBoundsX().getLength();
auto dx = totalW - line.getLineBoundsX().getLength();
if (isCentred)
dx /= 2.0f;
layout.getLine(i).lineOrigin.x += dx;
line.lineOrigin.x += dx;
}
}
}
@ -560,7 +566,7 @@ namespace TextLayoutHelpers
{
auto& attr = text.getAttribute (i);
appendText (text.getText().substring (attr.range.getStart(), attr.range.getEnd()),
appendText (substring (text.getText(), attr.range),
attr.font, attr.colour);
}
}
@ -611,4 +617,66 @@ void TextLayout::recalculateSize()
}
}
//==============================================================================
#if JUCE_UNIT_TESTS
struct TextLayoutTests : public UnitTest
{
TextLayoutTests()
: UnitTest ("Text Layout", UnitTestCategories::text)
{}
static TextLayout createLayout (StringRef text, float width)
{
Font fontToUse (12.0f);
AttributedString string (text);
string.setFont (std::move (fontToUse));
TextLayout layout;
layout.createLayout (std::move (string), width);
return layout;
}
void testLineBreaks (const String& line, float width, const StringArray& expected)
{
const auto layout = createLayout (line, width);
beginTest ("A line is split into expected pieces");
{
expectEquals (layout.getNumLines(), expected.size());
const auto limit = jmin (layout.getNumLines(), expected.size());
for (int i = 0; i != limit; ++i)
expectEquals (substring (line, layout.getLine (i).stringRange), expected[i]);
}
}
void runTest() override
{
const String shortLine ("hello world");
testLineBreaks (shortLine, 1.0e7f, { shortLine });
testLineBreaks ("this line should be split",
60.0f,
{ "this line ",
"should be ",
"split" });
testLineBreaks ("these\nlines \nhave\n weird \n spacing ",
80.0f,
{ "these\n",
"lines \n",
"have\n",
" weird \n",
" spacing " });
}
};
static TextLayoutTests textLayoutTests;
#endif
} // namespace juce