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

Modernised some code in some text layout classes, and made TextLayout draw underlining where the font asks for it

This commit is contained in:
jules 2017-04-06 10:55:48 +01:00
parent f8ae98894f
commit 89ad7eb0a4
3 changed files with 79 additions and 80 deletions

View file

@ -48,7 +48,7 @@ TextLayout::Run::Run() noexcept
{
}
TextLayout::Run::Run (Range<int> range, const int numGlyphsToPreallocate)
TextLayout::Run::Run (Range<int> range, int numGlyphsToPreallocate)
: colour (0xff000000), stringRange (range)
{
glyphs.ensureStorageAllocated (numGlyphsToPreallocate);
@ -94,31 +94,20 @@ Range<float> TextLayout::Line::getLineBoundsX() const noexcept
Range<float> range;
bool isFirst = true;
for (int i = runs.size(); --i >= 0;)
for (auto* run : runs)
{
const Run& run = *runs.getUnchecked(i);
if (run.glyphs.size() > 0)
for (auto& glyph : run->glyphs)
{
float minX = run.glyphs.getReference(0).anchor.x;
float maxX = minX;
for (int j = run.glyphs.size(); --j >= 0;)
{
const Glyph& glyph = run.glyphs.getReference (j);
const float x = glyph.anchor.x;
minX = jmin (minX, x);
maxX = jmax (maxX, x + glyph.width);
}
Range<float> runRange (glyph.anchor.x, glyph.anchor.x + glyph.width);
if (isFirst)
{
isFirst = false;
range = Range<float> (minX, maxX);
range = runRange;
}
else
{
range = range.getUnionWith (Range<float> (minX, maxX));
range = range.getUnionWith (runRange);
}
}
}
@ -134,10 +123,10 @@ Range<float> TextLayout::Line::getLineBoundsY() const noexcept
Rectangle<float> TextLayout::Line::getLineBounds() const noexcept
{
const Range<float> x (getLineBoundsX()),
y (getLineBoundsY());
auto x = getLineBoundsX();
auto y = getLineBoundsY();
return Rectangle<float> (x.getStart(), y.getStart(), x.getLength(), y.getLength());
return { x.getStart(), y.getStart(), x.getLength(), y.getLength() };
}
//==============================================================================
@ -198,28 +187,40 @@ void TextLayout::addLine (Line* line)
lines.add (line);
}
void TextLayout::draw (Graphics& g, const Rectangle<float>& area) const
void TextLayout::draw (Graphics& g, Rectangle<float> area) const
{
const Point<float> origin (justification.appliedToRectangle (Rectangle<float> (width, getHeight()), area).getPosition());
auto origin = justification.appliedToRectangle (Rectangle<float> (width, getHeight()), area).getPosition();
LowLevelGraphicsContext& context = g.getInternalContext();
auto& context = g.getInternalContext();
for (int i = 0; i < lines.size(); ++i)
for (auto* line : lines)
{
const Line& line = getLine (i);
const Point<float> lineOrigin (origin + line.lineOrigin);
auto lineOrigin = origin + line->lineOrigin;
for (int j = 0; j < line.runs.size(); ++j)
for (auto* run : line->runs)
{
const Run& run = *line.runs.getUnchecked (j);
context.setFont (run.font);
context.setFill (run.colour);
context.setFont (run->font);
context.setFill (run->colour);
for (int k = 0; k < run.glyphs.size(); ++k)
{
const Glyph& glyph = run.glyphs.getReference (k);
for (auto& glyph : run->glyphs)
context.drawGlyph (glyph.glyphCode, AffineTransform::translation (lineOrigin.x + glyph.anchor.x,
lineOrigin.y + glyph.anchor.y));
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);
}
const float lineThickness = run->font.getDescent() * 0.3f;
context.fillRect ({ runExtent.getStart() + lineOrigin.x, lineOrigin.y + lineThickness * 2.0f,
runExtent.getLength(), lineThickness });
}
}
}
@ -287,7 +288,7 @@ namespace TextLayoutHelpers
{
struct Token
{
Token (const String& t, const Font& f, Colour c, const bool whitespace)
Token (const String& t, const Font& f, Colour c, bool whitespace)
: text (t), font (f), colour (c),
area (font.getStringWidthFloat (t), f.getHeight()),
isWhitespace (whitespace),
@ -308,7 +309,7 @@ namespace TextLayoutHelpers
struct TokenList
{
TokenList() noexcept : totalLines (0) {}
TokenList() noexcept {}
void createLayout (const AttributedString& text, TextLayout& layout)
{
@ -328,7 +329,7 @@ namespace TextLayoutHelpers
for (int i = 0; i < tokens.size(); ++i)
{
const Token& t = *tokens.getUnchecked (i);
auto& t = *tokens.getUnchecked (i);
Array<int> newGlyphs;
Array<float> xOffsets;
@ -364,19 +365,7 @@ namespace TextLayoutHelpers
if (t.isWhitespace || t.isNewLine)
++charPosition;
const Token* const nextToken = tokens [i + 1];
if (nextToken == nullptr) // this is the last token
{
addRun (*currentLine, currentRun.release(), t, runStartPosition, charPosition);
currentLine->stringRange = Range<int> (lineStartPosition, charPosition);
if (! needToSetLineOrigin)
layout.addLine (currentLine.release());
needToSetLineOrigin = true;
}
else
if (auto* nextToken = tokens [i + 1])
{
if (t.font != nextToken->font || t.colour != nextToken->colour)
{
@ -400,6 +389,16 @@ namespace TextLayoutHelpers
needToSetLineOrigin = true;
}
}
else
{
addRun (*currentLine, currentRun.release(), t, runStartPosition, charPosition);
currentLine->stringRange = Range<int> (lineStartPosition, charPosition);
if (! needToSetLineOrigin)
layout.addLine (currentLine.release());
needToSetLineOrigin = true;
}
}
if ((text.getJustification().getFlags() & (Justification::right | Justification::horizontallyCentred)) != 0)
@ -423,7 +422,7 @@ namespace TextLayoutHelpers
static void addRun (TextLayout::Line& glyphLine, TextLayout::Run* glyphRun,
const Token& t, const int start, const int end)
{
glyphRun->stringRange = Range<int> (start, end);
glyphRun->stringRange = { start, end };
glyphRun->font = t.font;
glyphRun->colour = t.colour;
glyphLine.ascent = jmax (glyphLine.ascent, t.font.getAscent());
@ -441,7 +440,7 @@ namespace TextLayoutHelpers
void appendText (const String& stringText, const Font& font, Colour colour)
{
String::CharPointerType t (stringText.getCharPointer());
auto t = stringText.getCharPointer();
String currentString;
int lastCharType = 0;
@ -483,13 +482,13 @@ namespace TextLayoutHelpers
for (i = 0; i < tokens.size(); ++i)
{
Token& t = *tokens.getUnchecked(i);
auto& t = *tokens.getUnchecked(i);
t.area.setPosition (x, y);
t.line = totalLines;
x += t.area.getWidth();
h = jmax (h, t.area.getHeight() + extraLineSpacing);
const Token* const nextTok = tokens[i + 1];
auto* nextTok = tokens[i + 1];
if (nextTok == nullptr)
break;
@ -514,7 +513,7 @@ namespace TextLayoutHelpers
{
while (--i >= 0)
{
Token& tok = *tokens.getUnchecked (i);
auto& tok = *tokens.getUnchecked (i);
if (tok.line == totalLines)
tok.lineHeight = height;
@ -530,7 +529,7 @@ namespace TextLayoutHelpers
for (int i = 0; i < numAttributes; ++i)
{
const AttributedString::Attribute& attr = text.getAttribute (i);
auto& attr = text.getAttribute (i);
appendText (text.getText().substring (attr.range.getStart(), attr.range.getEnd()),
attr.font, attr.colour);
@ -539,7 +538,8 @@ namespace TextLayoutHelpers
static String getTrimmedEndIfNotAllWhitespace (const String& s)
{
String trimmed (s.trimEnd());
auto trimmed = s.trimEnd();
if (trimmed.isEmpty() && s.isNotEmpty())
trimmed = s.replaceCharacters ("\r\n\t", " ");
@ -547,7 +547,7 @@ namespace TextLayoutHelpers
}
OwnedArray<Token> tokens;
int totalLines;
int totalLines = 0;
JUCE_DECLARE_NON_COPYABLE (TokenList)
};
@ -562,15 +562,15 @@ void TextLayout::createStandardLayout (const AttributedString& text)
void TextLayout::recalculateSize()
{
if (lines.size() > 0)
if (! lines.isEmpty())
{
Rectangle<float> bounds (lines.getFirst()->getLineBounds());
auto bounds = lines.getFirst()->getLineBounds();
for (int i = lines.size(); --i > 0;)
bounds = bounds.getUnion (lines.getUnchecked(i)->getLineBounds());
for (auto* line : lines)
bounds = bounds.getUnion (line->getLineBounds());
for (int i = lines.size(); --i >= 0;)
lines.getUnchecked(i)->lineOrigin.x -= bounds.getX();
for (auto* line : lines)
line->lineOrigin.x -= bounds.getX();
width = bounds.getWidth();
height = bounds.getHeight();