migrating to the latest JUCE version

This commit is contained in:
2022-11-04 23:11:33 +01:00
committed by Nikolai Rodionov
parent 4257a0f8ba
commit faf8f18333
2796 changed files with 888518 additions and 784244 deletions

View File

@ -1,254 +1,282 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace
{
int getLength (const Array<AttributedString::Attribute>& atts) noexcept
{
return atts.size() != 0 ? atts.getReference (atts.size() - 1).range.getEnd() : 0;
}
void splitAttributeRanges (Array<AttributedString::Attribute>& atts, int position)
{
for (int i = atts.size(); --i >= 0;)
{
const auto& att = atts.getUnchecked (i);
auto offset = position - att.range.getStart();
if (offset >= 0)
{
if (offset > 0 && position < att.range.getEnd())
{
atts.insert (i + 1, AttributedString::Attribute (att));
atts.getReference (i).range.setEnd (position);
atts.getReference (i + 1).range.setStart (position);
}
break;
}
}
}
Range<int> splitAttributeRanges (Array<AttributedString::Attribute>& atts, Range<int> newRange)
{
newRange = newRange.getIntersectionWith ({ 0, getLength (atts) });
if (! newRange.isEmpty())
{
splitAttributeRanges (atts, newRange.getStart());
splitAttributeRanges (atts, newRange.getEnd());
}
return newRange;
}
void mergeAdjacentRanges (Array<AttributedString::Attribute>& atts)
{
for (int i = atts.size() - 1; --i >= 0;)
{
auto& a1 = atts.getReference (i);
auto& a2 = atts.getReference (i + 1);
if (a1.colour == a2.colour && a1.font == a2.font)
{
a1.range.setEnd (a2.range.getEnd());
atts.remove (i + 1);
if (i < atts.size() - 1)
++i;
}
}
}
void appendRange (Array<AttributedString::Attribute>& atts,
int length, const Font* f, const Colour* c)
{
if (atts.size() == 0)
{
atts.add ({ Range<int> (0, length), f != nullptr ? *f : Font(), c != nullptr ? *c : Colour (0xff000000) });
}
else
{
auto start = getLength (atts);
atts.add ({ Range<int> (start, start + length),
f != nullptr ? *f : atts.getReference (atts.size() - 1).font,
c != nullptr ? *c : atts.getReference (atts.size() - 1).colour });
mergeAdjacentRanges (atts);
}
}
void applyFontAndColour (Array<AttributedString::Attribute>& atts,
Range<int> range, const Font* f, const Colour* c)
{
range = splitAttributeRanges (atts, range);
for (auto& att : atts)
{
if (range.getStart() < att.range.getEnd())
{
if (range.getEnd() <= att.range.getStart())
break;
if (c != nullptr) att.colour = *c;
if (f != nullptr) att.font = *f;
}
}
mergeAdjacentRanges (atts);
}
void truncate (Array<AttributedString::Attribute>& atts, int newLength)
{
splitAttributeRanges (atts, newLength);
for (int i = atts.size(); --i >= 0;)
if (atts.getReference (i).range.getStart() >= newLength)
atts.remove (i);
}
}
//==============================================================================
AttributedString::Attribute::Attribute (Range<int> r, const Font& f, Colour c) noexcept
: range (r), font (f), colour (c)
{
}
//==============================================================================
void AttributedString::setText (const String& newText)
{
auto newLength = newText.length();
auto oldLength = getLength (attributes);
if (newLength > oldLength)
appendRange (attributes, newLength - oldLength, nullptr, nullptr);
else if (newLength < oldLength)
truncate (attributes, newLength);
text = newText;
}
void AttributedString::append (const String& textToAppend)
{
text += textToAppend;
appendRange (attributes, textToAppend.length(), nullptr, nullptr);
}
void AttributedString::append (const String& textToAppend, const Font& font)
{
text += textToAppend;
appendRange (attributes, textToAppend.length(), &font, nullptr);
}
void AttributedString::append (const String& textToAppend, Colour colour)
{
text += textToAppend;
appendRange (attributes, textToAppend.length(), nullptr, &colour);
}
void AttributedString::append (const String& textToAppend, const Font& font, Colour colour)
{
text += textToAppend;
appendRange (attributes, textToAppend.length(), &font, &colour);
}
void AttributedString::append (const AttributedString& other)
{
auto originalLength = getLength (attributes);
auto originalNumAtts = attributes.size();
text += other.text;
attributes.addArray (other.attributes);
for (auto i = originalNumAtts; i < attributes.size(); ++i)
attributes.getReference (i).range += originalLength;
mergeAdjacentRanges (attributes);
}
void AttributedString::clear()
{
text.clear();
attributes.clear();
}
void AttributedString::setJustification (Justification newJustification) noexcept
{
justification = newJustification;
}
void AttributedString::setWordWrap (WordWrap newWordWrap) noexcept
{
wordWrap = newWordWrap;
}
void AttributedString::setReadingDirection (ReadingDirection newReadingDirection) noexcept
{
readingDirection = newReadingDirection;
}
void AttributedString::setLineSpacing (const float newLineSpacing) noexcept
{
lineSpacing = newLineSpacing;
}
void AttributedString::setColour (Range<int> range, Colour colour)
{
applyFontAndColour (attributes, range, nullptr, &colour);
}
void AttributedString::setFont (Range<int> range, const Font& font)
{
applyFontAndColour (attributes, range, &font, nullptr);
}
void AttributedString::setColour (Colour colour)
{
setColour ({ 0, getLength (attributes) }, colour);
}
void AttributedString::setFont (const Font& font)
{
setFont ({ 0, getLength (attributes) }, font);
}
void AttributedString::draw (Graphics& g, const Rectangle<float>& area) const
{
if (text.isNotEmpty() && g.clipRegionIntersects (area.getSmallestIntegerContainer()))
{
jassert (text.length() == getLength (attributes));
if (! g.getInternalContext().drawTextLayout (*this, area))
{
TextLayout layout;
layout.createLayout (*this, area.getWidth());
layout.draw (g, area);
}
}
}
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace
{
int getLength (const Array<AttributedString::Attribute>& atts) noexcept
{
return atts.size() != 0 ? atts.getReference (atts.size() - 1).range.getEnd() : 0;
}
void splitAttributeRanges (Array<AttributedString::Attribute>& atts, int position)
{
for (int i = atts.size(); --i >= 0;)
{
const auto& att = atts.getUnchecked (i);
auto offset = position - att.range.getStart();
if (offset >= 0)
{
if (offset > 0 && position < att.range.getEnd())
{
atts.insert (i + 1, AttributedString::Attribute (att));
atts.getReference (i).range.setEnd (position);
atts.getReference (i + 1).range.setStart (position);
}
break;
}
}
}
inline bool areInvariantsMaintained (const String& text, const Array<AttributedString::Attribute>& atts)
{
if (atts.isEmpty())
return true;
if (atts.getFirst().range.getStart() != 0)
return false;
if (atts.getLast().range.getEnd() != text.length())
return false;
for (auto it = std::next (atts.begin()); it != atts.end(); ++it)
if (it->range.getStart() != std::prev (it)->range.getEnd())
return false;
return true;
}
Range<int> splitAttributeRanges (Array<AttributedString::Attribute>& atts, Range<int> newRange)
{
newRange = newRange.getIntersectionWith ({ 0, getLength (atts) });
if (! newRange.isEmpty())
{
splitAttributeRanges (atts, newRange.getStart());
splitAttributeRanges (atts, newRange.getEnd());
}
return newRange;
}
void mergeAdjacentRanges (Array<AttributedString::Attribute>& atts)
{
for (int i = atts.size() - 1; --i >= 0;)
{
auto& a1 = atts.getReference (i);
auto& a2 = atts.getReference (i + 1);
if (a1.colour == a2.colour && a1.font == a2.font)
{
a1.range.setEnd (a2.range.getEnd());
atts.remove (i + 1);
if (i < atts.size() - 1)
++i;
}
}
}
void appendRange (Array<AttributedString::Attribute>& atts,
int length, const Font* f, const Colour* c)
{
if (atts.size() == 0)
{
atts.add ({ Range<int> (0, length), f != nullptr ? *f : Font(), c != nullptr ? *c : Colour (0xff000000) });
}
else
{
auto start = getLength (atts);
atts.add ({ Range<int> (start, start + length),
f != nullptr ? *f : atts.getReference (atts.size() - 1).font,
c != nullptr ? *c : atts.getReference (atts.size() - 1).colour });
mergeAdjacentRanges (atts);
}
}
void applyFontAndColour (Array<AttributedString::Attribute>& atts,
Range<int> range, const Font* f, const Colour* c)
{
range = splitAttributeRanges (atts, range);
for (auto& att : atts)
{
if (range.getStart() < att.range.getEnd())
{
if (range.getEnd() <= att.range.getStart())
break;
if (c != nullptr) att.colour = *c;
if (f != nullptr) att.font = *f;
}
}
mergeAdjacentRanges (atts);
}
void truncate (Array<AttributedString::Attribute>& atts, int newLength)
{
splitAttributeRanges (atts, newLength);
for (int i = atts.size(); --i >= 0;)
if (atts.getReference (i).range.getStart() >= newLength)
atts.remove (i);
}
}
//==============================================================================
AttributedString::Attribute::Attribute (Range<int> r, const Font& f, Colour c) noexcept
: range (r), font (f), colour (c)
{
}
//==============================================================================
void AttributedString::setText (const String& newText)
{
auto newLength = newText.length();
auto oldLength = getLength (attributes);
if (newLength > oldLength)
appendRange (attributes, newLength - oldLength, nullptr, nullptr);
else if (newLength < oldLength)
truncate (attributes, newLength);
text = newText;
jassert (areInvariantsMaintained (text, attributes));
}
void AttributedString::append (const String& textToAppend)
{
text += textToAppend;
appendRange (attributes, textToAppend.length(), nullptr, nullptr);
jassert (areInvariantsMaintained (text, attributes));
}
void AttributedString::append (const String& textToAppend, const Font& font)
{
text += textToAppend;
appendRange (attributes, textToAppend.length(), &font, nullptr);
jassert (areInvariantsMaintained (text, attributes));
}
void AttributedString::append (const String& textToAppend, Colour colour)
{
text += textToAppend;
appendRange (attributes, textToAppend.length(), nullptr, &colour);
jassert (areInvariantsMaintained (text, attributes));
}
void AttributedString::append (const String& textToAppend, const Font& font, Colour colour)
{
text += textToAppend;
appendRange (attributes, textToAppend.length(), &font, &colour);
jassert (areInvariantsMaintained (text, attributes));
}
void AttributedString::append (const AttributedString& other)
{
auto originalLength = getLength (attributes);
auto originalNumAtts = attributes.size();
text += other.text;
attributes.addArray (other.attributes);
for (auto i = originalNumAtts; i < attributes.size(); ++i)
attributes.getReference (i).range += originalLength;
mergeAdjacentRanges (attributes);
jassert (areInvariantsMaintained (text, attributes));
}
void AttributedString::clear()
{
text.clear();
attributes.clear();
}
void AttributedString::setJustification (Justification newJustification) noexcept
{
justification = newJustification;
}
void AttributedString::setWordWrap (WordWrap newWordWrap) noexcept
{
wordWrap = newWordWrap;
}
void AttributedString::setReadingDirection (ReadingDirection newReadingDirection) noexcept
{
readingDirection = newReadingDirection;
}
void AttributedString::setLineSpacing (const float newLineSpacing) noexcept
{
lineSpacing = newLineSpacing;
}
void AttributedString::setColour (Range<int> range, Colour colour)
{
applyFontAndColour (attributes, range, nullptr, &colour);
jassert (areInvariantsMaintained (text, attributes));
}
void AttributedString::setFont (Range<int> range, const Font& font)
{
applyFontAndColour (attributes, range, &font, nullptr);
jassert (areInvariantsMaintained (text, attributes));
}
void AttributedString::setColour (Colour colour)
{
setColour ({ 0, getLength (attributes) }, colour);
jassert (areInvariantsMaintained (text, attributes));
}
void AttributedString::setFont (const Font& font)
{
setFont ({ 0, getLength (attributes) }, font);
jassert (areInvariantsMaintained (text, attributes));
}
void AttributedString::draw (Graphics& g, const Rectangle<float>& area) const
{
if (text.isNotEmpty() && g.clipRegionIntersects (area.getSmallestIntegerContainer()))
{
jassert (text.length() == getLength (attributes));
if (! g.getInternalContext().drawTextLayout (*this, area))
{
TextLayout layout;
layout.createLayout (*this, area.getWidth());
layout.draw (g, area);
}
}
}
} // namespace juce

View File

@ -1,205 +1,210 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A text string with a set of colour/font settings that are associated with sub-ranges
of the text.
An attributed string lets you create a string with varied fonts, colours, word-wrapping,
layout, etc., and draw it using AttributedString::draw().
@see TextLayout
@tags{Graphics}
*/
class JUCE_API AttributedString
{
public:
/** Creates an empty attributed string. */
AttributedString() = default;
/** Creates an attributed string with the given text. */
explicit AttributedString (const String& newString) { setText (newString); }
AttributedString (const AttributedString&) = default;
AttributedString& operator= (const AttributedString&) = default;
AttributedString (AttributedString&&) noexcept = default;
AttributedString& operator= (AttributedString&&) noexcept = default;
//==============================================================================
/** Returns the complete text of this attributed string. */
const String& getText() const noexcept { return text; }
/** Replaces all the text.
This will change the text, but won't affect any of the colour or font attributes
that have been added.
*/
void setText (const String& newText);
/** Appends some text (with a default font and colour). */
void append (const String& textToAppend);
/** Appends some text, with a specified font, and the default colour (black). */
void append (const String& textToAppend, const Font& font);
/** Appends some text, with a specified colour, and the default font. */
void append (const String& textToAppend, Colour colour);
/** Appends some text, with a specified font and colour. */
void append (const String& textToAppend, const Font& font, Colour colour);
/** Appends another AttributedString to this one.
Note that this will only append the text, fonts, and colours - it won't copy any
other properties such as justification, line-spacing, etc from the other object.
*/
void append (const AttributedString& other);
/** Resets the string, clearing all text and attributes.
Note that this won't affect global settings like the justification type,
word-wrap mode, etc.
*/
void clear();
//==============================================================================
/** Draws this string within the given area.
The layout of the string within the rectangle is controlled by the justification
value passed to setJustification().
*/
void draw (Graphics& g, const Rectangle<float>& area) const;
//==============================================================================
/** Returns the justification that should be used for laying-out the text.
This may include both vertical and horizontal flags.
*/
Justification getJustification() const noexcept { return justification; }
/** Sets the justification that should be used for laying-out the text.
This may include both vertical and horizontal flags.
*/
void setJustification (Justification newJustification) noexcept;
//==============================================================================
/** Types of word-wrap behaviour.
@see getWordWrap, setWordWrap
*/
enum WordWrap
{
none, /**< No word-wrapping: lines extend indefinitely. */
byWord, /**< Lines are wrapped on a word boundary. */
byChar, /**< Lines are wrapped on a character boundary. */
};
/** Returns the word-wrapping behaviour. */
WordWrap getWordWrap() const noexcept { return wordWrap; }
/** Sets the word-wrapping behaviour. */
void setWordWrap (WordWrap newWordWrap) noexcept;
//==============================================================================
/** Types of reading direction that can be used.
@see getReadingDirection, setReadingDirection
*/
enum ReadingDirection
{
natural,
leftToRight,
rightToLeft,
};
/** Returns the reading direction for the text. */
ReadingDirection getReadingDirection() const noexcept { return readingDirection; }
/** Sets the reading direction that should be used for the text. */
void setReadingDirection (ReadingDirection newReadingDirection) noexcept;
//==============================================================================
/** Returns the extra line-spacing distance. */
float getLineSpacing() const noexcept { return lineSpacing; }
/** Sets an extra line-spacing distance. */
void setLineSpacing (float newLineSpacing) noexcept;
//==============================================================================
/** An attribute that has been applied to a range of characters in an AttributedString. */
class JUCE_API Attribute
{
public:
Attribute() = default;
Attribute (const Attribute&) = default;
Attribute& operator= (const Attribute&) = default;
Attribute (Attribute&&) noexcept = default;
Attribute& operator= (Attribute&&) noexcept = default;
/** Creates an attribute that specifies the font and colour for a range of characters. */
Attribute (Range<int> range, const Font& font, Colour colour) noexcept;
/** The range of characters to which this attribute will be applied. */
Range<int> range;
/** The font for this range of characters. */
Font font;
/** The colour for this range of characters. */
Colour colour { 0xff000000 };
private:
JUCE_LEAK_DETECTOR (Attribute)
};
/** Returns the number of attributes that have been added to this string. */
int getNumAttributes() const noexcept { return attributes.size(); }
/** Returns one of the string's attributes.
The index provided must be less than getNumAttributes(), and >= 0.
*/
const Attribute& getAttribute (int index) const noexcept { return attributes.getReference (index); }
//==============================================================================
/** Adds a colour attribute for the specified range. */
void setColour (Range<int> range, Colour colour);
/** Removes all existing colour attributes, and applies this colour to the whole string. */
void setColour (Colour colour);
/** Adds a font attribute for the specified range. */
void setFont (Range<int> range, const Font& font);
/** Removes all existing font attributes, and applies this font to the whole string. */
void setFont (const Font& font);
private:
String text;
float lineSpacing = 0.0f;
Justification justification = Justification::left;
WordWrap wordWrap = AttributedString::byWord;
ReadingDirection readingDirection = AttributedString::natural;
Array<Attribute> attributes;
JUCE_LEAK_DETECTOR (AttributedString)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A text string with a set of colour/font settings that are associated with sub-ranges
of the text.
An attributed string lets you create a string with varied fonts, colours, word-wrapping,
layout, etc., and draw it using AttributedString::draw().
Invariants:
- Every character in the string is a member of exactly one attribute.
- Attributes are sorted such that the range-end of attribute 'i' is equal to the
range-begin of attribute 'i + 1'.
@see TextLayout
@tags{Graphics}
*/
class JUCE_API AttributedString
{
public:
/** Creates an empty attributed string. */
AttributedString() = default;
/** Creates an attributed string with the given text. */
explicit AttributedString (const String& newString) { setText (newString); }
AttributedString (const AttributedString&) = default;
AttributedString& operator= (const AttributedString&) = default;
AttributedString (AttributedString&&) noexcept = default;
AttributedString& operator= (AttributedString&&) noexcept = default;
//==============================================================================
/** Returns the complete text of this attributed string. */
const String& getText() const noexcept { return text; }
/** Replaces all the text.
This will change the text, but won't affect any of the colour or font attributes
that have been added.
*/
void setText (const String& newText);
/** Appends some text (with a default font and colour). */
void append (const String& textToAppend);
/** Appends some text, with a specified font, and the default colour (black). */
void append (const String& textToAppend, const Font& font);
/** Appends some text, with a specified colour, and the default font. */
void append (const String& textToAppend, Colour colour);
/** Appends some text, with a specified font and colour. */
void append (const String& textToAppend, const Font& font, Colour colour);
/** Appends another AttributedString to this one.
Note that this will only append the text, fonts, and colours - it won't copy any
other properties such as justification, line-spacing, etc from the other object.
*/
void append (const AttributedString& other);
/** Resets the string, clearing all text and attributes.
Note that this won't affect global settings like the justification type,
word-wrap mode, etc.
*/
void clear();
//==============================================================================
/** Draws this string within the given area.
The layout of the string within the rectangle is controlled by the justification
value passed to setJustification().
*/
void draw (Graphics& g, const Rectangle<float>& area) const;
//==============================================================================
/** Returns the justification that should be used for laying-out the text.
This may include both vertical and horizontal flags.
*/
Justification getJustification() const noexcept { return justification; }
/** Sets the justification that should be used for laying-out the text.
This may include both vertical and horizontal flags.
*/
void setJustification (Justification newJustification) noexcept;
//==============================================================================
/** Types of word-wrap behaviour.
@see getWordWrap, setWordWrap
*/
enum WordWrap
{
none, /**< No word-wrapping: lines extend indefinitely. */
byWord, /**< Lines are wrapped on a word boundary. */
byChar, /**< Lines are wrapped on a character boundary. */
};
/** Returns the word-wrapping behaviour. */
WordWrap getWordWrap() const noexcept { return wordWrap; }
/** Sets the word-wrapping behaviour. */
void setWordWrap (WordWrap newWordWrap) noexcept;
//==============================================================================
/** Types of reading direction that can be used.
@see getReadingDirection, setReadingDirection
*/
enum ReadingDirection
{
natural,
leftToRight,
rightToLeft,
};
/** Returns the reading direction for the text. */
ReadingDirection getReadingDirection() const noexcept { return readingDirection; }
/** Sets the reading direction that should be used for the text. */
void setReadingDirection (ReadingDirection newReadingDirection) noexcept;
//==============================================================================
/** Returns the extra line-spacing distance. */
float getLineSpacing() const noexcept { return lineSpacing; }
/** Sets an extra line-spacing distance. */
void setLineSpacing (float newLineSpacing) noexcept;
//==============================================================================
/** An attribute that has been applied to a range of characters in an AttributedString. */
class JUCE_API Attribute
{
public:
Attribute() = default;
Attribute (const Attribute&) = default;
Attribute& operator= (const Attribute&) = default;
Attribute (Attribute&&) noexcept = default;
Attribute& operator= (Attribute&&) noexcept = default;
/** Creates an attribute that specifies the font and colour for a range of characters. */
Attribute (Range<int> range, const Font& font, Colour colour) noexcept;
/** The range of characters to which this attribute will be applied. */
Range<int> range;
/** The font for this range of characters. */
Font font;
/** The colour for this range of characters. */
Colour colour { 0xff000000 };
private:
JUCE_LEAK_DETECTOR (Attribute)
};
/** Returns the number of attributes that have been added to this string. */
int getNumAttributes() const noexcept { return attributes.size(); }
/** Returns one of the string's attributes.
The index provided must be less than getNumAttributes(), and >= 0.
*/
const Attribute& getAttribute (int index) const noexcept { return attributes.getReference (index); }
//==============================================================================
/** Adds a colour attribute for the specified range. */
void setColour (Range<int> range, Colour colour);
/** Removes all existing colour attributes, and applies this colour to the whole string. */
void setColour (Colour colour);
/** Adds a font attribute for the specified range. */
void setFont (Range<int> range, const Font& font);
/** Removes all existing font attributes, and applies this font to the whole string. */
void setFont (const Font& font);
private:
String text;
float lineSpacing = 0.0f;
Justification justification = Justification::left;
WordWrap wordWrap = AttributedString::byWord;
ReadingDirection readingDirection = AttributedString::natural;
Array<Attribute> attributes;
JUCE_LEAK_DETECTOR (AttributedString)
};
} // namespace juce

View File

@ -1,398 +1,398 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
class CustomTypeface::GlyphInfo
{
public:
GlyphInfo (juce_wchar c, const Path& p, float w) noexcept
: character (c), path (p), width (w)
{
}
struct KerningPair
{
juce_wchar character2;
float kerningAmount;
};
void addKerningPair (juce_wchar subsequentCharacter, float extraKerningAmount) noexcept
{
kerningPairs.add ({ subsequentCharacter, extraKerningAmount });
}
float getHorizontalSpacing (juce_wchar subsequentCharacter) const noexcept
{
if (subsequentCharacter != 0)
for (auto& kp : kerningPairs)
if (kp.character2 == subsequentCharacter)
return width + kp.kerningAmount;
return width;
}
const juce_wchar character;
const Path path;
float width;
Array<KerningPair> kerningPairs;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GlyphInfo)
};
//==============================================================================
namespace CustomTypefaceHelpers
{
static juce_wchar readChar (InputStream& in)
{
auto n = (uint32) (uint16) in.readShort();
if (n >= 0xd800 && n <= 0xdfff)
{
auto nextWord = (uint32) (uint16) in.readShort();
jassert (nextWord >= 0xdc00); // illegal unicode character!
n = 0x10000 + (((n - 0xd800) << 10) | (nextWord - 0xdc00));
}
return (juce_wchar) n;
}
static void writeChar (OutputStream& out, juce_wchar charToWrite)
{
if (charToWrite >= 0x10000)
{
charToWrite -= 0x10000;
out.writeShort ((short) (uint16) (0xd800 + (charToWrite >> 10)));
out.writeShort ((short) (uint16) (0xdc00 + (charToWrite & 0x3ff)));
}
else
{
out.writeShort ((short) (uint16) charToWrite);
}
}
}
//==============================================================================
CustomTypeface::CustomTypeface()
: Typeface (String(), String())
{
clear();
}
CustomTypeface::CustomTypeface (InputStream& serialisedTypefaceStream)
: Typeface (String(), String())
{
clear();
GZIPDecompressorInputStream gzin (serialisedTypefaceStream);
BufferedInputStream in (gzin, 32768);
name = in.readString();
const bool isBold = in.readBool();
const bool isItalic = in.readBool();
style = FontStyleHelpers::getStyleName (isBold, isItalic);
ascent = in.readFloat();
defaultCharacter = CustomTypefaceHelpers::readChar (in);
auto numChars = in.readInt();
for (int i = 0; i < numChars; ++i)
{
auto c = CustomTypefaceHelpers::readChar (in);
auto width = in.readFloat();
Path p;
p.loadPathFromStream (in);
addGlyph (c, p, width);
}
auto numKerningPairs = in.readInt();
for (int i = 0; i < numKerningPairs; ++i)
{
auto char1 = CustomTypefaceHelpers::readChar (in);
auto char2 = CustomTypefaceHelpers::readChar (in);
addKerningPair (char1, char2, in.readFloat());
}
}
CustomTypeface::~CustomTypeface()
{
}
//==============================================================================
void CustomTypeface::clear()
{
defaultCharacter = 0;
ascent = 1.0f;
style = "Regular";
zeromem (lookupTable, sizeof (lookupTable));
glyphs.clear();
}
void CustomTypeface::setCharacteristics (const String& newName, float newAscent, bool isBold,
bool isItalic, juce_wchar newDefaultCharacter) noexcept
{
name = newName;
defaultCharacter = newDefaultCharacter;
ascent = newAscent;
style = FontStyleHelpers::getStyleName (isBold, isItalic);
}
void CustomTypeface::setCharacteristics (const String& newName, const String& newStyle,
float newAscent, juce_wchar newDefaultCharacter) noexcept
{
name = newName;
style = newStyle;
defaultCharacter = newDefaultCharacter;
ascent = newAscent;
}
void CustomTypeface::addGlyph (juce_wchar character, const Path& path, float width) noexcept
{
// Check that you're not trying to add the same character twice..
jassert (findGlyph (character, false) == nullptr);
if (isPositiveAndBelow ((int) character, numElementsInArray (lookupTable)))
lookupTable [character] = (short) glyphs.size();
glyphs.add (new GlyphInfo (character, path, width));
}
void CustomTypeface::addKerningPair (juce_wchar char1, juce_wchar char2, float extraAmount) noexcept
{
if (extraAmount != 0.0f)
{
if (auto* g = findGlyph (char1, true))
g->addKerningPair (char2, extraAmount);
else
jassertfalse; // can only add kerning pairs for characters that exist!
}
}
CustomTypeface::GlyphInfo* CustomTypeface::findGlyph (juce_wchar character, bool loadIfNeeded) noexcept
{
if (isPositiveAndBelow ((int) character, numElementsInArray (lookupTable)) && lookupTable [character] > 0)
return glyphs [(int) lookupTable [(int) character]];
for (auto* g : glyphs)
if (g->character == character)
return g;
if (loadIfNeeded && loadGlyphIfPossible (character))
return findGlyph (character, false);
return nullptr;
}
bool CustomTypeface::loadGlyphIfPossible (juce_wchar)
{
return false;
}
void CustomTypeface::addGlyphsFromOtherTypeface (Typeface& typefaceToCopy, juce_wchar characterStartIndex, int numCharacters) noexcept
{
setCharacteristics (name, style, typefaceToCopy.getAscent(), defaultCharacter);
for (int i = 0; i < numCharacters; ++i)
{
auto c = (juce_wchar) (characterStartIndex + static_cast<juce_wchar> (i));
Array<int> glyphIndexes;
Array<float> offsets;
typefaceToCopy.getGlyphPositions (String::charToString (c), glyphIndexes, offsets);
const int glyphIndex = glyphIndexes.getFirst();
if (glyphIndex >= 0 && glyphIndexes.size() > 0)
{
auto glyphWidth = offsets[1];
Path p;
typefaceToCopy.getOutlineForGlyph (glyphIndex, p);
addGlyph (c, p, glyphWidth);
for (int j = glyphs.size() - 1; --j >= 0;)
{
auto char2 = glyphs.getUnchecked (j)->character;
glyphIndexes.clearQuick();
offsets.clearQuick();
typefaceToCopy.getGlyphPositions (String::charToString (c) + String::charToString (char2), glyphIndexes, offsets);
if (offsets.size() > 1)
addKerningPair (c, char2, offsets[1] - glyphWidth);
}
}
}
}
bool CustomTypeface::writeToStream (OutputStream& outputStream)
{
GZIPCompressorOutputStream out (outputStream);
out.writeString (name);
out.writeBool (FontStyleHelpers::isBold (style));
out.writeBool (FontStyleHelpers::isItalic (style));
out.writeFloat (ascent);
CustomTypefaceHelpers::writeChar (out, defaultCharacter);
out.writeInt (glyphs.size());
int numKerningPairs = 0;
for (auto* g : glyphs)
{
CustomTypefaceHelpers::writeChar (out, g->character);
out.writeFloat (g->width);
g->path.writePathToStream (out);
numKerningPairs += g->kerningPairs.size();
}
out.writeInt (numKerningPairs);
for (auto* g : glyphs)
{
for (auto& p : g->kerningPairs)
{
CustomTypefaceHelpers::writeChar (out, g->character);
CustomTypefaceHelpers::writeChar (out, p.character2);
out.writeFloat (p.kerningAmount);
}
}
return true;
}
//==============================================================================
float CustomTypeface::getAscent() const { return ascent; }
float CustomTypeface::getDescent() const { return 1.0f - ascent; }
float CustomTypeface::getHeightToPointsFactor() const { return ascent; }
float CustomTypeface::getStringWidth (const String& text)
{
float x = 0;
for (auto t = text.getCharPointer(); ! t.isEmpty();)
{
auto c = t.getAndAdvance();
if (auto* glyph = findGlyph (c, true))
{
x += glyph->getHorizontalSpacing (*t);
}
else
{
if (auto fallbackTypeface = Typeface::getFallbackTypeface())
if (fallbackTypeface.get() != this)
x += fallbackTypeface->getStringWidth (String::charToString (c));
}
}
return x;
}
void CustomTypeface::getGlyphPositions (const String& text, Array<int>& resultGlyphs, Array<float>& xOffsets)
{
xOffsets.add (0);
float x = 0;
for (auto t = text.getCharPointer(); ! t.isEmpty();)
{
float width = 0.0f;
int glyphChar = 0;
auto c = t.getAndAdvance();
if (auto* glyph = findGlyph (c, true))
{
width = glyph->getHorizontalSpacing (*t);
glyphChar = (int) glyph->character;
}
else
{
auto fallbackTypeface = getFallbackTypeface();
if (fallbackTypeface != nullptr && fallbackTypeface.get() != this)
{
Array<int> subGlyphs;
Array<float> subOffsets;
fallbackTypeface->getGlyphPositions (String::charToString (c), subGlyphs, subOffsets);
if (subGlyphs.size() > 0)
{
glyphChar = subGlyphs.getFirst();
width = subOffsets[1];
}
}
}
x += width;
resultGlyphs.add (glyphChar);
xOffsets.add (x);
}
}
bool CustomTypeface::getOutlineForGlyph (int glyphNumber, Path& path)
{
if (auto* glyph = findGlyph ((juce_wchar) glyphNumber, true))
{
path = glyph->path;
return true;
}
if (auto fallbackTypeface = getFallbackTypeface())
if (fallbackTypeface.get() != this)
return fallbackTypeface->getOutlineForGlyph (glyphNumber, path);
return false;
}
EdgeTable* CustomTypeface::getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight)
{
if (auto* glyph = findGlyph ((juce_wchar) glyphNumber, true))
{
if (! glyph->path.isEmpty())
return new EdgeTable (glyph->path.getBoundsTransformed (transform)
.getSmallestIntegerContainer().expanded (1, 0),
glyph->path, transform);
}
else
{
if (auto fallbackTypeface = getFallbackTypeface())
if (fallbackTypeface.get() != this)
return fallbackTypeface->getEdgeTableForGlyph (glyphNumber, transform, fontHeight);
}
return nullptr;
}
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
class CustomTypeface::GlyphInfo
{
public:
GlyphInfo (juce_wchar c, const Path& p, float w) noexcept
: character (c), path (p), width (w)
{
}
struct KerningPair
{
juce_wchar character2;
float kerningAmount;
};
void addKerningPair (juce_wchar subsequentCharacter, float extraKerningAmount) noexcept
{
kerningPairs.add ({ subsequentCharacter, extraKerningAmount });
}
float getHorizontalSpacing (juce_wchar subsequentCharacter) const noexcept
{
if (subsequentCharacter != 0)
for (auto& kp : kerningPairs)
if (kp.character2 == subsequentCharacter)
return width + kp.kerningAmount;
return width;
}
const juce_wchar character;
const Path path;
float width;
Array<KerningPair> kerningPairs;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GlyphInfo)
};
//==============================================================================
namespace CustomTypefaceHelpers
{
static juce_wchar readChar (InputStream& in)
{
auto n = (uint32) (uint16) in.readShort();
if (n >= 0xd800 && n <= 0xdfff)
{
auto nextWord = (uint32) (uint16) in.readShort();
jassert (nextWord >= 0xdc00); // illegal unicode character!
n = 0x10000 + (((n - 0xd800) << 10) | (nextWord - 0xdc00));
}
return (juce_wchar) n;
}
static void writeChar (OutputStream& out, juce_wchar charToWrite)
{
if (charToWrite >= 0x10000)
{
charToWrite -= 0x10000;
out.writeShort ((short) (uint16) (0xd800 + (charToWrite >> 10)));
out.writeShort ((short) (uint16) (0xdc00 + (charToWrite & 0x3ff)));
}
else
{
out.writeShort ((short) (uint16) charToWrite);
}
}
}
//==============================================================================
CustomTypeface::CustomTypeface()
: Typeface (String(), String())
{
clear();
}
CustomTypeface::CustomTypeface (InputStream& serialisedTypefaceStream)
: Typeface (String(), String())
{
clear();
GZIPDecompressorInputStream gzin (serialisedTypefaceStream);
BufferedInputStream in (gzin, 32768);
name = in.readString();
const bool isBold = in.readBool();
const bool isItalic = in.readBool();
style = FontStyleHelpers::getStyleName (isBold, isItalic);
ascent = in.readFloat();
defaultCharacter = CustomTypefaceHelpers::readChar (in);
auto numChars = in.readInt();
for (int i = 0; i < numChars; ++i)
{
auto c = CustomTypefaceHelpers::readChar (in);
auto width = in.readFloat();
Path p;
p.loadPathFromStream (in);
addGlyph (c, p, width);
}
auto numKerningPairs = in.readInt();
for (int i = 0; i < numKerningPairs; ++i)
{
auto char1 = CustomTypefaceHelpers::readChar (in);
auto char2 = CustomTypefaceHelpers::readChar (in);
addKerningPair (char1, char2, in.readFloat());
}
}
CustomTypeface::~CustomTypeface()
{
}
//==============================================================================
void CustomTypeface::clear()
{
defaultCharacter = 0;
ascent = 1.0f;
style = "Regular";
zeromem (lookupTable, sizeof (lookupTable));
glyphs.clear();
}
void CustomTypeface::setCharacteristics (const String& newName, float newAscent, bool isBold,
bool isItalic, juce_wchar newDefaultCharacter) noexcept
{
name = newName;
defaultCharacter = newDefaultCharacter;
ascent = newAscent;
style = FontStyleHelpers::getStyleName (isBold, isItalic);
}
void CustomTypeface::setCharacteristics (const String& newName, const String& newStyle,
float newAscent, juce_wchar newDefaultCharacter) noexcept
{
name = newName;
style = newStyle;
defaultCharacter = newDefaultCharacter;
ascent = newAscent;
}
void CustomTypeface::addGlyph (juce_wchar character, const Path& path, float width) noexcept
{
// Check that you're not trying to add the same character twice..
jassert (findGlyph (character, false) == nullptr);
if (isPositiveAndBelow ((int) character, numElementsInArray (lookupTable)))
lookupTable [character] = (short) glyphs.size();
glyphs.add (new GlyphInfo (character, path, width));
}
void CustomTypeface::addKerningPair (juce_wchar char1, juce_wchar char2, float extraAmount) noexcept
{
if (extraAmount != 0.0f)
{
if (auto* g = findGlyph (char1, true))
g->addKerningPair (char2, extraAmount);
else
jassertfalse; // can only add kerning pairs for characters that exist!
}
}
CustomTypeface::GlyphInfo* CustomTypeface::findGlyph (juce_wchar character, bool loadIfNeeded) noexcept
{
if (isPositiveAndBelow ((int) character, numElementsInArray (lookupTable)) && lookupTable [character] > 0)
return glyphs [(int) lookupTable [(int) character]];
for (auto* g : glyphs)
if (g->character == character)
return g;
if (loadIfNeeded && loadGlyphIfPossible (character))
return findGlyph (character, false);
return nullptr;
}
bool CustomTypeface::loadGlyphIfPossible (juce_wchar)
{
return false;
}
void CustomTypeface::addGlyphsFromOtherTypeface (Typeface& typefaceToCopy, juce_wchar characterStartIndex, int numCharacters) noexcept
{
setCharacteristics (name, style, typefaceToCopy.getAscent(), defaultCharacter);
for (int i = 0; i < numCharacters; ++i)
{
auto c = (juce_wchar) (characterStartIndex + static_cast<juce_wchar> (i));
Array<int> glyphIndexes;
Array<float> offsets;
typefaceToCopy.getGlyphPositions (String::charToString (c), glyphIndexes, offsets);
const int glyphIndex = glyphIndexes.getFirst();
if (glyphIndex >= 0 && glyphIndexes.size() > 0)
{
auto glyphWidth = offsets[1];
Path p;
typefaceToCopy.getOutlineForGlyph (glyphIndex, p);
addGlyph (c, p, glyphWidth);
for (int j = glyphs.size() - 1; --j >= 0;)
{
auto char2 = glyphs.getUnchecked (j)->character;
glyphIndexes.clearQuick();
offsets.clearQuick();
typefaceToCopy.getGlyphPositions (String::charToString (c) + String::charToString (char2), glyphIndexes, offsets);
if (offsets.size() > 1)
addKerningPair (c, char2, offsets[1] - glyphWidth);
}
}
}
}
bool CustomTypeface::writeToStream (OutputStream& outputStream)
{
GZIPCompressorOutputStream out (outputStream);
out.writeString (name);
out.writeBool (FontStyleHelpers::isBold (style));
out.writeBool (FontStyleHelpers::isItalic (style));
out.writeFloat (ascent);
CustomTypefaceHelpers::writeChar (out, defaultCharacter);
out.writeInt (glyphs.size());
int numKerningPairs = 0;
for (auto* g : glyphs)
{
CustomTypefaceHelpers::writeChar (out, g->character);
out.writeFloat (g->width);
g->path.writePathToStream (out);
numKerningPairs += g->kerningPairs.size();
}
out.writeInt (numKerningPairs);
for (auto* g : glyphs)
{
for (auto& p : g->kerningPairs)
{
CustomTypefaceHelpers::writeChar (out, g->character);
CustomTypefaceHelpers::writeChar (out, p.character2);
out.writeFloat (p.kerningAmount);
}
}
return true;
}
//==============================================================================
float CustomTypeface::getAscent() const { return ascent; }
float CustomTypeface::getDescent() const { return 1.0f - ascent; }
float CustomTypeface::getHeightToPointsFactor() const { return ascent; }
float CustomTypeface::getStringWidth (const String& text)
{
float x = 0;
for (auto t = text.getCharPointer(); ! t.isEmpty();)
{
auto c = t.getAndAdvance();
if (auto* glyph = findGlyph (c, true))
{
x += glyph->getHorizontalSpacing (*t);
}
else
{
if (auto fallbackTypeface = Typeface::getFallbackTypeface())
if (fallbackTypeface.get() != this)
x += fallbackTypeface->getStringWidth (String::charToString (c));
}
}
return x;
}
void CustomTypeface::getGlyphPositions (const String& text, Array<int>& resultGlyphs, Array<float>& xOffsets)
{
xOffsets.add (0);
float x = 0;
for (auto t = text.getCharPointer(); ! t.isEmpty();)
{
float width = 0.0f;
int glyphChar = 0;
auto c = t.getAndAdvance();
if (auto* glyph = findGlyph (c, true))
{
width = glyph->getHorizontalSpacing (*t);
glyphChar = (int) glyph->character;
}
else
{
auto fallbackTypeface = getFallbackTypeface();
if (fallbackTypeface != nullptr && fallbackTypeface.get() != this)
{
Array<int> subGlyphs;
Array<float> subOffsets;
fallbackTypeface->getGlyphPositions (String::charToString (c), subGlyphs, subOffsets);
if (subGlyphs.size() > 0)
{
glyphChar = subGlyphs.getFirst();
width = subOffsets[1];
}
}
}
x += width;
resultGlyphs.add (glyphChar);
xOffsets.add (x);
}
}
bool CustomTypeface::getOutlineForGlyph (int glyphNumber, Path& path)
{
if (auto* glyph = findGlyph ((juce_wchar) glyphNumber, true))
{
path = glyph->path;
return true;
}
if (auto fallbackTypeface = getFallbackTypeface())
if (fallbackTypeface.get() != this)
return fallbackTypeface->getOutlineForGlyph (glyphNumber, path);
return false;
}
EdgeTable* CustomTypeface::getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight)
{
if (auto* glyph = findGlyph ((juce_wchar) glyphNumber, true))
{
if (! glyph->path.isEmpty())
return new EdgeTable (glyph->path.getBoundsTransformed (transform)
.getSmallestIntegerContainer().expanded (1, 0),
glyph->path, transform);
}
else
{
if (auto fallbackTypeface = getFallbackTypeface())
if (fallbackTypeface.get() != this)
return fallbackTypeface->getEdgeTableForGlyph (glyphNumber, transform, fontHeight);
}
return nullptr;
}
} // namespace juce

View File

@ -1,165 +1,165 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A typeface that can be populated with custom glyphs.
You can create a CustomTypeface if you need one that contains your own glyphs,
or if you need to load a typeface from a Juce-formatted binary stream.
If you want to create a copy of a native face, you can use addGlyphsFromOtherTypeface()
to copy glyphs into this face.
NOTE! For most people this class is almost certainly NOT the right tool to use!
If what you want to do is to embed a font into your exe, then your best plan is
probably to embed your TTF/OTF font file into your binary using the Projucer,
and then call Typeface::createSystemTypefaceFor() to load it from memory.
@see Typeface, Font
@tags{Graphics}
*/
class JUCE_API CustomTypeface : public Typeface
{
public:
//==============================================================================
/** Creates a new, empty typeface. */
CustomTypeface();
/** Loads a typeface from a previously saved stream.
The stream must have been created by writeToStream().
NOTE! Since this class was written, support was added for loading real font files from
memory, so for most people, using Typeface::createSystemTypefaceFor() to load a real font
is more appropriate than using this class to store it in a proprietary format.
@see writeToStream
*/
explicit CustomTypeface (InputStream& serialisedTypefaceStream);
/** Destructor. */
~CustomTypeface() override;
//==============================================================================
/** Resets this typeface, deleting all its glyphs and settings. */
void clear();
/** Sets the vital statistics for the typeface.
@param fontFamily the typeface's font family
@param ascent the ascent - this is normalised to a height of 1.0 and this is
the value that will be returned by Typeface::getAscent(). The
descent is assumed to be (1.0 - ascent)
@param isBold should be true if the typeface is bold
@param isItalic should be true if the typeface is italic
@param defaultCharacter the character to be used as a replacement if there's
no glyph available for the character that's being drawn
*/
void setCharacteristics (const String& fontFamily, float ascent,
bool isBold, bool isItalic,
juce_wchar defaultCharacter) noexcept;
/** Sets the vital statistics for the typeface.
@param fontFamily the typeface's font family
@param fontStyle the typeface's font style
@param ascent the ascent - this is normalised to a height of 1.0 and this is
the value that will be returned by Typeface::getAscent(). The
descent is assumed to be (1.0 - ascent)
@param defaultCharacter the character to be used as a replacement if there's
no glyph available for the character that's being drawn
*/
void setCharacteristics (const String& fontFamily, const String& fontStyle,
float ascent, juce_wchar defaultCharacter) noexcept;
/** Adds a glyph to the typeface.
The path that is passed in is normalised so that the font height is 1.0, and its
origin is the anchor point of the character on its baseline.
The width is the nominal width of the character, and any extra kerning values that
are specified will be added to this width.
*/
void addGlyph (juce_wchar character, const Path& path, float width) noexcept;
/** Specifies an extra kerning amount to be used between a pair of characters.
The amount will be added to the nominal width of the first character when laying out a string.
*/
void addKerningPair (juce_wchar char1, juce_wchar char2, float extraAmount) noexcept;
/** Adds a range of glyphs from another typeface.
This will attempt to pull in the paths and kerning information from another typeface and
add it to this one.
*/
void addGlyphsFromOtherTypeface (Typeface& typefaceToCopy, juce_wchar characterStartIndex, int numCharacters) noexcept;
/** Saves this typeface as a Juce-formatted font file.
A CustomTypeface can be created to reload the data that is written - see the CustomTypeface
constructor.
NOTE! Since this class was written, support was added for loading real font files from
memory, so for most people, using Typeface::createSystemTypefaceFor() to load a real font
is more appropriate than using this class to store it in a proprietary format.
*/
bool writeToStream (OutputStream& outputStream);
//==============================================================================
// The following methods implement the basic Typeface behaviour.
float getAscent() const override;
float getDescent() const override;
float getHeightToPointsFactor() const override;
float getStringWidth (const String&) override;
void getGlyphPositions (const String&, Array<int>& glyphs, Array<float>& xOffsets) override;
bool getOutlineForGlyph (int glyphNumber, Path&) override;
EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform&, float fontHeight) override;
protected:
//==============================================================================
juce_wchar defaultCharacter;
float ascent;
//==============================================================================
/** If a subclass overrides this, it can load glyphs into the font on-demand.
When methods such as getGlyphPositions() or getOutlineForGlyph() are asked for a
particular character and there's no corresponding glyph, they'll call this
method so that a subclass can try to add that glyph, returning true if it
manages to do so.
*/
virtual bool loadGlyphIfPossible (juce_wchar characterNeeded);
private:
//==============================================================================
class GlyphInfo;
OwnedArray<GlyphInfo> glyphs;
short lookupTable[128];
GlyphInfo* findGlyph (const juce_wchar character, bool loadIfNeeded) noexcept;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomTypeface)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A typeface that can be populated with custom glyphs.
You can create a CustomTypeface if you need one that contains your own glyphs,
or if you need to load a typeface from a Juce-formatted binary stream.
If you want to create a copy of a native face, you can use addGlyphsFromOtherTypeface()
to copy glyphs into this face.
NOTE! For most people this class is almost certainly NOT the right tool to use!
If what you want to do is to embed a font into your exe, then your best plan is
probably to embed your TTF/OTF font file into your binary using the Projucer,
and then call Typeface::createSystemTypefaceFor() to load it from memory.
@see Typeface, Font
@tags{Graphics}
*/
class JUCE_API CustomTypeface : public Typeface
{
public:
//==============================================================================
/** Creates a new, empty typeface. */
CustomTypeface();
/** Loads a typeface from a previously saved stream.
The stream must have been created by writeToStream().
NOTE! Since this class was written, support was added for loading real font files from
memory, so for most people, using Typeface::createSystemTypefaceFor() to load a real font
is more appropriate than using this class to store it in a proprietary format.
@see writeToStream
*/
explicit CustomTypeface (InputStream& serialisedTypefaceStream);
/** Destructor. */
~CustomTypeface() override;
//==============================================================================
/** Resets this typeface, deleting all its glyphs and settings. */
void clear();
/** Sets the vital statistics for the typeface.
@param fontFamily the typeface's font family
@param ascent the ascent - this is normalised to a height of 1.0 and this is
the value that will be returned by Typeface::getAscent(). The
descent is assumed to be (1.0 - ascent)
@param isBold should be true if the typeface is bold
@param isItalic should be true if the typeface is italic
@param defaultCharacter the character to be used as a replacement if there's
no glyph available for the character that's being drawn
*/
void setCharacteristics (const String& fontFamily, float ascent,
bool isBold, bool isItalic,
juce_wchar defaultCharacter) noexcept;
/** Sets the vital statistics for the typeface.
@param fontFamily the typeface's font family
@param fontStyle the typeface's font style
@param ascent the ascent - this is normalised to a height of 1.0 and this is
the value that will be returned by Typeface::getAscent(). The
descent is assumed to be (1.0 - ascent)
@param defaultCharacter the character to be used as a replacement if there's
no glyph available for the character that's being drawn
*/
void setCharacteristics (const String& fontFamily, const String& fontStyle,
float ascent, juce_wchar defaultCharacter) noexcept;
/** Adds a glyph to the typeface.
The path that is passed in is normalised so that the font height is 1.0, and its
origin is the anchor point of the character on its baseline.
The width is the nominal width of the character, and any extra kerning values that
are specified will be added to this width.
*/
void addGlyph (juce_wchar character, const Path& path, float width) noexcept;
/** Specifies an extra kerning amount to be used between a pair of characters.
The amount will be added to the nominal width of the first character when laying out a string.
*/
void addKerningPair (juce_wchar char1, juce_wchar char2, float extraAmount) noexcept;
/** Adds a range of glyphs from another typeface.
This will attempt to pull in the paths and kerning information from another typeface and
add it to this one.
*/
void addGlyphsFromOtherTypeface (Typeface& typefaceToCopy, juce_wchar characterStartIndex, int numCharacters) noexcept;
/** Saves this typeface as a Juce-formatted font file.
A CustomTypeface can be created to reload the data that is written - see the CustomTypeface
constructor.
NOTE! Since this class was written, support was added for loading real font files from
memory, so for most people, using Typeface::createSystemTypefaceFor() to load a real font
is more appropriate than using this class to store it in a proprietary format.
*/
bool writeToStream (OutputStream& outputStream);
//==============================================================================
// The following methods implement the basic Typeface behaviour.
float getAscent() const override;
float getDescent() const override;
float getHeightToPointsFactor() const override;
float getStringWidth (const String&) override;
void getGlyphPositions (const String&, Array<int>& glyphs, Array<float>& xOffsets) override;
bool getOutlineForGlyph (int glyphNumber, Path&) override;
EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform&, float fontHeight) override;
protected:
//==============================================================================
juce_wchar defaultCharacter;
float ascent;
//==============================================================================
/** If a subclass overrides this, it can load glyphs into the font on-demand.
When methods such as getGlyphPositions() or getOutlineForGlyph() are asked for a
particular character and there's no corresponding glyph, they'll call this
method so that a subclass can try to add that glyph, returning true if it
manages to do so.
*/
virtual bool loadGlyphIfPossible (juce_wchar characterNeeded);
private:
//==============================================================================
class GlyphInfo;
OwnedArray<GlyphInfo> glyphs;
short lookupTable[128];
GlyphInfo* findGlyph (const juce_wchar character, bool loadIfNeeded) noexcept;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomTypeface)
};
} // namespace juce

