mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Font: Add support for querying fallbacks
This commit is contained in:
parent
a6a336acb8
commit
a1b23c0248
2 changed files with 177 additions and 66 deletions
|
|
@ -50,8 +50,6 @@ namespace FontValues
|
|||
|
||||
const float defaultFontHeight = 14.0f;
|
||||
float minimumHorizontalScale = 0.7f;
|
||||
String fallbackFont;
|
||||
String fallbackFontStyle;
|
||||
}
|
||||
|
||||
class HbScale
|
||||
|
|
@ -455,12 +453,14 @@ public:
|
|||
instance referencing the shared state.
|
||||
*/
|
||||
|
||||
StringArray getFallbackFamilies() const { return fallbacks; }
|
||||
String getTypefaceName() const { return typefaceName; }
|
||||
String getTypefaceStyle() const { return typefaceStyle; }
|
||||
float getHeight() const { return height; }
|
||||
float getHorizontalScale() const { return horizontalScale; }
|
||||
float getKerning() const { return kerning; }
|
||||
bool getUnderline() const { return underline; }
|
||||
bool getFallbackEnabled() const { return fallback; }
|
||||
|
||||
/* This shared state may be shared between two or more Font instances that are being
|
||||
read/modified from multiple threads.
|
||||
|
|
@ -469,10 +469,16 @@ public:
|
|||
during the modification.
|
||||
*/
|
||||
|
||||
void setTypeface (Typeface::Ptr x)
|
||||
void setTypeface (Typeface::Ptr newTypeface)
|
||||
{
|
||||
jassert (getReferenceCount() == 1);
|
||||
typeface = std::move (x);
|
||||
typeface = newTypeface;
|
||||
|
||||
if (newTypeface != nullptr)
|
||||
{
|
||||
typefaceName = typeface->getName();
|
||||
typefaceStyle = typeface->getStyle();
|
||||
}
|
||||
}
|
||||
|
||||
void setTypefaceName (String x)
|
||||
|
|
@ -517,6 +523,18 @@ public:
|
|||
underline = x;
|
||||
}
|
||||
|
||||
void setFallbackFamilies (const StringArray& x)
|
||||
{
|
||||
jassert (getReferenceCount() == 1);
|
||||
fallbacks = x;
|
||||
}
|
||||
|
||||
void setFallback (bool x)
|
||||
{
|
||||
jassert (getReferenceCount() == 1);
|
||||
fallback = x;
|
||||
}
|
||||
|
||||
private:
|
||||
static float legacyHeightToPoints (Typeface::Ptr p, float h)
|
||||
{
|
||||
|
|
@ -524,9 +542,11 @@ private:
|
|||
}
|
||||
|
||||
Typeface::Ptr typeface;
|
||||
StringArray fallbacks;
|
||||
String typefaceName, typefaceStyle;
|
||||
float height = 0.0f, horizontalScale = 1.0f, kerning = 0.0f, ascent = 0.0f;
|
||||
bool underline = false;
|
||||
bool fallback = true;
|
||||
|
||||
CriticalSection mutex;
|
||||
};
|
||||
|
|
@ -659,45 +679,39 @@ StringArray Font::getAvailableStyles() const
|
|||
return findAllTypefaceStyles (getTypefacePtr()->getName());
|
||||
}
|
||||
|
||||
void Font::setPreferredFallbackFamilies (const StringArray& fallbacks)
|
||||
{
|
||||
if (getPreferredFallbackFamilies() != fallbacks)
|
||||
{
|
||||
dupeInternalIfShared();
|
||||
font->setFallbackFamilies (fallbacks);
|
||||
}
|
||||
}
|
||||
|
||||
StringArray Font::getPreferredFallbackFamilies() const
|
||||
{
|
||||
return font->getFallbackFamilies();
|
||||
}
|
||||
|
||||
void Font::setFallbackEnabled (bool enabled)
|
||||
{
|
||||
if (getFallbackEnabled() != enabled)
|
||||
{
|
||||
dupeInternalIfShared();
|
||||
font->setFallback (enabled);
|
||||
}
|
||||
}
|
||||
|
||||
bool Font::getFallbackEnabled() const
|
||||
{
|
||||
return font->getFallbackEnabled();
|
||||
}
|
||||
|
||||
Typeface::Ptr Font::getTypefacePtr() const
|
||||
{
|
||||
return font->getTypefacePtr (*this);
|
||||
}
|
||||
|
||||
Typeface* Font::getTypeface() const
|
||||
{
|
||||
return getTypefacePtr().get();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const String& Font::getFallbackFontName()
|
||||
{
|
||||
return FontValues::fallbackFont;
|
||||
}
|
||||
|
||||
void Font::setFallbackFontName (const String& name)
|
||||
{
|
||||
FontValues::fallbackFont = name;
|
||||
|
||||
#if JUCE_MAC || JUCE_IOS
|
||||
jassertfalse; // Note that use of a fallback font isn't currently implemented in OSX..
|
||||
#endif
|
||||
}
|
||||
|
||||
const String& Font::getFallbackFontStyle()
|
||||
{
|
||||
return FontValues::fallbackFontStyle;
|
||||
}
|
||||
|
||||
void Font::setFallbackFontStyle (const String& style)
|
||||
{
|
||||
FontValues::fallbackFontStyle = style;
|
||||
|
||||
#if JUCE_MAC || JUCE_IOS
|
||||
jassertfalse; // Note that use of a fallback font isn't currently implemented in OSX..
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Font Font::withHeight (const float newHeight) const
|
||||
{
|
||||
|
|
@ -944,6 +958,71 @@ void Font::findFonts (Array<Font>& destArray)
|
|||
}
|
||||
}
|
||||
|
||||
static bool characterNotRendered (uint32_t c)
|
||||
{
|
||||
constexpr uint32_t points[]
|
||||
{
|
||||
// Control points
|
||||
0x0000, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x001A, 0x001B, 0x0085,
|
||||
|
||||
// BIDI control points
|
||||
0x061C, 0x200E, 0x200F, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E, 0x2066, 0x2067, 0x2068, 0x2069
|
||||
};
|
||||
|
||||
return std::find (std::begin (points), std::end (points), c) != std::end (points);
|
||||
}
|
||||
|
||||
static bool isFontSuitableForCodepoint (const Font& font, juce_wchar c)
|
||||
{
|
||||
const auto& hbFont = font.getNativeDetails().font;
|
||||
hb_codepoint_t glyph{};
|
||||
|
||||
return characterNotRendered ((uint32_t) c)
|
||||
|| hb_font_get_nominal_glyph (hbFont.get(), (hb_codepoint_t) c, &glyph);
|
||||
}
|
||||
|
||||
static bool isFontSuitableForText (const Font& font, const String& str)
|
||||
{
|
||||
for (const auto c : str)
|
||||
if (! isFontSuitableForCodepoint (font, c))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Font Font::findSuitableFontForText (const String& text, const String& language) const
|
||||
{
|
||||
if (! getFallbackEnabled() || isFontSuitableForText (*this, text))
|
||||
return *this;
|
||||
|
||||
for (const auto& fallback : getPreferredFallbackFamilies())
|
||||
{
|
||||
auto copy = *this;
|
||||
copy.setTypefaceName (fallback);
|
||||
|
||||
if (isFontSuitableForText (copy, text))
|
||||
return copy;
|
||||
}
|
||||
|
||||
if (auto current = getTypefacePtr())
|
||||
{
|
||||
if (auto suggested = current->createSystemFallback (text, language))
|
||||
{
|
||||
auto copy = *this;
|
||||
|
||||
if (copy.getTypefacePtr() != suggested)
|
||||
{
|
||||
copy.dupeInternalIfShared();
|
||||
copy.font->setTypeface (suggested);
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String Font::toString() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -168,6 +168,30 @@ public:
|
|||
/** Returns a list of the styles that this font can use. */
|
||||
StringArray getAvailableStyles() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Sets the names of the fallback font families that should be tried, in order,
|
||||
when searching for glyphs that are missing in the main typeface, specified via
|
||||
setTypefaceName() or Font(const Typeface::Ptr&).
|
||||
*/
|
||||
void setPreferredFallbackFamilies (const StringArray& fallbacks);
|
||||
|
||||
/** Returns the names of the fallback font families.
|
||||
*/
|
||||
StringArray getPreferredFallbackFamilies() const;
|
||||
|
||||
/** When drawing text using this Font, specifies whether glyphs that are missing in the main
|
||||
typeface should be replaced with glyphs from other fonts.
|
||||
To find missing glyphs, the typefaces for the preferred fallback families will be checked
|
||||
in order, followed by the system fallback fonts. The system fallback font is likely to be
|
||||
different on each platform.
|
||||
|
||||
Fallback is enabled by default.
|
||||
*/
|
||||
void setFallbackEnabled (bool enabled);
|
||||
|
||||
/** Returns true if fallback is enabled, or false otherwise. */
|
||||
bool getFallbackEnabled() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a typeface font family that represents the default sans-serif font.
|
||||
|
||||
|
|
@ -208,7 +232,13 @@ public:
|
|||
*/
|
||||
static const String& getDefaultStyle();
|
||||
|
||||
/** Returns the default system typeface for the given font. */
|
||||
/** Returns the default system typeface for the given font.
|
||||
|
||||
Note: This will only ever return the typeface for the font's "main" family.
|
||||
Before attempting to render glyphs from this typeface, it's a good idea to check
|
||||
that those glyphs are present in the typeface, and to select a different
|
||||
face if necessary.
|
||||
*/
|
||||
static Typeface::Ptr getDefaultTypefaceForFont (const Font& font);
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -346,7 +376,8 @@ public:
|
|||
*/
|
||||
static void setDefaultMinimumHorizontalScaleFactor (float newMinimumScaleFactor) noexcept;
|
||||
|
||||
/** Returns the font's kerning.
|
||||
/** Returns the font's tracking, i.e. spacing applied between characters in
|
||||
addition to the kerning defined by the font.
|
||||
|
||||
This is the extra space added between adjacent characters, as a proportion
|
||||
of the font's height.
|
||||
|
|
@ -356,7 +387,7 @@ public:
|
|||
*/
|
||||
float getExtraKerningFactor() const noexcept;
|
||||
|
||||
/** Returns a copy of this font with a new kerning factor.
|
||||
/** Returns a copy of this font with a new tracking 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,
|
||||
|
|
@ -364,7 +395,7 @@ public:
|
|||
*/
|
||||
[[nodiscard]] Font withExtraKerningFactor (float extraKerning) const;
|
||||
|
||||
/** Changes the font's kerning.
|
||||
/** Changes the font's tracking.
|
||||
@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,
|
||||
|
|
@ -404,17 +435,13 @@ public:
|
|||
void getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) const;
|
||||
|
||||
//==============================================================================
|
||||
#ifndef DOXYGEN
|
||||
/** Returns the typeface used by this font.
|
||||
/** Returns the main 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.
|
||||
Note: This will only ever return the typeface for the "main" family.
|
||||
Before attempting to render glyphs from this typeface, it's a good idea to check
|
||||
that those glyphs are present in the typeface, and to select a different
|
||||
face if necessary.
|
||||
*/
|
||||
[[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.
|
||||
|
|
@ -445,25 +472,30 @@ public:
|
|||
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();
|
||||
/** Attempts to locate a visually similar font that is capable of rendering the
|
||||
provided string.
|
||||
|
||||
/** 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);
|
||||
If fallback is disabled on this Font by setFallbackEnabled(), then this will
|
||||
always return a copy of the current Font.
|
||||
|
||||
/** 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();
|
||||
Otherwise, the current font, then each of the fallback fonts specified by
|
||||
setPreferredFallbackFamilies() will be checked, and the first Font that is
|
||||
capable of rendering the string will be returned. If none of these fonts is
|
||||
suitable, then the system font fallback mechanism will be used to locate a
|
||||
font from the currently installed fonts. If the system also cannot find any
|
||||
suitable font, then a copy of the original Font will be returned.
|
||||
|
||||
/** 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.
|
||||
Note that most fonts don't contain glyphs for all possible unicode codepoints,
|
||||
and instead may contain e.g. just the glyphs required for a specific script. So,
|
||||
if the provided text would be displayed using several scripts (multiple languages,
|
||||
emoji, etc.) then there's a good chance that no single font will be able to
|
||||
render the entire text. Shorter strings will generally produce better fallback
|
||||
results than longer strings, with the caveat that the system may take control
|
||||
characters such as combining marks and variation selectors into account when
|
||||
selecting suitable fonts, so querying fallbacks character-by-character is likely
|
||||
to produce poor results.
|
||||
*/
|
||||
static void setFallbackFontStyle (const String& style);
|
||||
Font findSuitableFontForText (const String& text, const String& language = {}) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a string to describe this font.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue