migrating to the latest JUCE version
This commit is contained in:
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
1654
deps/juce/modules/juce_graphics/fonts/juce_Font.cpp
vendored
1654
deps/juce/modules/juce_graphics/fonts/juce_Font.cpp
vendored
File diff suppressed because it is too large
Load Diff
971
deps/juce/modules/juce_graphics/fonts/juce_Font.h
vendored
971
deps/juce/modules/juce_graphics/fonts/juce_Font.h
vendored
@ -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
@ -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
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user