File diff suppressed because it is too large Load Diff

View File

@ -1,483 +1,488 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
Represents a particular font, including its size, style, etc.
Apart from the typeface to be used, a Font object also dictates whether
the font is bold, italic, underlined, how big it is, and its kerning and
horizontal scale factor.
@see Typeface
@tags{Graphics}
*/
class JUCE_API Font final
{
public:
//==============================================================================
/** A combination of these values is used by the constructor to specify the
style of font to use.
*/
enum FontStyleFlags
{
plain = 0, /**< indicates a plain, non-bold, non-italic version of the font. @see setStyleFlags */
bold = 1, /**< boldens the font. @see setStyleFlags */
italic = 2, /**< finds an italic version of the font. @see setStyleFlags */
underlined = 4 /**< underlines the font. @see setStyleFlags */
};
//==============================================================================
/** Creates a sans-serif font in a given size.
@param fontHeight the height in pixels (can be fractional)
@param styleFlags the style to use - this can be a combination of the
Font::bold, Font::italic and Font::underlined, or
just Font::plain for the normal style.
@see FontStyleFlags, getDefaultSansSerifFontName
*/
Font (float fontHeight, int styleFlags = plain);
/** Creates a font with a given typeface and parameters.
@param typefaceName the font family of the typeface to use
@param fontHeight the height in pixels (can be fractional)
@param styleFlags the style to use - this can be a combination of the
Font::bold, Font::italic and Font::underlined, or
just Font::plain for the normal style.
@see FontStyleFlags, getDefaultSansSerifFontName
*/
Font (const String& typefaceName, float fontHeight, int styleFlags);
/** Creates a font with a given typeface and parameters.
@param typefaceName the font family of the typeface to use
@param typefaceStyle the font style of the typeface to use
@param fontHeight the height in pixels (can be fractional)
*/
Font (const String& typefaceName, const String& typefaceStyle, float fontHeight);
/** Creates a copy of another Font object. */
Font (const Font& other) noexcept;
/** Creates a font for a typeface. */
Font (const Typeface::Ptr& typeface);
/** Creates a basic sans-serif font at a default height.
You should use one of the other constructors for creating a font that you're planning
on drawing with - this constructor is here to help initialise objects before changing
the font's settings later.
*/
Font();
/** Move constructor */
Font (Font&& other) noexcept;
/** Move assignment operator */
Font& operator= (Font&& other) noexcept;
/** Copies this font from another one. */
Font& operator= (const Font& other) noexcept;
bool operator== (const Font& other) const noexcept;
bool operator!= (const Font& other) const noexcept;
/** Destructor. */
~Font() noexcept;
//==============================================================================
/** Changes the font family of the typeface.
e.g. "Arial", "Courier", etc.
This may also be set to Font::getDefaultSansSerifFontName(), Font::getDefaultSerifFontName(),
or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font family names,
but are generic font family names that are used to represent the various default fonts.
If you need to know the exact typeface font family being used, you can call
Font::getTypefacePtr()->getName(), which will give you the platform-specific font family.
If a suitable font isn't found on the machine, it'll just use a default instead.
*/
void setTypefaceName (const String& faceName);
/** Returns the font family of the typeface that this font uses.
e.g. "Arial", "Courier", etc.
This may also be set to Font::getDefaultSansSerifFontName(), Font::getDefaultSerifFontName(),
or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font family names,
but are generic font family names that are used to represent the various default fonts.
If you need to know the exact typeface font family being used, you can call
Font::getTypefacePtr()->getName(), which will give you the platform-specific font family.
*/
String getTypefaceName() const noexcept;
//==============================================================================
/** Returns the font style of the typeface that this font uses.
@see withTypefaceStyle, getAvailableStyles()
*/
String getTypefaceStyle() const noexcept;
/** Changes the font style of the typeface.
@see getAvailableStyles()
*/
void setTypefaceStyle (const String& newStyle);
/** Returns a copy of this font with a new typeface style.
@see getAvailableStyles()
*/
Font withTypefaceStyle (const String& newStyle) const;
/** Returns a list of the styles that this font can use. */
StringArray getAvailableStyles() const;
//==============================================================================
/** Returns a typeface font family that represents the default sans-serif font.
This is also the typeface that will be used when a font is created without
specifying any typeface details.
Note that this method just returns a generic placeholder string that means "the default
sans-serif font" - it's not the actual font family of this font.
@see setTypefaceName, getDefaultSerifFontName, getDefaultMonospacedFontName
*/
static const String& getDefaultSansSerifFontName();
/** Returns a typeface font family that represents the default serif font.
Note that this method just returns a generic placeholder string that means "the default
serif font" - it's not the actual font family of this font.
@see setTypefaceName, getDefaultSansSerifFontName, getDefaultMonospacedFontName
*/
static const String& getDefaultSerifFontName();
/** Returns a typeface font family that represents the default monospaced font.
Note that this method just returns a generic placeholder string that means "the default
monospaced font" - it's not the actual font family of this font.
@see setTypefaceName, getDefaultSansSerifFontName, getDefaultSerifFontName
*/
static const String& getDefaultMonospacedFontName();
/** Returns a font style name that represents the default style.
Note that this method just returns a generic placeholder string that means "the default
font style" - it's not the actual name of the font style of any particular font.
@see setTypefaceStyle
*/
static const String& getDefaultStyle();
/** Returns the default system typeface for the given font. */
static Typeface::Ptr getDefaultTypefaceForFont (const Font& font);
//==============================================================================
/** Returns a copy of this font with a new height. */
Font withHeight (float height) const;
/** Returns a copy of this font with a new height, specified in points. */
Font withPointHeight (float heightInPoints) const;
/** Changes the font's height.
@see getHeight, withHeight, setHeightWithoutChangingWidth
*/
void setHeight (float newHeight);
/** Changes the font's height without changing its width.
This alters the horizontal scale to compensate for the change in height.
*/
void setHeightWithoutChangingWidth (float newHeight);
/** Returns the total height of this font, in pixels.
This is the maximum height, from the top of the ascent to the bottom of the
descenders.
@see withHeight, setHeightWithoutChangingWidth, getAscent
*/
float getHeight() const noexcept;
/** Returns the total height of this font, in points.
This is the maximum height, from the top of the ascent to the bottom of the
descenders.
@see withPointHeight, getHeight
*/
float getHeightInPoints() const;
/** Returns the height of the font above its baseline, in pixels.
This is the maximum height from the baseline to the top.
@see getHeight, getDescent
*/
float getAscent() const;
/** Returns the height of the font above its baseline, in points.
This is the maximum height from the baseline to the top.
@see getHeight, getDescent
*/
float getAscentInPoints() const;
/** Returns the amount that the font descends below its baseline, in pixels.
This is calculated as (getHeight() - getAscent()).
@see getAscent, getHeight
*/
float getDescent() const;
/** Returns the amount that the font descends below its baseline, in points.
This is calculated as (getHeight() - getAscent()).
@see getAscent, getHeight
*/
float getDescentInPoints() const;
//==============================================================================
/** Returns the font's style flags.
This will return a bitwise-or'ed combination of values from the FontStyleFlags
enum, to describe whether the font is bold, italic, etc.
@see FontStyleFlags, withStyle
*/
int getStyleFlags() const noexcept;
/** Returns a copy of this font with the given set of style flags.
@param styleFlags a bitwise-or'ed combination of values from the FontStyleFlags enum.
@see FontStyleFlags, getStyleFlags
*/
Font withStyle (int styleFlags) const;
/** Changes the font's style.
@param newFlags a bitwise-or'ed combination of values from the FontStyleFlags enum.
@see FontStyleFlags, withStyle
*/
void setStyleFlags (int newFlags);
//==============================================================================
/** Makes the font bold or non-bold. */
void setBold (bool shouldBeBold);
/** Returns a copy of this font with the bold attribute set.
If the font does not have a bold version, this will return the default font.
*/
Font boldened() const;
/** Returns true if the font is bold. */
bool isBold() const noexcept;
/** Makes the font italic or non-italic. */
void setItalic (bool shouldBeItalic);
/** Returns a copy of this font with the italic attribute set. */
Font italicised() const;
/** Returns true if the font is italic. */
bool isItalic() const noexcept;
/** Makes the font underlined or non-underlined. */
void setUnderline (bool shouldBeUnderlined);
/** Returns true if the font is underlined. */
bool isUnderlined() const noexcept;
//==============================================================================
/** Returns the font's horizontal scale.
A value of 1.0 is the normal scale, less than this will be narrower, greater
than 1.0 will be stretched out.
@see withHorizontalScale
*/
float getHorizontalScale() const noexcept;
/** Returns a copy of this font with a new horizontal scale.
@param scaleFactor a value of 1.0 is the normal scale, less than this will be
narrower, greater than 1.0 will be stretched out.
@see getHorizontalScale
*/
Font withHorizontalScale (float scaleFactor) const;
/** Changes the font's horizontal scale factor.
@param scaleFactor a value of 1.0 is the normal scale, less than this will be
narrower, greater than 1.0 will be stretched out.
*/
void setHorizontalScale (float scaleFactor);
/** Returns the minimum horizontal scale to which fonts may be squashed when trying to
create a layout.
@see setDefaultMinimumHorizontalScaleFactor
*/
static float getDefaultMinimumHorizontalScaleFactor() noexcept;
/** Sets the minimum horizontal scale to which fonts may be squashed when trying to
create a text layout.
@see getDefaultMinimumHorizontalScaleFactor
*/
static void setDefaultMinimumHorizontalScaleFactor (float newMinimumScaleFactor) noexcept;
/** Returns the font's kerning.
This is the extra space added between adjacent characters, as a proportion
of the font's height.
A value of zero is normal spacing, positive values will spread the letters
out more, and negative values make them closer together.
*/
float getExtraKerningFactor() const noexcept;
/** Returns a copy of this font with a new kerning factor.
@param extraKerning a multiple of the font's height that will be added
to space between the characters. So a value of zero is
normal spacing, positive values spread the letters out,
negative values make them closer together.
*/
Font withExtraKerningFactor (float extraKerning) const;
/** Changes the font's kerning.
@param extraKerning a multiple of the font's height that will be added
to space between the characters. So a value of zero is
normal spacing, positive values spread the letters out,
negative values make them closer together.
*/
void setExtraKerningFactor (float extraKerning);
//==============================================================================
/** Changes all the font's characteristics with one call. */
void setSizeAndStyle (float newHeight,
int newStyleFlags,
float newHorizontalScale,
float newKerningAmount);
/** Changes all the font's characteristics with one call. */
void setSizeAndStyle (float newHeight,
const String& newStyle,
float newHorizontalScale,
float newKerningAmount);
//==============================================================================
/** Returns the total width of a string as it would be drawn using this font.
For a more accurate floating-point result, use getStringWidthFloat().
*/
int getStringWidth (const String& text) const;
/** Returns the total width of a string as it would be drawn using this font.
@see getStringWidth
*/
float getStringWidthFloat (const String& text) const;
/** Returns the series of glyph numbers and their x offsets needed to represent a string.
An extra x offset is added at the end of the run, to indicate where the right hand
edge of the last character is.
*/
void getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) const;
//==============================================================================
#ifndef DOXYGEN
/** Returns the typeface used by this font.
Note that the object returned may go out of scope if this font is deleted
or has its style changed.
*/
[[deprecated ("This method is unsafe, use getTypefacePtr() instead.")]]
Typeface* getTypeface() const;
#endif
/** Returns the typeface used by this font. */
Typeface::Ptr getTypefacePtr() const;
/** Creates an array of Font objects to represent all the fonts on the system.
If you just need the font family names of the typefaces, you can also use
findAllTypefaceNames() instead.
@param results the array to which new Font objects will be added.
*/
static void findFonts (Array<Font>& results);
/** Returns a list of all the available typeface font families.
The names returned can be passed into setTypefaceName().
You can use this instead of findFonts() if you only need their font family names,
and not font objects.
*/
static StringArray findAllTypefaceNames();
/** Returns a list of all the available typeface font styles.
The names returned can be passed into setTypefaceStyle().
You can use this instead of findFonts() if you only need their styles, and not
font objects.
*/
static StringArray findAllTypefaceStyles (const String& family);
//==============================================================================
/** Returns the font family of the typeface to be used for rendering glyphs that aren't
found in the requested typeface.
*/
static const String& getFallbackFontName();
/** Sets the (platform-specific) font family of the typeface to use to find glyphs that
aren't available in whatever font you're trying to use.
*/
static void setFallbackFontName (const String& name);
/** Returns the font style of the typeface to be used for rendering glyphs that aren't
found in the requested typeface.
*/
static const String& getFallbackFontStyle();
/** Sets the (platform-specific) font style of the typeface to use to find glyphs that
aren't available in whatever font you're trying to use.
*/
static void setFallbackFontStyle (const String& style);
//==============================================================================
/** Creates a string to describe this font.
The string will contain information to describe the font's typeface, size, and
style. To recreate the font from this string, use fromString().
*/
String toString() const;
/** Recreates a font from its stringified encoding.
This method takes a string that was created by toString(), and recreates the
original font.
*/
static Font fromString (const String& fontDescription);
private:
//==============================================================================
class SharedFontInternal;
ReferenceCountedObjectPtr<SharedFontInternal> font;
void dupeInternalIfShared();
void checkTypefaceSuitability();
float getHeightToPointsFactor() const;
JUCE_LEAK_DETECTOR (Font)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
Represents a particular font, including its size, style, etc.
Apart from the typeface to be used, a Font object also dictates whether
the font is bold, italic, underlined, how big it is, and its kerning and
horizontal scale factor.
@see Typeface
@tags{Graphics}
*/
class JUCE_API Font final
{
public:
//==============================================================================
/** A combination of these values is used by the constructor to specify the
style of font to use.
*/
enum FontStyleFlags
{
plain = 0, /**< indicates a plain, non-bold, non-italic version of the font. @see setStyleFlags */
bold = 1, /**< boldens the font. @see setStyleFlags */
italic = 2, /**< finds an italic version of the font. @see setStyleFlags */
underlined = 4 /**< underlines the font. @see setStyleFlags */
};
//==============================================================================
/** Creates a sans-serif font in a given size.
@param fontHeight the height in pixels (can be fractional)
@param styleFlags the style to use - this can be a combination of the
Font::bold, Font::italic and Font::underlined, or
just Font::plain for the normal style.
@see FontStyleFlags, getDefaultSansSerifFontName
*/
Font (float fontHeight, int styleFlags = plain);
/** Creates a font with a given typeface and parameters.
@param typefaceName the font family of the typeface to use
@param fontHeight the height in pixels (can be fractional)
@param styleFlags the style to use - this can be a combination of the
Font::bold, Font::italic and Font::underlined, or
just Font::plain for the normal style.
@see FontStyleFlags, getDefaultSansSerifFontName
*/
Font (const String& typefaceName, float fontHeight, int styleFlags);
/** Creates a font with a given typeface and parameters.
@param typefaceName the font family of the typeface to use
@param typefaceStyle the font style of the typeface to use
@param fontHeight the height in pixels (can be fractional)
*/
Font (const String& typefaceName, const String& typefaceStyle, float fontHeight);
/** Creates a copy of another Font object. */
Font (const Font& other) noexcept;
/** Creates a font for a typeface. */
Font (const Typeface::Ptr& typeface);
/** Creates a basic sans-serif font at a default height.
You should use one of the other constructors for creating a font that you're planning
on drawing with - this constructor is here to help initialise objects before changing
the font's settings later.
*/
Font();
/** Move constructor */
Font (Font&& other) noexcept;
/** Move assignment operator */
Font& operator= (Font&& other) noexcept;
/** Copies this font from another one. */
Font& operator= (const Font& other) noexcept;
bool operator== (const Font& other) const noexcept;
bool operator!= (const Font& other) const noexcept;
/** Destructor. */
~Font() noexcept;
//==============================================================================
/** Changes the font family of the typeface.
e.g. "Arial", "Courier", etc.
This may also be set to Font::getDefaultSansSerifFontName(), Font::getDefaultSerifFontName(),
or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font family names,
but are generic font family names that are used to represent the various default fonts.
If you need to know the exact typeface font family being used, you can call
Font::getTypefacePtr()->getName(), which will give you the platform-specific font family.
If a suitable font isn't found on the machine, it'll just use a default instead.
*/
void setTypefaceName (const String& faceName);
/** Returns the font family of the typeface that this font uses.
e.g. "Arial", "Courier", etc.
This may also be set to Font::getDefaultSansSerifFontName(), Font::getDefaultSerifFontName(),
or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font family names,
but are generic font family names that are used to represent the various default fonts.
If you need to know the exact typeface font family being used, you can call
Font::getTypefacePtr()->getName(), which will give you the platform-specific font family.
*/
String getTypefaceName() const noexcept;
//==============================================================================
/** Returns the font style of the typeface that this font uses.
@see withTypefaceStyle, getAvailableStyles()
*/
String getTypefaceStyle() const noexcept;
/** Changes the font style of the typeface.
@see getAvailableStyles()
*/
void setTypefaceStyle (const String& newStyle);
/** Returns a copy of this font with a new typeface style.
@see getAvailableStyles()
*/
JUCE_NODISCARD Font withTypefaceStyle (const String& newStyle) const;
/** Returns a list of the styles that this font can use. */
StringArray getAvailableStyles() const;
//==============================================================================
/** Returns a typeface font family that represents the default sans-serif font.
This is also the typeface that will be used when a font is created without
specifying any typeface details.
Note that this method just returns a generic placeholder string that means "the default
sans-serif font" - it's not the actual font family of this font.
@see setTypefaceName, getDefaultSerifFontName, getDefaultMonospacedFontName
*/
static const String& getDefaultSansSerifFontName();
/** Returns a typeface font family that represents the default serif font.
Note that this method just returns a generic placeholder string that means "the default
serif font" - it's not the actual font family of this font.
@see setTypefaceName, getDefaultSansSerifFontName, getDefaultMonospacedFontName
*/
static const String& getDefaultSerifFontName();
/** Returns a typeface font family that represents the default monospaced font.
Note that this method just returns a generic placeholder string that means "the default
monospaced font" - it's not the actual font family of this font.
@see setTypefaceName, getDefaultSansSerifFontName, getDefaultSerifFontName
*/
static const String& getDefaultMonospacedFontName();
/** Returns a font style name that represents the default style.
Note that this method just returns a generic placeholder string that means "the default
font style" - it's not the actual name of the font style of any particular font.
@see setTypefaceStyle
*/
static const String& getDefaultStyle();
/** Returns the default system typeface for the given font. */
static Typeface::Ptr getDefaultTypefaceForFont (const Font& font);
//==============================================================================
/** Returns a copy of this font with a new height. */
JUCE_NODISCARD Font withHeight (float height) const;
/** Returns a copy of this font with a new height, specified in points. */
JUCE_NODISCARD Font withPointHeight (float heightInPoints) const;
/** Changes the font's height.
@see getHeight, withHeight, setHeightWithoutChangingWidth
*/
void setHeight (float newHeight);
/** Changes the font's height without changing its width.
This alters the horizontal scale to compensate for the change in height.
*/
void setHeightWithoutChangingWidth (float newHeight);
/** Returns the total height of this font, in pixels.
This is the maximum height, from the top of the ascent to the bottom of the
descenders.
@see withHeight, setHeightWithoutChangingWidth, getAscent
*/
float getHeight() const noexcept;
/** Returns the total height of this font, in points.
This is the maximum height, from the top of the ascent to the bottom of the
descenders.
@see withPointHeight, getHeight
*/
float getHeightInPoints() const;
/** Returns the height of the font above its baseline, in pixels.
This is the maximum height from the baseline to the top.
@see getHeight, getDescent
*/
float getAscent() const;
/** Returns the height of the font above its baseline, in points.
This is the maximum height from the baseline to the top.
@see getHeight, getDescent
*/
float getAscentInPoints() const;
/** Returns the amount that the font descends below its baseline, in pixels.
This is calculated as (getHeight() - getAscent()).
@see getAscent, getHeight
*/
float getDescent() const;
/** Returns the amount that the font descends below its baseline, in points.
This is calculated as (getHeight() - getAscent()).
@see getAscent, getHeight
*/
float getDescentInPoints() const;
//==============================================================================
/** Returns the font's style flags.
This will return a bitwise-or'ed combination of values from the FontStyleFlags
enum, to describe whether the font is bold, italic, etc.
@see FontStyleFlags, withStyle
*/
int getStyleFlags() const noexcept;
/** Returns a copy of this font with the given set of style flags.
@param styleFlags a bitwise-or'ed combination of values from the FontStyleFlags enum.
@see FontStyleFlags, getStyleFlags
*/
JUCE_NODISCARD Font withStyle (int styleFlags) const;
/** Changes the font's style.
@param newFlags a bitwise-or'ed combination of values from the FontStyleFlags enum.
@see FontStyleFlags, withStyle
*/
void setStyleFlags (int newFlags);
//==============================================================================
/** Makes the font bold or non-bold. */
void setBold (bool shouldBeBold);
/** Returns a copy of this font with the bold attribute set.
If the font does not have a bold version, this will return the default font.
*/
JUCE_NODISCARD Font boldened() const;
/** Returns true if the font is bold. */
bool isBold() const noexcept;
/** Makes the font italic or non-italic. */
void setItalic (bool shouldBeItalic);
/** Returns a copy of this font with the italic attribute set. */
JUCE_NODISCARD Font italicised() const;
/** Returns true if the font is italic. */
bool isItalic() const noexcept;
/** Makes the font underlined or non-underlined. */
void setUnderline (bool shouldBeUnderlined);
/** Returns true if the font is underlined. */
bool isUnderlined() const noexcept;
//==============================================================================
/** Returns the font's horizontal scale.
A value of 1.0 is the normal scale, less than this will be narrower, greater
than 1.0 will be stretched out.
@see withHorizontalScale
*/
float getHorizontalScale() const noexcept;
/** Returns a copy of this font with a new horizontal scale.
@param scaleFactor a value of 1.0 is the normal scale, less than this will be
narrower, greater than 1.0 will be stretched out.
@see getHorizontalScale
*/
JUCE_NODISCARD Font withHorizontalScale (float scaleFactor) const;
/** Changes the font's horizontal scale factor.
@param scaleFactor a value of 1.0 is the normal scale, less than this will be
narrower, greater than 1.0 will be stretched out.
*/
void setHorizontalScale (float scaleFactor);
/** Returns the minimum horizontal scale to which fonts may be squashed when trying to
create a layout.
@see setDefaultMinimumHorizontalScaleFactor
*/
static float getDefaultMinimumHorizontalScaleFactor() noexcept;
/** Sets the minimum horizontal scale to which fonts may be squashed when trying to
create a text layout.
@see getDefaultMinimumHorizontalScaleFactor
*/
static void setDefaultMinimumHorizontalScaleFactor (float newMinimumScaleFactor) noexcept;
/** Returns the font's kerning.
This is the extra space added between adjacent characters, as a proportion
of the font's height.
A value of zero is normal spacing, positive values will spread the letters
out more, and negative values make them closer together.
*/
float getExtraKerningFactor() const noexcept;
/** Returns a copy of this font with a new kerning factor.
@param extraKerning a multiple of the font's height that will be added
to space between the characters. So a value of zero is
normal spacing, positive values spread the letters out,
negative values make them closer together.
*/
JUCE_NODISCARD Font withExtraKerningFactor (float extraKerning) const;
/** Changes the font's kerning.
@param extraKerning a multiple of the font's height that will be added
to space between the characters. So a value of zero is
normal spacing, positive values spread the letters out,
negative values make them closer together.
*/
void setExtraKerningFactor (float extraKerning);
//==============================================================================
/** Changes all the font's characteristics with one call. */
void setSizeAndStyle (float newHeight,
int newStyleFlags,
float newHorizontalScale,
float newKerningAmount);
/** Changes all the font's characteristics with one call. */
void setSizeAndStyle (float newHeight,
const String& newStyle,
float newHorizontalScale,
float newKerningAmount);
//==============================================================================
/** Returns the total width of a string as it would be drawn using this font.
For a more accurate floating-point result, use getStringWidthFloat().
*/
int getStringWidth (const String& text) const;
/** Returns the total width of a string as it would be drawn using this font.
@see getStringWidth
*/
float getStringWidthFloat (const String& text) const;
/** Returns the series of glyph numbers and their x offsets needed to represent a string.
An extra x offset is added at the end of the run, to indicate where the right hand
edge of the last character is.
*/
void getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) const;
//==============================================================================
#ifndef DOXYGEN
/** Returns the typeface used by this font.
Note that the object returned may go out of scope if this font is deleted
or has its style changed.
*/
[[deprecated ("This method is unsafe, use getTypefacePtr() instead.")]]
Typeface* getTypeface() const;
#endif
/** Returns the typeface used by this font. */
Typeface::Ptr getTypefacePtr() const;
/** Creates an array of Font objects to represent all the fonts on the system.
If you just need the font family names of the typefaces, you can also use
findAllTypefaceNames() instead.
@param results the array to which new Font objects will be added.
*/
static void findFonts (Array<Font>& results);
/** Returns a list of all the available typeface font families.
The names returned can be passed into setTypefaceName().
You can use this instead of findFonts() if you only need their font family names,
and not font objects.
*/
static StringArray findAllTypefaceNames();
/** Returns a list of all the available typeface font styles.
The names returned can be passed into setTypefaceStyle().
You can use this instead of findFonts() if you only need their styles, and not
font objects.
*/
static StringArray findAllTypefaceStyles (const String& family);
//==============================================================================
/** Returns the font family of the typeface to be used for rendering glyphs that aren't
found in the requested typeface.
*/
static const String& getFallbackFontName();
/** Sets the (platform-specific) font family of the typeface to use to find glyphs that
aren't available in whatever font you're trying to use.
*/
static void setFallbackFontName (const String& name);
/** Returns the font style of the typeface to be used for rendering glyphs that aren't
found in the requested typeface.
*/
static const String& getFallbackFontStyle();
/** Sets the (platform-specific) font style of the typeface to use to find glyphs that
aren't available in whatever font you're trying to use.
*/
static void setFallbackFontStyle (const String& style);
//==============================================================================
/** Creates a string to describe this font.
The string will contain information to describe the font's typeface, size, and
style. To recreate the font from this string, use fromString().
*/
String toString() const;
/** Recreates a font from its stringified encoding.
This method takes a string that was created by toString(), and recreates the
original font.
*/
static Font fromString (const String& fontDescription);
private:
//==============================================================================
static bool compare (const Font&, const Font&) noexcept;
void dupeInternalIfShared();
void checkTypefaceSuitability();
float getHeightToPointsFactor() const;
friend struct GraphicsFontHelpers;
class SharedFontInternal;
ReferenceCountedObjectPtr<SharedFontInternal> font;
JUCE_LEAK_DETECTOR (Font)
};
} // namespace juce

