diff --git a/modules/juce_graphics/fonts/juce_Font.cpp b/modules/juce_graphics/fonts/juce_Font.cpp index 05dbe44baf..b08cd2cdf0 100644 --- a/modules/juce_graphics/fonts/juce_Font.cpp +++ b/modules/juce_graphics/fonts/juce_Font.cpp @@ -193,7 +193,7 @@ class Font::SharedFontInternal : public ReferenceCountedObject { public: explicit SharedFontInternal (FontOptions x) - : options (std::move (x)) + : options (x.getName().isEmpty() ? x.withName (getDefaultSansSerifFontName()) : std::move (x)) { } @@ -256,6 +256,7 @@ public: String getTypefaceName() const { return options.getName(); } String getTypefaceStyle() const { return options.getStyle(); } float getHeight() const { return options.getHeight(); } + float getPointHeight() const { return options.getPointHeight(); } float getHorizontalScale() const { return options.getHorizontalScale(); } float getKerning() const { return options.getKerningFactor(); } bool getUnderline() const { return options.getUnderline(); } @@ -300,6 +301,12 @@ public: options = options.withHeight (x); } + void setPointHeight (float x) + { + jassert (getReferenceCount() == 1); + options = options.withPointHeight (x); + } + void setHorizontalScale (float x) { jassert (getReferenceCount() == 1); @@ -360,7 +367,15 @@ Font::Font (FontOptions opt) template auto legacyArgs (Args&&... args) { - return FontOptions { std::forward (args)... }.withMetricsKind (TypefaceMetricsKind::legacy); + auto result = FontOptions { std::forward (args)... }.withMetricsKind (TypefaceMetricsKind::legacy); + + if (result.getName().isEmpty()) + result = result.withName (Font::getDefaultSansSerifFontName()); + + if (result.getPointHeight() > 0.0f) + result = result.withHeight (result.getPointHeight()); + + return result; } Font::Font() : font (new SharedFontInternal (legacyArgs())) {} @@ -541,7 +556,7 @@ float Font::getHeightToPointsFactor() const Font Font::withPointHeight (float heightInPoints) const { Font f (*this); - f.setHeight (heightInPoints / getHeightToPointsFactor()); + f.setPointHeight (heightInPoints); return f; } @@ -557,6 +572,18 @@ void Font::setHeight (float newHeight) } } +void Font::setPointHeight (float newHeight) +{ + newHeight = FontValues::limitFontHeight (newHeight); + + if (! approximatelyEqual (font->getPointHeight(), newHeight)) + { + dupeInternalIfShared(); + font->setPointHeight (newHeight); + font->resetTypeface(); + } +} + void Font::setHeightWithoutChangingWidth (float newHeight) { newHeight = FontValues::limitFontHeight (newHeight); @@ -713,10 +740,22 @@ float Font::getAscent() const return font->getMetrics (*this).ascent * getHeight(); } -float Font::getHeight() const noexcept { return font->getHeight(); } +float Font::getHeight() const noexcept +{ + jassert ((font->getHeight() > 0.0f) != (font->getPointHeight() > 0.0f)); + const auto height = font->getHeight(); + return height > 0.0f ? height : font->getPointHeight() / getHeightToPointsFactor(); +} + float Font::getDescent() const { return font->getHeight() - getAscent(); } -float Font::getHeightInPoints() const { return getHeight() * getHeightToPointsFactor(); } +float Font::getHeightInPoints() const +{ + jassert ((font->getHeight() > 0.0f) != (font->getPointHeight() > 0.0f)); + const auto pointHeight = font->getPointHeight(); + return pointHeight > 0.0f ? pointHeight : font->getHeight() * getHeightToPointsFactor(); +} + float Font::getAscentInPoints() const { return getAscent() * getHeightToPointsFactor(); } float Font::getDescentInPoints() const { return getDescent() * getHeightToPointsFactor(); } @@ -875,7 +914,7 @@ Font::Native Font::getNativeDetails() const Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font) { - const auto systemTypeface = [&]() -> Typeface::Ptr + const auto resolvedTypeface = [&]() -> Typeface::Ptr { if (font.getTypefaceName() != getSystemUIFontName()) return {}; @@ -893,8 +932,8 @@ Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font) return getDefaultTypefaceForFont (copy); }(); - if (systemTypeface != nullptr) - return systemTypeface; + if (resolvedTypeface != nullptr) + return resolvedTypeface; return Native::getDefaultPlatformTypefaceForFont (font); } diff --git a/modules/juce_graphics/fonts/juce_Font.h b/modules/juce_graphics/fonts/juce_Font.h index c116e5a619..aff8f99e67 100644 --- a/modules/juce_graphics/fonts/juce_Font.h +++ b/modules/juce_graphics/fonts/juce_Font.h @@ -265,10 +265,22 @@ public: [[nodiscard]] Font withPointHeight (float heightInPoints) const; /** Changes the font's height. - @see getHeight, withHeight, setHeightWithoutChangingWidth + + The font will be scaled so that the sum of the ascender and descender is equal to the + provided height in logical pixels. + + @see setPointHeight, getHeight, withHeight, setHeightWithoutChangingWidth */ void setHeight (float newHeight); + /** Changes the font's height. + + The argument specifies the size of the font's em-square in logical pixels. + + @see setHeight, getHeight, withHeight, setHeightWithoutChangingWidth + */ + void setPointHeight (float newHeight); + /** Changes the font's height without changing its width. This alters the horizontal scale to compensate for the change in height. */ diff --git a/modules/juce_graphics/fonts/juce_FontOptions.cpp b/modules/juce_graphics/fonts/juce_FontOptions.cpp index 4f924f6a4d..74e27485ef 100644 --- a/modules/juce_graphics/fonts/juce_FontOptions.cpp +++ b/modules/juce_graphics/fonts/juce_FontOptions.cpp @@ -72,7 +72,7 @@ FontOptions::FontOptions (const String& typefaceName, float fontHeight, int styl } FontOptions::FontOptions (const String& typefaceName, const String& typefaceStyle, float fontHeight) - : name (typefaceName.isEmpty() ? Font::getDefaultSansSerifFontName() : typefaceName), + : name (typefaceName), style (typefaceStyle), height (FontValues::limitFontHeight (fontHeight)) { @@ -94,6 +94,7 @@ auto FontOptions::tie() const fallbacks, metricsKind, height, + pointHeight, tracking, horizontalScale, fallbackEnabled, diff --git a/modules/juce_graphics/fonts/juce_FontOptions.h b/modules/juce_graphics/fonts/juce_FontOptions.h index a919a357a3..2dcdd8c1e5 100644 --- a/modules/juce_graphics/fonts/juce_FontOptions.h +++ b/modules/juce_graphics/fonts/juce_FontOptions.h @@ -109,8 +109,22 @@ public: /** Returns a copy of these options with font fallback enabled or disabled. */ [[nodiscard]] FontOptions withFallbackEnabled (bool x = true) const { return withMember (*this, &FontOptions::fallbackEnabled, x); } - /** Returns a copy of these options with the specified height in pixels (can be fractional). */ - [[nodiscard]] FontOptions withHeight (float x) const { return withMember (*this, &FontOptions::height, x); } + /** Returns a copy of these options with the specified height in JUCE units (can be fractional). + + FontOptions can hold either a JUCE height, set via withHeight(), or a point height, set via withPointHeight(). + After calling withHeight(), the result of getPointHeight() will be -1.0f to indicate that the point height is unset. + + For more information about how JUCE font heights work, see Font::setHeight(). + */ + [[nodiscard]] FontOptions withHeight (float x) const { jassert (x > 0); auto copy = *this; copy.height = x; copy.pointHeight = -1.0f; return copy; } + + /** Returns a copy of these options with the specified height in points (can be fractional). + + After calling withPointHeight(), the result of getHeight() will be -1.0f to indicate that the JUCE height is unset. + + For more information about how point heights work, see Font::setPointHeight(). + */ + [[nodiscard]] FontOptions withPointHeight (float x) const { jassert (x > 0); auto copy = *this; copy.pointHeight = x; copy.height = -1.0f; return copy; } /** Returns a copy of these options with the specified extra kerning factor (also called "tracking"). */ [[nodiscard]] FontOptions withKerningFactor (float x) const { return withMember (*this, &FontOptions::tracking, x); } @@ -134,6 +148,8 @@ public: [[nodiscard]] auto getFallbacks() const { return fallbacks; } /** @see withHeight() */ [[nodiscard]] auto getHeight() const { return height; } + /** @see withPointHeight() */ + [[nodiscard]] auto getPointHeight() const { return pointHeight; } /** @see withKerningFactor() */ [[nodiscard]] auto getKerningFactor() const { return tracking; } /** @see withHorizontalScale() */ @@ -165,7 +181,8 @@ private: Typeface::Ptr typeface; std::vector fallbacks; TypefaceMetricsKind metricsKind { TypefaceMetricsKind::portable }; - float height{}; + float height = -1.0f; + float pointHeight = -1.0f; float tracking{}; float horizontalScale = 1.0f; bool fallbackEnabled = true; diff --git a/modules/juce_graphics/fonts/juce_Typeface.h b/modules/juce_graphics/fonts/juce_Typeface.h index 5fc94dc403..31c4b39a9c 100644 --- a/modules/juce_graphics/fonts/juce_Typeface.h +++ b/modules/juce_graphics/fonts/juce_Typeface.h @@ -361,6 +361,18 @@ public: On Android 29+, this will use AFontMatcher to return the "system-ui" font. On earlier Android versions, this will attempt to return the Roboto font. + + NOTE: The metrics of the system typeface may be significantly different from the metrics of + the sans-serif font that JUCE would normally select to be the default font. This is + especially evident on Windows: For Segoe UI (the Windows system typeface) + the sum of ascender and descender is somewhat larger than the em-size of the font, + but for Verdana (the JUCE default sans-serif font on Windows) the sum of ascender and + descender is closer to the em-size. When the size of a font is set via + FontOptions::withHeight() or Font::setHeight(), JUCE will scale fonts based on the sum of + ascender and descender, so switching to Segoe UI might cause text to render at a much + smaller size than with Verdana. You may get better results by setting font sizes in points + using FontOptions::withFontHeight() and Font::setPointHeight(). When using points, Segoe UI + still renders slightly smaller than Verdana, but the differences are less pronounced. */ static Typeface::Ptr findSystemTypeface();