File diff suppressed because it is too large Load Diff

View File

@ -1,328 +1,321 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A glyph from a particular font, with a particular size, style,
typeface and position.
You should rarely need to use this class directly - for most purposes, the
GlyphArrangement class will do what you need for text layout.
@see GlyphArrangement, Font
@tags{Graphics}
*/
class JUCE_API PositionedGlyph final
{
public:
//==============================================================================
PositionedGlyph() noexcept;
PositionedGlyph (const Font& font, juce_wchar character, int glyphNumber,
float anchorX, float baselineY, float width, bool isWhitespace);
PositionedGlyph (const PositionedGlyph&) = default;
PositionedGlyph& operator= (const PositionedGlyph&) = default;
PositionedGlyph (PositionedGlyph&&) noexcept = default;
PositionedGlyph& operator= (PositionedGlyph&&) noexcept = default;
~PositionedGlyph();
/** Returns the character the glyph represents. */
juce_wchar getCharacter() const noexcept { return character; }
/** Checks whether the glyph is actually empty. */
bool isWhitespace() const noexcept { return whitespace; }
/** Returns the position of the glyph's left-hand edge. */
float getLeft() const noexcept { return x; }
/** Returns the position of the glyph's right-hand edge. */
float getRight() const noexcept { return x + w; }
/** Returns the y position of the glyph's baseline. */
float getBaselineY() const noexcept { return y; }
/** Returns the y position of the top of the glyph. */
float getTop() const { return y - font.getAscent(); }
/** Returns the y position of the bottom of the glyph. */
float getBottom() const { return y + font.getDescent(); }
/** Returns the bounds of the glyph. */
Rectangle<float> getBounds() const { return { x, getTop(), w, font.getHeight() }; }
//==============================================================================
/** Shifts the glyph's position by a relative amount. */
void moveBy (float deltaX, float deltaY);
//==============================================================================
/** Draws the glyph into a graphics context.
(Note that this may change the context's currently selected font).
*/
void draw (Graphics& g) const;
/** Draws the glyph into a graphics context, with an extra transform applied to it.
(Note that this may change the context's currently selected font).
*/
void draw (Graphics& g, AffineTransform transform) const;
/** Returns the path for this glyph.
@param path the glyph's outline will be appended to this path
*/
void createPath (Path& path) const;
/** Checks to see if a point lies within this glyph. */
bool hitTest (float x, float y) const;
private:
//==============================================================================
friend class GlyphArrangement;
Font font;
juce_wchar character;
int glyph;
float x, y, w;
bool whitespace;
JUCE_LEAK_DETECTOR (PositionedGlyph)
};
//==============================================================================
/**
A set of glyphs, each with a position.
You can create a GlyphArrangement, text to it and then draw it onto a
graphics context. It's used internally by the text methods in the
Graphics class, but can be used directly if more control is needed.
@see Font, PositionedGlyph
@tags{Graphics}
*/
class JUCE_API GlyphArrangement final
{
public:
//==============================================================================
/** Creates an empty arrangement. */
GlyphArrangement();
GlyphArrangement (const GlyphArrangement&) = default;
GlyphArrangement& operator= (const GlyphArrangement&) = default;
GlyphArrangement (GlyphArrangement&&) = default;
GlyphArrangement& operator= (GlyphArrangement&&) = default;
/** Destructor. */
~GlyphArrangement() = default;
//==============================================================================
/** Returns the total number of glyphs in the arrangement. */
int getNumGlyphs() const noexcept { return glyphs.size(); }
/** Returns one of the glyphs from the arrangement.
@param index the glyph's index, from 0 to (getNumGlyphs() - 1). Be
careful not to pass an out-of-range index here, as it
doesn't do any bounds-checking.
*/
PositionedGlyph& getGlyph (int index) noexcept;
const PositionedGlyph* begin() const { return glyphs.begin(); }
const PositionedGlyph* end() const { return glyphs.end(); }
//==============================================================================
/** Clears all text from the arrangement and resets it. */
void clear();
/** Appends a line of text to the arrangement.
This will add the text as a single line, where x is the left-hand edge of the
first character, and y is the position for the text's baseline.
If the text contains new-lines or carriage-returns, this will ignore them - use
addJustifiedText() to add multi-line arrangements.
*/
void addLineOfText (const Font& font,
const String& text,
float x, float y);
/** Adds a line of text, truncating it if it's wider than a specified size.
This is the same as addLineOfText(), but if the line's width exceeds the value
specified in maxWidthPixels, it will be truncated using either ellipsis (i.e. dots: "..."),
if useEllipsis is true, or if this is false, it will just drop any subsequent characters.
*/
void addCurtailedLineOfText (const Font& font,
const String& text,
float x, float y,
float maxWidthPixels,
bool useEllipsis);
/** Adds some multi-line text, breaking lines at word-boundaries if they are too wide.
This will add text to the arrangement, breaking it into new lines either where there
is a new-line or carriage-return character in the text, or where a line's width
exceeds the value set in maxLineWidth.
Each line that is added will be laid out using the flags set in horizontalLayout, so
the lines can be left- or right-justified, or centred horizontally in the space
between x and (x + maxLineWidth).
The y coordinate is the position of the baseline of the first line of text - subsequent
lines will be placed below it, separated by a distance of font.getHeight() + leading.
*/
void addJustifiedText (const Font& font,
const String& text,
float x, float y,
float maxLineWidth,
Justification horizontalLayout,
float leading = 0.0f);
/** Tries to fit some text within a given space.
This does its best to make the given text readable within the specified rectangle,
so it's useful for labelling things.
If the text is too big, it'll be squashed horizontally or broken over multiple lines
if the maximumLinesToUse value allows this. If the text just won't fit into the space,
it'll cram as much as possible in there, and put some ellipsis at the end to show that
it's been truncated.
A Justification parameter lets you specify how the text is laid out within the rectangle,
both horizontally and vertically.
The minimumHorizontalScale parameter specifies how much the text can be squashed horizontally
to try to squeeze it into the space. If you don't want any horizontal scaling to occur, you
can set this value to 1.0f. Pass 0 if you want it to use the default value.
@see Graphics::drawFittedText
*/
void addFittedText (const Font& font,
const String& text,
float x, float y, float width, float height,
Justification layout,
int maximumLinesToUse,
float minimumHorizontalScale = 0.0f);
/** Appends another glyph arrangement to this one. */
void addGlyphArrangement (const GlyphArrangement&);
/** Appends a custom glyph to the arrangement. */
void addGlyph (const PositionedGlyph&);
//==============================================================================
/** Draws this glyph arrangement to a graphics context.
This uses cached bitmaps so is much faster than the draw (Graphics&, AffineTransform)
method, which renders the glyphs as filled vectors.
*/
void draw (const Graphics&) const;
/** Draws this glyph arrangement to a graphics context.
This renders the paths as filled vectors, so is far slower than the draw (Graphics&)
method for non-transformed arrangements.
*/
void draw (const Graphics&, AffineTransform) const;
/** Converts the set of glyphs into a path.
@param path the glyphs' outlines will be appended to this path
*/
void createPath (Path& path) const;
/** Looks for a glyph that contains the given coordinate.
@returns the index of the glyph, or -1 if none were found.
*/
int findGlyphIndexAt (float x, float y) const;
//==============================================================================
/** Finds the smallest rectangle that will enclose a subset of the glyphs.
@param startIndex the first glyph to test
@param numGlyphs the number of glyphs to include; if this is < 0, all glyphs after
startIndex will be included
@param includeWhitespace if true, the extent of any whitespace characters will also
be taken into account
*/
Rectangle<float> getBoundingBox (int startIndex, int numGlyphs, bool includeWhitespace) const;
/** Shifts a set of glyphs by a given amount.
@param startIndex the first glyph to transform
@param numGlyphs the number of glyphs to move; if this is < 0, all glyphs after
startIndex will be used
@param deltaX the amount to add to their x-positions
@param deltaY the amount to add to their y-positions
*/
void moveRangeOfGlyphs (int startIndex, int numGlyphs,
float deltaX, float deltaY);
/** Removes a set of glyphs from the arrangement.
@param startIndex the first glyph to remove
@param numGlyphs the number of glyphs to remove; if this is < 0, all glyphs after
startIndex will be deleted
*/
void removeRangeOfGlyphs (int startIndex, int numGlyphs);
/** Expands or compresses a set of glyphs horizontally.
@param startIndex the first glyph to transform
@param numGlyphs the number of glyphs to stretch; if this is < 0, all glyphs after
startIndex will be used
@param horizontalScaleFactor how much to scale their horizontal width by
*/
void stretchRangeOfGlyphs (int startIndex, int numGlyphs,
float horizontalScaleFactor);
/** Justifies a set of glyphs within a given space.
This moves the glyphs as a block so that the whole thing is located within the
given rectangle with the specified layout.
If the Justification::horizontallyJustified flag is specified, each line will
be stretched out to fill the specified width.
*/
void justifyGlyphs (int startIndex, int numGlyphs,
float x, float y, float width, float height,
Justification justification);
private:
//==============================================================================
Array<PositionedGlyph> glyphs;
int insertEllipsis (const Font&, float maxXPos, int startIndex, int endIndex);
int fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font&,
Justification, float minimumHorizontalScale);
void spreadOutLine (int start, int numGlyphs, float targetWidth);
void splitLines (const String&, Font, int start, float x, float y, float w, float h, int maxLines,
float lineWidth, Justification, float minimumHorizontalScale);
void addLinesWithLineBreaks (const String&, const Font&, float x, float y, float width, float height, Justification);
void drawGlyphUnderline (const Graphics&, const PositionedGlyph&, int, AffineTransform) const;
JUCE_LEAK_DETECTOR (GlyphArrangement)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A glyph from a particular font, with a particular size, style,
typeface and position.
You should rarely need to use this class directly - for most purposes, the
GlyphArrangement class will do what you need for text layout.
@see GlyphArrangement, Font
@tags{Graphics}
*/
class JUCE_API PositionedGlyph final
{
public:
//==============================================================================
PositionedGlyph() noexcept;
PositionedGlyph (const Font& font, juce_wchar character, int glyphNumber,
float anchorX, float baselineY, float width, bool isWhitespace);
/** Returns the character the glyph represents. */
juce_wchar getCharacter() const noexcept { return character; }
/** Checks whether the glyph is actually empty. */
bool isWhitespace() const noexcept { return whitespace; }
/** Returns the position of the glyph's left-hand edge. */
float getLeft() const noexcept { return x; }
/** Returns the position of the glyph's right-hand edge. */
float getRight() const noexcept { return x + w; }
/** Returns the y position of the glyph's baseline. */
float getBaselineY() const noexcept { return y; }
/** Returns the y position of the top of the glyph. */
float getTop() const { return y - font.getAscent(); }
/** Returns the y position of the bottom of the glyph. */
float getBottom() const { return y + font.getDescent(); }
/** Returns the bounds of the glyph. */
Rectangle<float> getBounds() const { return { x, getTop(), w, font.getHeight() }; }
//==============================================================================
/** Shifts the glyph's position by a relative amount. */
void moveBy (float deltaX, float deltaY);
//==============================================================================
/** Draws the glyph into a graphics context.
(Note that this may change the context's currently selected font).
*/
void draw (Graphics& g) const;
/** Draws the glyph into a graphics context, with an extra transform applied to it.
(Note that this may change the context's currently selected font).
*/
void draw (Graphics& g, AffineTransform transform) const;
/** Returns the path for this glyph.
@param path the glyph's outline will be appended to this path
*/
void createPath (Path& path) const;
/** Checks to see if a point lies within this glyph. */
bool hitTest (float x, float y) const;
private:
//==============================================================================
friend class GlyphArrangement;
Font font;
juce_wchar character;
int glyph;
float x, y, w;
bool whitespace;
JUCE_LEAK_DETECTOR (PositionedGlyph)
};
//==============================================================================
/**
A set of glyphs, each with a position.
You can create a GlyphArrangement, text to it and then draw it onto a
graphics context. It's used internally by the text methods in the
Graphics class, but can be used directly if more control is needed.
@see Font, PositionedGlyph
@tags{Graphics}
*/
class JUCE_API GlyphArrangement final
{
public:
//==============================================================================
/** Creates an empty arrangement. */
GlyphArrangement();
GlyphArrangement (const GlyphArrangement&) = default;
GlyphArrangement& operator= (const GlyphArrangement&) = default;
GlyphArrangement (GlyphArrangement&&) = default;
GlyphArrangement& operator= (GlyphArrangement&&) = default;
/** Destructor. */
~GlyphArrangement() = default;
//==============================================================================
/** Returns the total number of glyphs in the arrangement. */
int getNumGlyphs() const noexcept { return glyphs.size(); }
/** Returns one of the glyphs from the arrangement.
@param index the glyph's index, from 0 to (getNumGlyphs() - 1). Be
careful not to pass an out-of-range index here, as it
doesn't do any bounds-checking.
*/
PositionedGlyph& getGlyph (int index) noexcept;
const PositionedGlyph* begin() const { return glyphs.begin(); }
const PositionedGlyph* end() const { return glyphs.end(); }
//==============================================================================
/** Clears all text from the arrangement and resets it. */
void clear();
/** Appends a line of text to the arrangement.
This will add the text as a single line, where x is the left-hand edge of the
first character, and y is the position for the text's baseline.
If the text contains new-lines or carriage-returns, this will ignore them - use
addJustifiedText() to add multi-line arrangements.
*/
void addLineOfText (const Font& font,
const String& text,
float x, float y);
/** Adds a line of text, truncating it if it's wider than a specified size.
This is the same as addLineOfText(), but if the line's width exceeds the value
specified in maxWidthPixels, it will be truncated using either ellipsis (i.e. dots: "..."),
if useEllipsis is true, or if this is false, it will just drop any subsequent characters.
*/
void addCurtailedLineOfText (const Font& font,
const String& text,
float x, float y,
float maxWidthPixels,
bool useEllipsis);
/** Adds some multi-line text, breaking lines at word-boundaries if they are too wide.
This will add text to the arrangement, breaking it into new lines either where there
is a new-line or carriage-return character in the text, or where a line's width
exceeds the value set in maxLineWidth.
Each line that is added will be laid out using the flags set in horizontalLayout, so
the lines can be left- or right-justified, or centred horizontally in the space
between x and (x + maxLineWidth).
The y coordinate is the position of the baseline of the first line of text - subsequent
lines will be placed below it, separated by a distance of font.getHeight() + leading.
*/
void addJustifiedText (const Font& font,
const String& text,
float x, float y,
float maxLineWidth,
Justification horizontalLayout,
float leading = 0.0f);
/** Tries to fit some text within a given space.
This does its best to make the given text readable within the specified rectangle,
so it's useful for labelling things.
If the text is too big, it'll be squashed horizontally or broken over multiple lines
if the maximumLinesToUse value allows this. If the text just won't fit into the space,
it'll cram as much as possible in there, and put some ellipsis at the end to show that
it's been truncated.
A Justification parameter lets you specify how the text is laid out within the rectangle,
both horizontally and vertically.
The minimumHorizontalScale parameter specifies how much the text can be squashed horizontally
to try to squeeze it into the space. If you don't want any horizontal scaling to occur, you
can set this value to 1.0f. Pass 0 if you want it to use the default value.
@see Graphics::drawFittedText
*/
void addFittedText (const Font& font,
const String& text,
float x, float y, float width, float height,
Justification layout,
int maximumLinesToUse,
float minimumHorizontalScale = 0.0f);
/** Appends another glyph arrangement to this one. */
void addGlyphArrangement (const GlyphArrangement&);
/** Appends a custom glyph to the arrangement. */
void addGlyph (const PositionedGlyph&);
//==============================================================================
/** Draws this glyph arrangement to a graphics context.
This uses cached bitmaps so is much faster than the draw (Graphics&, AffineTransform)
method, which renders the glyphs as filled vectors.
*/
void draw (const Graphics&) const;
/** Draws this glyph arrangement to a graphics context.
This renders the paths as filled vectors, so is far slower than the draw (Graphics&)
method for non-transformed arrangements.
*/
void draw (const Graphics&, AffineTransform) const;
/** Converts the set of glyphs into a path.
@param path the glyphs' outlines will be appended to this path
*/
void createPath (Path& path) const;
/** Looks for a glyph that contains the given coordinate.
@returns the index of the glyph, or -1 if none were found.
*/
int findGlyphIndexAt (float x, float y) const;
//==============================================================================
/** Finds the smallest rectangle that will enclose a subset of the glyphs.
@param startIndex the first glyph to test
@param numGlyphs the number of glyphs to include; if this is < 0, all glyphs after
startIndex will be included
@param includeWhitespace if true, the extent of any whitespace characters will also
be taken into account
*/
Rectangle<float> getBoundingBox (int startIndex, int numGlyphs, bool includeWhitespace) const;
/** Shifts a set of glyphs by a given amount.
@param startIndex the first glyph to transform
@param numGlyphs the number of glyphs to move; if this is < 0, all glyphs after
startIndex will be used
@param deltaX the amount to add to their x-positions
@param deltaY the amount to add to their y-positions
*/
void moveRangeOfGlyphs (int startIndex, int numGlyphs,
float deltaX, float deltaY);
/** Removes a set of glyphs from the arrangement.
@param startIndex the first glyph to remove
@param numGlyphs the number of glyphs to remove; if this is < 0, all glyphs after
startIndex will be deleted
*/
void removeRangeOfGlyphs (int startIndex, int numGlyphs);
/** Expands or compresses a set of glyphs horizontally.
@param startIndex the first glyph to transform
@param numGlyphs the number of glyphs to stretch; if this is < 0, all glyphs after
startIndex will be used
@param horizontalScaleFactor how much to scale their horizontal width by
*/
void stretchRangeOfGlyphs (int startIndex, int numGlyphs,
float horizontalScaleFactor);
/** Justifies a set of glyphs within a given space.
This moves the glyphs as a block so that the whole thing is located within the
given rectangle with the specified layout.
If the Justification::horizontallyJustified flag is specified, each line will
be stretched out to fill the specified width.
*/
void justifyGlyphs (int startIndex, int numGlyphs,
float x, float y, float width, float height,
Justification justification);
private:
//==============================================================================
Array<PositionedGlyph> glyphs;
int insertEllipsis (const Font&, float maxXPos, int startIndex, int endIndex);
int fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font&,
Justification, float minimumHorizontalScale);
void spreadOutLine (int start, int numGlyphs, float targetWidth);
void splitLines (const String&, Font, int start, float x, float y, float w, float h, int maxLines,
float lineWidth, Justification, float minimumHorizontalScale);
void addLinesWithLineBreaks (const String&, const Font&, float x, float y, float width, float height, Justification);
void drawGlyphUnderline (const Graphics&, const PositionedGlyph&, int, AffineTransform) const;
JUCE_LEAK_DETECTOR (GlyphArrangement)
};
} // namespace juce

File diff suppressed because it is too large Load Diff

View File

@ -1,270 +1,270 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A Pre-formatted piece of text, which may contain multiple fonts and colours.
A TextLayout is created from an AttributedString, and once created can be
quickly drawn into a Graphics context.
@see AttributedString
@tags{Graphics}
*/
class JUCE_API TextLayout final
{
private:
template <typename Iterator>
class DereferencingIterator
{
public:
using value_type = typename std::remove_reference<decltype(**std::declval<Iterator>())>::type;
using difference_type = typename std::iterator_traits<Iterator>::difference_type;
using pointer = value_type*;
using reference = value_type&;
using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;
explicit DereferencingIterator (Iterator in) : iterator (std::move (in)) {}
DereferencingIterator& operator+= (difference_type distance)
{
iterator += distance;
return *this;
}
friend DereferencingIterator operator+ (DereferencingIterator i, difference_type d) { return i += d; }
friend DereferencingIterator operator+ (difference_type d, DereferencingIterator i) { return i += d; }
DereferencingIterator& operator-= (difference_type distance)
{
iterator -= distance;
return *this;
}
friend DereferencingIterator operator- (DereferencingIterator i, difference_type d) { return i -= d; }
friend difference_type operator- (DereferencingIterator a, DereferencingIterator b) { return a.iterator - b.iterator; }
reference operator[] (difference_type d) const { return *iterator[d]; }
friend bool operator< (DereferencingIterator a, DereferencingIterator b) { return a.iterator < b.iterator; }
friend bool operator<= (DereferencingIterator a, DereferencingIterator b) { return a.iterator <= b.iterator; }
friend bool operator> (DereferencingIterator a, DereferencingIterator b) { return a.iterator > b.iterator; }
friend bool operator>= (DereferencingIterator a, DereferencingIterator b) { return a.iterator >= b.iterator; }
friend bool operator== (DereferencingIterator a, DereferencingIterator b) { return a.iterator == b.iterator; }
friend bool operator!= (DereferencingIterator a, DereferencingIterator b) { return a.iterator != b.iterator; }
DereferencingIterator& operator++() { ++iterator; return *this; }
DereferencingIterator& operator--() { --iterator; return *this; }
DereferencingIterator operator++ (int) const { DereferencingIterator copy (*this); ++(*this); return copy; }
DereferencingIterator operator-- (int) const { DereferencingIterator copy (*this); --(*this); return copy; }
reference operator* () const { return **iterator; }
pointer operator->() const { return *iterator; }
private:
Iterator iterator;
};
public:
/** Creates an empty layout.
Having created a TextLayout, you can populate it using createLayout() or
createLayoutWithBalancedLineLengths().
*/
TextLayout();
TextLayout (const TextLayout&);
TextLayout& operator= (const TextLayout&);
TextLayout (TextLayout&&) noexcept;
TextLayout& operator= (TextLayout&&) noexcept;
/** Destructor. */
~TextLayout();
//==============================================================================
/** Creates a layout from the given attributed string.
This will replace any data that is currently stored in the layout.
*/
void createLayout (const AttributedString&, float maxWidth);
/** Creates a layout from the given attributed string, given some size constraints.
This will replace any data that is currently stored in the layout.
*/
void createLayout (const AttributedString&, float maxWidth, float maxHeight);
/** Creates a layout, attempting to choose a width which results in lines
of a similar length.
This will be slower than the normal createLayout method, but produces a
tidier result.
*/
void createLayoutWithBalancedLineLengths (const AttributedString&, float maxWidth);
/** Creates a layout, attempting to choose a width which results in lines
of a similar length.
This will be slower than the normal createLayout method, but produces a
tidier result.
*/
void createLayoutWithBalancedLineLengths (const AttributedString&, float maxWidth, float maxHeight);
/** Draws the layout within the specified area.
The position of the text within the rectangle is controlled by the justification
flags set in the original AttributedString that was used to create this layout.
*/
void draw (Graphics&, Rectangle<float> area) const;
//==============================================================================
/** A positioned glyph. */
class JUCE_API Glyph
{
public:
Glyph (int glyphCode, Point<float> anchor, float width) noexcept;
/** The code number of this glyph. */
int glyphCode;
/** The glyph's anchor point - this is relative to the line's origin.
@see TextLayout::Line::lineOrigin
*/
Point<float> anchor;
float width;
private:
JUCE_LEAK_DETECTOR (Glyph)
};
//==============================================================================
/** A sequence of glyphs with a common font and colour. */
class JUCE_API Run
{
public:
Run() = default;
Run (Range<int> stringRange, int numGlyphsToPreallocate);
/** 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 { 0xff000000 }; /**< The run's colour. */
Array<Glyph> glyphs; /**< The glyphs in this run. */
Range<int> stringRange; /**< The character range that this run represents in the
original string that was used to create it. */
private:
JUCE_LEAK_DETECTOR (Run)
};
//==============================================================================
/** A line containing a sequence of glyph-runs. */
class JUCE_API Line
{
public:
Line() = default;
Line (Range<int> stringRange, Point<float> lineOrigin,
float ascent, float descent, float leading, int numRunsToPreallocate);
Line (const Line&);
Line& operator= (const Line&);
Line (Line&&) noexcept = default;
Line& operator= (Line&&) noexcept = default;
~Line() noexcept = default;
/** Returns the X position range which contains all the glyphs in this line. */
Range<float> getLineBoundsX() const noexcept;
/** Returns the Y position range which contains all the glyphs in this line. */
Range<float> getLineBoundsY() const noexcept;
/** Returns the smallest rectangle which contains all the glyphs in this line. */
Rectangle<float> getLineBounds() const noexcept;
void swap (Line& other) noexcept;
OwnedArray<Run> runs; /**< The glyph-runs in this line. */
Range<int> stringRange; /**< The character range that this line represents in the
original string that was used to create it. */
Point<float> lineOrigin; /**< The line's baseline origin. */
float ascent = 0.0f, descent = 0.0f, leading = 0.0f;
private:
JUCE_LEAK_DETECTOR (Line)
};
//==============================================================================
/** Returns the maximum width of the content. */
float getWidth() const noexcept { return width; }
/** Returns the maximum height of the content. */
float getHeight() const noexcept { return height; }
/** Returns the number of lines in the layout. */
int getNumLines() const noexcept { return lines.size(); }
/** Returns one of the lines. */
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. */
void addLine (std::unique_ptr<Line>);
/** Pre-allocates space for the specified number of lines. */
void ensureStorageAllocated (int numLinesNeeded);
using iterator = DereferencingIterator< Line* const*>;
using const_iterator = DereferencingIterator<const Line* const*>;
/** Returns an iterator over the lines of content */
iterator begin() { return iterator (lines.begin()); }
const_iterator begin() const { return const_iterator (lines.begin()); }
const_iterator cbegin() const { return const_iterator (lines.begin()); }
/** Returns an iterator over the lines of content */
iterator end() { return iterator (lines.end()); }
const_iterator end() const { return const_iterator (lines.end()); }
const_iterator cend() const { return const_iterator (lines.end()); }
/** If you modify the TextLayout after creating it, call this to compute
the new dimensions of the content.
*/
void recalculateSize();
private:
OwnedArray<Line> lines;
float width, height;
Justification justification;
void createStandardLayout (const AttributedString&);
bool createNativeLayout (const AttributedString&);
JUCE_LEAK_DETECTOR (TextLayout)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A Pre-formatted piece of text, which may contain multiple fonts and colours.
A TextLayout is created from an AttributedString, and once created can be
quickly drawn into a Graphics context.
@see AttributedString
@tags{Graphics}
*/
class JUCE_API TextLayout final
{
private:
template <typename Iterator>
class DereferencingIterator
{
public:
using value_type = typename std::remove_reference<decltype(**std::declval<Iterator>())>::type;
using difference_type = typename std::iterator_traits<Iterator>::difference_type;
using pointer = value_type*;
using reference = value_type&;
using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;
explicit DereferencingIterator (Iterator in) : iterator (std::move (in)) {}
DereferencingIterator& operator+= (difference_type distance)
{
iterator += distance;
return *this;
}
friend DereferencingIterator operator+ (DereferencingIterator i, difference_type d) { return i += d; }
friend DereferencingIterator operator+ (difference_type d, DereferencingIterator i) { return i += d; }
DereferencingIterator& operator-= (difference_type distance)
{
iterator -= distance;
return *this;
}
friend DereferencingIterator operator- (DereferencingIterator i, difference_type d) { return i -= d; }
friend difference_type operator- (DereferencingIterator a, DereferencingIterator b) { return a.iterator - b.iterator; }
reference operator[] (difference_type d) const { return *iterator[d]; }
friend bool operator< (DereferencingIterator a, DereferencingIterator b) { return a.iterator < b.iterator; }
friend bool operator<= (DereferencingIterator a, DereferencingIterator b) { return a.iterator <= b.iterator; }
friend bool operator> (DereferencingIterator a, DereferencingIterator b) { return a.iterator > b.iterator; }
friend bool operator>= (DereferencingIterator a, DereferencingIterator b) { return a.iterator >= b.iterator; }
friend bool operator== (DereferencingIterator a, DereferencingIterator b) { return a.iterator == b.iterator; }
friend bool operator!= (DereferencingIterator a, DereferencingIterator b) { return a.iterator != b.iterator; }
DereferencingIterator& operator++() { ++iterator; return *this; }
DereferencingIterator& operator--() { --iterator; return *this; }
DereferencingIterator operator++ (int) const { DereferencingIterator copy (*this); ++(*this); return copy; }
DereferencingIterator operator-- (int) const { DereferencingIterator copy (*this); --(*this); return copy; }
reference operator* () const { return **iterator; }
pointer operator->() const { return *iterator; }
private:
Iterator iterator;
};
public:
/** Creates an empty layout.
Having created a TextLayout, you can populate it using createLayout() or
createLayoutWithBalancedLineLengths().
*/
TextLayout();
TextLayout (const TextLayout&);
TextLayout& operator= (const TextLayout&);
TextLayout (TextLayout&&) noexcept;
TextLayout& operator= (TextLayout&&) noexcept;
/** Destructor. */
~TextLayout();
//==============================================================================
/** Creates a layout from the given attributed string.
This will replace any data that is currently stored in the layout.
*/
void createLayout (const AttributedString&, float maxWidth);
/** Creates a layout from the given attributed string, given some size constraints.
This will replace any data that is currently stored in the layout.
*/
void createLayout (const AttributedString&, float maxWidth, float maxHeight);
/** Creates a layout, attempting to choose a width which results in lines
of a similar length.
This will be slower than the normal createLayout method, but produces a
tidier result.
*/
void createLayoutWithBalancedLineLengths (const AttributedString&, float maxWidth);
/** Creates a layout, attempting to choose a width which results in lines
of a similar length.
This will be slower than the normal createLayout method, but produces a
tidier result.
*/
void createLayoutWithBalancedLineLengths (const AttributedString&, float maxWidth, float maxHeight);
/** Draws the layout within the specified area.
The position of the text within the rectangle is controlled by the justification
flags set in the original AttributedString that was used to create this layout.
*/
void draw (Graphics&, Rectangle<float> area) const;
//==============================================================================
/** A positioned glyph. */
class JUCE_API Glyph
{
public:
Glyph (int glyphCode, Point<float> anchor, float width) noexcept;
/** The code number of this glyph. */
int glyphCode;
/** The glyph's anchor point - this is relative to the line's origin.
@see TextLayout::Line::lineOrigin
*/
Point<float> anchor;
float width;
private:
JUCE_LEAK_DETECTOR (Glyph)
};
//==============================================================================
/** A sequence of glyphs with a common font and colour. */
class JUCE_API Run
{
public:
Run() = default;
Run (Range<int> stringRange, int numGlyphsToPreallocate);
/** 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 { 0xff000000 }; /**< The run's colour. */
Array<Glyph> glyphs; /**< The glyphs in this run. */
Range<int> stringRange; /**< The character range that this run represents in the
original string that was used to create it. */
private:
JUCE_LEAK_DETECTOR (Run)
};
//==============================================================================
/** A line containing a sequence of glyph-runs. */
class JUCE_API Line
{
public:
Line() = default;
Line (Range<int> stringRange, Point<float> lineOrigin,
float ascent, float descent, float leading, int numRunsToPreallocate);
Line (const Line&);
Line& operator= (const Line&);
Line (Line&&) noexcept = default;
Line& operator= (Line&&) noexcept = default;
~Line() noexcept = default;
/** Returns the X position range which contains all the glyphs in this line. */
Range<float> getLineBoundsX() const noexcept;
/** Returns the Y position range which contains all the glyphs in this line. */
Range<float> getLineBoundsY() const noexcept;
/** Returns the smallest rectangle which contains all the glyphs in this line. */
Rectangle<float> getLineBounds() const noexcept;
void swap (Line& other) noexcept;
OwnedArray<Run> runs; /**< The glyph-runs in this line. */
Range<int> stringRange; /**< The character range that this line represents in the
original string that was used to create it. */
Point<float> lineOrigin; /**< The line's baseline origin. */
float ascent = 0.0f, descent = 0.0f, leading = 0.0f;
private:
JUCE_LEAK_DETECTOR (Line)
};
//==============================================================================
/** Returns the maximum width of the content. */
float getWidth() const noexcept { return width; }
/** Returns the maximum height of the content. */
float getHeight() const noexcept { return height; }
/** Returns the number of lines in the layout. */
int getNumLines() const noexcept { return lines.size(); }
/** Returns one of the lines. */
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. */
void addLine (std::unique_ptr<Line>);
/** Pre-allocates space for the specified number of lines. */
void ensureStorageAllocated (int numLinesNeeded);
using iterator = DereferencingIterator< Line* const*>;
using const_iterator = DereferencingIterator<const Line* const*>;
/** Returns an iterator over the lines of content */
iterator begin() { return iterator (lines.begin()); }
const_iterator begin() const { return const_iterator (lines.begin()); }
const_iterator cbegin() const { return const_iterator (lines.begin()); }
/** Returns an iterator over the lines of content */
iterator end() { return iterator (lines.end()); }
const_iterator end() const { return const_iterator (lines.end()); }
const_iterator cend() const { return const_iterator (lines.end()); }
/** If you modify the TextLayout after creating it, call this to compute
the new dimensions of the content.
*/
void recalculateSize();
private:
OwnedArray<Line> lines;
float width, height;
Justification justification;
void createStandardLayout (const AttributedString&);
bool createNativeLayout (const AttributedString&);
JUCE_LEAK_DETECTOR (TextLayout)
};
} // namespace juce

View File

@ -1,263 +1,263 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
struct FontStyleHelpers
{
static const char* getStyleName (const bool bold,
const bool italic) noexcept
{
if (bold && italic) return "Bold Italic";
if (bold) return "Bold";
if (italic) return "Italic";
return "Regular";
}
static const char* getStyleName (const int styleFlags) noexcept
{
return getStyleName ((styleFlags & Font::bold) != 0,
(styleFlags & Font::italic) != 0);
}
static bool isBold (const String& style) noexcept
{
return style.containsWholeWordIgnoreCase ("Bold");
}
static bool isItalic (const String& style) noexcept
{
return style.containsWholeWordIgnoreCase ("Italic")
|| style.containsWholeWordIgnoreCase ("Oblique");
}
static bool isPlaceholderFamilyName (const String& family)
{
return family == Font::getDefaultSansSerifFontName()
|| family == Font::getDefaultSerifFontName()
|| family == Font::getDefaultMonospacedFontName();
}
struct ConcreteFamilyNames
{
ConcreteFamilyNames()
: sans (findName (Font::getDefaultSansSerifFontName())),
serif (findName (Font::getDefaultSerifFontName())),
mono (findName (Font::getDefaultMonospacedFontName()))
{
}
String lookUp (const String& placeholder)
{
if (placeholder == Font::getDefaultSansSerifFontName()) return sans;
if (placeholder == Font::getDefaultSerifFontName()) return serif;
if (placeholder == Font::getDefaultMonospacedFontName()) return mono;
return findName (placeholder);
}
private:
static String findName (const String& placeholder)
{
const Font f (placeholder, Font::getDefaultStyle(), 15.0f);
return Font::getDefaultTypefaceForFont (f)->getName();
}
String sans, serif, mono;
};
static String getConcreteFamilyNameFromPlaceholder (const String& placeholder)
{
static ConcreteFamilyNames names;
return names.lookUp (placeholder);
}
static String getConcreteFamilyName (const Font& font)
{
const String& family = font.getTypefaceName();
return isPlaceholderFamilyName (family) ? getConcreteFamilyNameFromPlaceholder (family)
: family;
}
};
//==============================================================================
Typeface::Typeface (const String& faceName, const String& styleName) noexcept
: name (faceName), style (styleName)
{
}
Typeface::~Typeface() = default;
Typeface::Ptr Typeface::getFallbackTypeface()
{
const Font fallbackFont (Font::getFallbackFontName(), Font::getFallbackFontStyle(), 10.0f);
return fallbackFont.getTypefacePtr();
}
EdgeTable* Typeface::getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight)
{
Path path;
if (getOutlineForGlyph (glyphNumber, path) && ! path.isEmpty())
{
applyVerticalHintingTransform (fontHeight, path);
return new EdgeTable (path.getBoundsTransformed (transform).getSmallestIntegerContainer().expanded (1, 0),
path, transform);
}
return nullptr;
}
//==============================================================================
struct Typeface::HintingParams
{
HintingParams (Typeface& t)
{
Font font (t);
font = font.withHeight ((float) standardHeight);
top = getAverageY (font, "BDEFPRTZOQ", true);
middle = getAverageY (font, "acegmnopqrsuvwxy", true);
bottom = getAverageY (font, "BDELZOC", false);
}
void applyVerticalHintingTransform (float fontSize, Path& path)
{
if (cachedSize != fontSize)
{
cachedSize = fontSize;
cachedScale = Scaling (top, middle, bottom, fontSize);
}
if (bottom < top + 3.0f / fontSize)
return;
Path result;
for (Path::Iterator i (path); i.next();)
{
switch (i.elementType)
{
case Path::Iterator::startNewSubPath: result.startNewSubPath (i.x1, cachedScale.apply (i.y1)); break;
case Path::Iterator::lineTo: result.lineTo (i.x1, cachedScale.apply (i.y1)); break;
case Path::Iterator::quadraticTo: result.quadraticTo (i.x1, cachedScale.apply (i.y1),
i.x2, cachedScale.apply (i.y2)); break;
case Path::Iterator::cubicTo: result.cubicTo (i.x1, cachedScale.apply (i.y1),
i.x2, cachedScale.apply (i.y2),
i.x3, cachedScale.apply (i.y3)); break;
case Path::Iterator::closePath: result.closeSubPath(); break;
default: jassertfalse; break;
}
}
result.swapWithPath (path);
}
private:
struct Scaling
{
Scaling() noexcept : middle(), upperScale(), upperOffset(), lowerScale(), lowerOffset() {}
Scaling (float t, float m, float b, float fontSize) noexcept : middle (m)
{
const float newT = std::floor (fontSize * t + 0.5f) / fontSize;
const float newB = std::floor (fontSize * b + 0.5f) / fontSize;
const float newM = std::floor (fontSize * m + 0.3f) / fontSize; // this is slightly biased so that lower-case letters
// are more likely to become taller than shorter.
upperScale = jlimit (0.9f, 1.1f, (newM - newT) / (m - t));
lowerScale = jlimit (0.9f, 1.1f, (newB - newM) / (b - m));
upperOffset = newM - m * upperScale;
lowerOffset = newB - b * lowerScale;
}
float apply (float y) const noexcept
{
return y < middle ? (y * upperScale + upperOffset)
: (y * lowerScale + lowerOffset);
}
float middle, upperScale, upperOffset, lowerScale, lowerOffset;
};
float cachedSize = 0;
Scaling cachedScale;
static float getAverageY (const Font& font, const char* chars, bool getTop)
{
GlyphArrangement ga;
ga.addLineOfText (font, chars, 0, 0);
Array<float> yValues;
for (auto& glyph : ga)
{
Path p;
glyph.createPath (p);
auto bounds = p.getBounds();
if (! p.isEmpty())
yValues.add (getTop ? bounds.getY() : bounds.getBottom());
}
std::sort (yValues.begin(), yValues.end());
auto median = yValues[yValues.size() / 2];
float total = 0;
int num = 0;
for (auto y : yValues)
{
if (std::abs (median - y) < 0.05f * (float) standardHeight)
{
total += y;
++num;
}
}
return num < 4 ? 0.0f : total / ((float) num * (float) standardHeight);
}
enum { standardHeight = 100 };
float top = 0, middle = 0, bottom = 0;
};
void Typeface::applyVerticalHintingTransform (float fontSize, Path& path)
{
if (fontSize > 3.0f && fontSize < 25.0f)
{
ScopedLock sl (hintingLock);
if (hintingParams == nullptr)
hintingParams.reset (new HintingParams (*this));
return hintingParams->applyVerticalHintingTransform (fontSize, path);
}
}
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
struct FontStyleHelpers
{
static const char* getStyleName (const bool bold,
const bool italic) noexcept
{
if (bold && italic) return "Bold Italic";
if (bold) return "Bold";
if (italic) return "Italic";
return "Regular";
}
static const char* getStyleName (const int styleFlags) noexcept
{
return getStyleName ((styleFlags & Font::bold) != 0,
(styleFlags & Font::italic) != 0);
}
static bool isBold (const String& style) noexcept
{
return style.containsWholeWordIgnoreCase ("Bold");
}
static bool isItalic (const String& style) noexcept
{
return style.containsWholeWordIgnoreCase ("Italic")
|| style.containsWholeWordIgnoreCase ("Oblique");
}
static bool isPlaceholderFamilyName (const String& family)
{
return family == Font::getDefaultSansSerifFontName()
|| family == Font::getDefaultSerifFontName()
|| family == Font::getDefaultMonospacedFontName();
}
struct ConcreteFamilyNames
{
ConcreteFamilyNames()
: sans (findName (Font::getDefaultSansSerifFontName())),
serif (findName (Font::getDefaultSerifFontName())),
mono (findName (Font::getDefaultMonospacedFontName()))
{
}
String lookUp (const String& placeholder)
{
if (placeholder == Font::getDefaultSansSerifFontName()) return sans;
if (placeholder == Font::getDefaultSerifFontName()) return serif;
if (placeholder == Font::getDefaultMonospacedFontName()) return mono;
return findName (placeholder);
}
private:
static String findName (const String& placeholder)
{
const Font f (placeholder, Font::getDefaultStyle(), 15.0f);
return Font::getDefaultTypefaceForFont (f)->getName();
}
String sans, serif, mono;
};
static String getConcreteFamilyNameFromPlaceholder (const String& placeholder)
{
static ConcreteFamilyNames names;
return names.lookUp (placeholder);
}
static String getConcreteFamilyName (const Font& font)
{
const String& family = font.getTypefaceName();
return isPlaceholderFamilyName (family) ? getConcreteFamilyNameFromPlaceholder (family)
: family;
}
};
//==============================================================================
Typeface::Typeface (const String& faceName, const String& styleName) noexcept
: name (faceName), style (styleName)
{
}
Typeface::~Typeface() = default;
Typeface::Ptr Typeface::getFallbackTypeface()
{
const Font fallbackFont (Font::getFallbackFontName(), Font::getFallbackFontStyle(), 10.0f);
return fallbackFont.getTypefacePtr();
}
EdgeTable* Typeface::getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight)
{
Path path;
if (getOutlineForGlyph (glyphNumber, path) && ! path.isEmpty())
{
applyVerticalHintingTransform (fontHeight, path);
return new EdgeTable (path.getBoundsTransformed (transform).getSmallestIntegerContainer().expanded (1, 0),
path, transform);
}
return nullptr;
}
//==============================================================================
struct Typeface::HintingParams
{
HintingParams (Typeface& t)
{
Font font (t);
font = font.withHeight ((float) standardHeight);
top = getAverageY (font, "BDEFPRTZOQ", true);
middle = getAverageY (font, "acegmnopqrsuvwxy", true);
bottom = getAverageY (font, "BDELZOC", false);
}
void applyVerticalHintingTransform (float fontSize, Path& path)
{
if (cachedSize != fontSize)
{
cachedSize = fontSize;
cachedScale = Scaling (top, middle, bottom, fontSize);
}
if (bottom < top + 3.0f / fontSize)
return;
Path result;
for (Path::Iterator i (path); i.next();)
{
switch (i.elementType)
{
case Path::Iterator::startNewSubPath: result.startNewSubPath (i.x1, cachedScale.apply (i.y1)); break;
case Path::Iterator::lineTo: result.lineTo (i.x1, cachedScale.apply (i.y1)); break;
case Path::Iterator::quadraticTo: result.quadraticTo (i.x1, cachedScale.apply (i.y1),
i.x2, cachedScale.apply (i.y2)); break;
case Path::Iterator::cubicTo: result.cubicTo (i.x1, cachedScale.apply (i.y1),
i.x2, cachedScale.apply (i.y2),
i.x3, cachedScale.apply (i.y3)); break;
case Path::Iterator::closePath: result.closeSubPath(); break;
default: jassertfalse; break;
}
}
result.swapWithPath (path);
}
private:
struct Scaling
{
Scaling() noexcept : middle(), upperScale(), upperOffset(), lowerScale(), lowerOffset() {}
Scaling (float t, float m, float b, float fontSize) noexcept : middle (m)
{
const float newT = std::floor (fontSize * t + 0.5f) / fontSize;
const float newB = std::floor (fontSize * b + 0.5f) / fontSize;
const float newM = std::floor (fontSize * m + 0.3f) / fontSize; // this is slightly biased so that lower-case letters
// are more likely to become taller than shorter.
upperScale = jlimit (0.9f, 1.1f, (newM - newT) / (m - t));
lowerScale = jlimit (0.9f, 1.1f, (newB - newM) / (b - m));
upperOffset = newM - m * upperScale;
lowerOffset = newB - b * lowerScale;
}
float apply (float y) const noexcept
{
return y < middle ? (y * upperScale + upperOffset)
: (y * lowerScale + lowerOffset);
}
float middle, upperScale, upperOffset, lowerScale, lowerOffset;
};
float cachedSize = 0;
Scaling cachedScale;
static float getAverageY (const Font& font, const char* chars, bool getTop)
{
GlyphArrangement ga;
ga.addLineOfText (font, chars, 0, 0);
Array<float> yValues;
for (auto& glyph : ga)
{
Path p;
glyph.createPath (p);
auto bounds = p.getBounds();
if (! p.isEmpty())
yValues.add (getTop ? bounds.getY() : bounds.getBottom());
}
std::sort (yValues.begin(), yValues.end());
auto median = yValues[yValues.size() / 2];
float total = 0;
int num = 0;
for (auto y : yValues)
{
if (std::abs (median - y) < 0.05f * (float) standardHeight)
{
total += y;
++num;
}
}
return num < 4 ? 0.0f : total / ((float) num * (float) standardHeight);
}
enum { standardHeight = 100 };
float top = 0, middle = 0, bottom = 0;
};
void Typeface::applyVerticalHintingTransform (float fontSize, Path& path)
{
if (fontSize > 3.0f && fontSize < 25.0f)
{
ScopedLock sl (hintingLock);
if (hintingParams == nullptr)
hintingParams.reset (new HintingParams (*this));
return hintingParams->applyVerticalHintingTransform (fontSize, path);
}
}
} // namespace juce

View File

@ -1,161 +1,161 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A typeface represents a size-independent font.
This base class is abstract, but calling createSystemTypefaceFor() will return
a platform-specific subclass that can be used.
The CustomTypeface subclass allow you to build your own typeface, and to
load and save it in the JUCE typeface format.
Normally you should never need to deal directly with Typeface objects - the Font
class does everything you typically need for rendering text.
@see CustomTypeface, Font
@tags{Graphics}
*/
class JUCE_API Typeface : public ReferenceCountedObject
{
public:
//==============================================================================
/** A handy typedef for a pointer to a typeface. */
using Ptr = ReferenceCountedObjectPtr<Typeface>;
//==============================================================================
/** Returns the font family of the typeface.
@see Font::getTypefaceName
*/
const String& getName() const noexcept { return name; }
//==============================================================================
/** Returns the font style of the typeface.
@see Font::getTypefaceStyle
*/
const String& getStyle() const noexcept { return style; }
//==============================================================================
/** Creates a new system typeface. */
static Ptr createSystemTypefaceFor (const Font& font);
/** Attempts to create a font from some raw font file data (e.g. a TTF or OTF file image).
The system will take its own internal copy of the data, so you can free the block once
this method has returned.
*/
static Ptr createSystemTypefaceFor (const void* fontFileData, size_t fontFileDataSize);
//==============================================================================
/** Destructor. */
~Typeface() override;
/** Returns true if this typeface can be used to render the specified font.
When called, the font will already have been checked to make sure that its name and
style flags match the typeface.
*/
virtual bool isSuitableForFont (const Font&) const { return true; }
/** Returns the ascent of the font, as a proportion of its height.
The height is considered to always be normalised as 1.0, so this will be a
value less that 1.0, indicating the proportion of the font that lies above
its baseline.
*/
virtual float getAscent() const = 0;
/** Returns the descent of the font, as a proportion of its height.
The height is considered to always be normalised as 1.0, so this will be a
value less that 1.0, indicating the proportion of the font that lies below
its baseline.
*/
virtual float getDescent() const = 0;
/** Returns the value by which you should multiply a JUCE font-height value to
convert it to the equivalent point-size.
*/
virtual float getHeightToPointsFactor() const = 0;
/** Measures the width of a line of text.
The distance returned is based on the font having an normalised height of 1.0.
You should never need to call this directly! Use Font::getStringWidth() instead!
*/
virtual float getStringWidth (const String& text) = 0;
/** Converts a line of text into its glyph numbers and their positions.
The distances returned are based on the font having an normalised height of 1.0.
You should never need to call this directly! Use Font::getGlyphPositions() instead!
*/
virtual void getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) = 0;
/** Returns the outline for a glyph.
The path returned will be normalised to a font height of 1.0.
*/
virtual bool getOutlineForGlyph (int glyphNumber, Path& path) = 0;
/** Returns a new EdgeTable that contains the path for the given glyph, with the specified transform applied. */
virtual EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight);
/** Returns true if the typeface uses hinting. */
virtual bool isHinted() const { return false; }
//==============================================================================
/** Changes the number of fonts that are cached in memory. */
static void setTypefaceCacheSize (int numFontsToCache);
/** Clears any fonts that are currently cached in memory. */
static void clearTypefaceCache();
/** On some platforms, this allows a specific path to be scanned.
On macOS you can load .ttf and .otf files, otherwise this is only available when using FreeType.
*/
static void scanFolderForFonts (const File& folder);
/** Makes an attempt at performing a good overall distortion that will scale a font of
the given size to align vertically with the pixel grid. The path should be an unscaled
(i.e. normalised to height of 1.0) path for a glyph.
*/
void applyVerticalHintingTransform (float fontHeight, Path& path);
protected:
//==============================================================================
String name, style;
Typeface (const String& name, const String& style) noexcept;
static Ptr getFallbackTypeface();
private:
struct HintingParams;
std::unique_ptr<HintingParams> hintingParams;
CriticalSection hintingLock;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Typeface)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A typeface represents a size-independent font.
This base class is abstract, but calling createSystemTypefaceFor() will return
a platform-specific subclass that can be used.
The CustomTypeface subclass allow you to build your own typeface, and to
load and save it in the JUCE typeface format.
Normally you should never need to deal directly with Typeface objects - the Font
class does everything you typically need for rendering text.
@see CustomTypeface, Font
@tags{Graphics}
*/
class JUCE_API Typeface : public ReferenceCountedObject
{
public:
//==============================================================================
/** A handy typedef for a pointer to a typeface. */
using Ptr = ReferenceCountedObjectPtr<Typeface>;
//==============================================================================
/** Returns the font family of the typeface.
@see Font::getTypefaceName
*/
const String& getName() const noexcept { return name; }
//==============================================================================
/** Returns the font style of the typeface.
@see Font::getTypefaceStyle
*/
const String& getStyle() const noexcept { return style; }
//==============================================================================
/** Creates a new system typeface. */
static Ptr createSystemTypefaceFor (const Font& font);
/** Attempts to create a font from some raw font file data (e.g. a TTF or OTF file image).
The system will take its own internal copy of the data, so you can free the block once
this method has returned.
*/
static Ptr createSystemTypefaceFor (const void* fontFileData, size_t fontFileDataSize);
//==============================================================================
/** Destructor. */
~Typeface() override;
/** Returns true if this typeface can be used to render the specified font.
When called, the font will already have been checked to make sure that its name and
style flags match the typeface.
*/
virtual bool isSuitableForFont (const Font&) const { return true; }
/** Returns the ascent of the font, as a proportion of its height.
The height is considered to always be normalised as 1.0, so this will be a
value less that 1.0, indicating the proportion of the font that lies above
its baseline.
*/
virtual float getAscent() const = 0;
/** Returns the descent of the font, as a proportion of its height.
The height is considered to always be normalised as 1.0, so this will be a
value less that 1.0, indicating the proportion of the font that lies below
its baseline.
*/
virtual float getDescent() const = 0;
/** Returns the value by which you should multiply a JUCE font-height value to
convert it to the equivalent point-size.
*/
virtual float getHeightToPointsFactor() const = 0;
/** Measures the width of a line of text.
The distance returned is based on the font having an normalised height of 1.0.
You should never need to call this directly! Use Font::getStringWidth() instead!
*/
virtual float getStringWidth (const String& text) = 0;
/** Converts a line of text into its glyph numbers and their positions.
The distances returned are based on the font having an normalised height of 1.0.
You should never need to call this directly! Use Font::getGlyphPositions() instead!
*/
virtual void getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) = 0;
/** Returns the outline for a glyph.
The path returned will be normalised to a font height of 1.0.
*/
virtual bool getOutlineForGlyph (int glyphNumber, Path& path) = 0;
/** Returns a new EdgeTable that contains the path for the given glyph, with the specified transform applied. */
virtual EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight);
/** Returns true if the typeface uses hinting. */
virtual bool isHinted() const { return false; }
//==============================================================================
/** Changes the number of fonts that are cached in memory. */
static void setTypefaceCacheSize (int numFontsToCache);
/** Clears any fonts that are currently cached in memory. */
static void clearTypefaceCache();
/** On some platforms, this allows a specific path to be scanned.
On macOS you can load .ttf and .otf files, otherwise this is only available when using FreeType.
*/
static void scanFolderForFonts (const File& folder);
/** Makes an attempt at performing a good overall distortion that will scale a font of
the given size to align vertically with the pixel grid. The path should be an unscaled
(i.e. normalised to height of 1.0) path for a glyph.
*/
void applyVerticalHintingTransform (float fontHeight, Path& path);
protected:
//==============================================================================
String name, style;
Typeface (const String& name, const String& style) noexcept;
static Ptr getFallbackTypeface();
private:
struct HintingParams;
std::unique_ptr<HintingParams> hintingParams;
CriticalSection hintingLock;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Typeface)
};
} // namespace juce