diff --git a/Common/Render/Text/draw_text.cpp b/Common/Render/Text/draw_text.cpp index b54c6c6a90..f2a88343f6 100644 --- a/Common/Render/Text/draw_text.cpp +++ b/Common/Render/Text/draw_text.cpp @@ -65,31 +65,36 @@ TextDrawer::TextDrawer(Draw::DrawContext *draw) : draw_(draw) { float TextDrawerWordWrapper::MeasureWidth(std::string_view str) { float w, h; - drawer_->MeasureString(str, &w, &h); + drawer_->MeasureString(style_, scale_, scale_, str, &w, &h); return w; } -const TextCacheKey &TextDrawer::LookupKey(std::string_view str, int flags, float maxWidth, float scale) { +const TextCacheKey &TextDrawer::LookupKey(const FontStyle &style, std::string_view str, int flags, float maxWidth, float scale) { lookupKey_.text.assign(str.data(), str.size()); - lookupKey_.style = fontStyle_; + lookupKey_.style = style; lookupKey_.flags = flags; lookupKey_.maxWidth = maxWidth; lookupKey_.scale = scale; return lookupKey_; } -const std::string &TextDrawer::WrapString(std::string_view str, float maxW, int flags) { +const std::string &TextDrawer::WrapString(const FontStyle &style, float scale, std::string_view str, float maxW, int flags) { // The wrapper measures in scaled units, so the result depends on the scale too. - auto [iter, inserted] = wrapCache_.try_emplace(LookupKey(str, flags, maxW, fontScaleX_)); + auto [iter, inserted] = wrapCache_.try_emplace(LookupKey(style, str, flags, maxW, scale)); TextWrapEntry &entry = iter->second; entry.lastUsedFrame = frameCount_; if (inserted) { - TextDrawerWordWrapper wrapper(this, str, maxW, flags); + TextDrawerWordWrapper wrapper(this, style, scale, str, maxW, flags); entry.wrapped = wrapper.Wrapped(); } return entry.wrapped; } +void TextDrawer::SetOrCreateFont(const FontStyle &style) { + EnsureFont(style); + fontStyle_ = style; +} + void TextDrawer::SetFontScale(float xscale, float yscale) { fontScaleX_ = xscale; fontScaleY_ = yscale; @@ -112,7 +117,7 @@ void TextDrawer::DrawString(DrawBuffer &target, std::string_view str, float x, f TextStringEntry *entry; - auto [iter, inserted] = cache_.try_emplace(LookupKey(str, align & FLAG_DROP_SHADOW)); + auto [iter, inserted] = cache_.try_emplace(LookupKey(fontStyle_, str, align & FLAG_DROP_SHADOW)); if (!inserted) { entry = iter->second.get(); entry->lastUsedFrame = frameCount_; @@ -186,7 +191,7 @@ void TextDrawer::DrawString(DrawBuffer &target, std::string_view str, float x, f target.Flush(true); } -void TextDrawer::MeasureString(std::string_view str, float *w, float *h) { +void TextDrawer::MeasureString(const FontStyle &style, float scaleX, float scaleY, std::string_view str, float *w, float *h) { if (str.empty()) { *w = 0.0f; *h = 0.0f; @@ -198,11 +203,12 @@ void TextDrawer::MeasureString(std::string_view str, float *w, float *h) { str = str.substr(0, MAX_TEXT_LENGTH); } - auto [iter, inserted] = sizeCache_.try_emplace(LookupKey(str)); + auto [iter, inserted] = sizeCache_.try_emplace(LookupKey(style, str)); TextMeasureEntry &entry = iter->second; if (inserted) { - float extW, extH; - MeasureStringInternal(str, &extW, &extH); + EnsureFont(style); + float extW = 0.0f, extH = 0.0f; + MeasureStringInternal(style, str, &extW, &extH); entry.width = extW; entry.height = extH; // Hm, use the old calculation? @@ -210,11 +216,11 @@ void TextDrawer::MeasureString(std::string_view str, float *w, float *h) { } entry.lastUsedFrame = frameCount_; - *w = entry.width * fontScaleX_ * dpiScale_; - *h = entry.height * fontScaleY_ * dpiScale_; + *w = entry.width * scaleX * dpiScale_; + *h = entry.height * scaleY * dpiScale_; } -void TextDrawer::MeasureStringRect(std::string_view str, float maxWidth, float *w, float *h, int align) { +void TextDrawer::MeasureStringRect(const FontStyle &style, float scaleX, float scaleY, std::string_view str, float maxWidth, float *w, float *h, int align) { const int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); // Clamp the size to something sane. @@ -223,10 +229,10 @@ void TextDrawer::MeasureStringRect(std::string_view str, float maxWidth, float * } float plainW, plainH; - MeasureString(str, &plainW, &plainH); + MeasureString(style, scaleX, scaleY, str, &plainW, &plainH); if (wrap && plainW > maxWidth) { - MeasureString(WrapString(str, maxWidth, wrap), w, h); + MeasureString(style, scaleX, scaleY, WrapString(style, scaleX, str, maxWidth, wrap), w, h); } else { *w = plainW; *h = plainH; @@ -256,7 +262,7 @@ void TextDrawer::DrawStringRect(DrawBuffer &target, std::string_view str, const } const int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); - DrawString(target, wrap ? std::string_view(WrapString(str, bounds.w, wrap)) : str, x, y, color, align); + DrawString(target, wrap ? std::string_view(WrapString(fontStyle_, fontScaleX_, str, bounds.w, wrap)) : str, x, y, color, align); } bool TextDrawer::DrawStringBitmapRect(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, const Bounds &bounds, int align, bool fullColor) { @@ -266,7 +272,7 @@ bool TextDrawer::DrawStringBitmapRect(std::vector &bitmapData, TextStri } const int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); - return DrawStringBitmap(bitmapData, entry, texFormat, wrap ? std::string_view(WrapString(str, bounds.w, wrap)) : str, align, fullColor); + return DrawStringBitmap(bitmapData, entry, texFormat, wrap ? std::string_view(WrapString(fontStyle_, fontScaleX_, str, bounds.w, wrap)) : str, align, fullColor); } void TextDrawer::AddDropShadow(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat srcFormat) const { diff --git a/Common/Render/Text/draw_text.h b/Common/Render/Text/draw_text.h index f3c250bf66..d5033aee12 100644 --- a/Common/Render/Text/draw_text.h +++ b/Common/Render/Text/draw_text.h @@ -71,11 +71,20 @@ public: virtual ~TextDrawer() = default; virtual bool IsReady() const { return true; } - virtual void SetOrCreateFont(const FontStyle &style) = 0; - + // Sets the font and scale that drawing uses. + void SetOrCreateFont(const FontStyle &style); void SetFontScale(float xscale, float yscale); - void MeasureString(std::string_view str, float *w, float *h); - void MeasureStringRect(std::string_view str, float maxWidth, float *w, float *h, int align = ALIGN_TOPLEFT); + + // Measuring doesn't depend on the current font and scale. + void MeasureString(const FontStyle &style, float scaleX, float scaleY, std::string_view str, float *w, float *h); + void MeasureStringRect(const FontStyle &style, float scaleX, float scaleY, std::string_view str, float maxWidth, float *w, float *h, int align = ALIGN_TOPLEFT); + // In the current font and scale. + void MeasureString(std::string_view str, float *w, float *h) { + MeasureString(fontStyle_, fontScaleX_, fontScaleY_, str, w, h); + } + void MeasureStringRect(std::string_view str, float maxWidth, float *w, float *h, int align = ALIGN_TOPLEFT) { + MeasureStringRect(fontStyle_, fontScaleX_, fontScaleY_, str, maxWidth, w, h, align); + } void DrawString(DrawBuffer &target, std::string_view str, float x, float y, uint32_t color, int align = ALIGN_TOPLEFT); void DrawStringRect(DrawBuffer &target, std::string_view str, const Bounds &bounds, uint32_t color, int align); @@ -102,8 +111,10 @@ public: protected: TextDrawer(Draw::DrawContext *draw); - // Implementations of this must handle multi-line strings. - virtual void MeasureStringInternal(std::string_view str, float *w, float *h) = 0; + // Creates the font for style, if it isn't already. + virtual void EnsureFont(const FontStyle &style) = 0; + // Implementations of this must handle multi-line strings. EnsureFont has been called for style. + virtual void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) = 0; void ClearCache(); @@ -111,7 +122,7 @@ protected: virtual void ClearFonts() = 0; // Wraps and/or ellipsizes, caching the result. The reference stays valid until the next OncePerFrame. - const std::string &WrapString(std::string_view str, float maxWidth, int flags); + const std::string &WrapString(const FontStyle &style, float scale, std::string_view str, float maxWidth, int flags); // v has the 8-bit alpha. static u16 AlphaToPremul4444(u32 v) { @@ -153,7 +164,7 @@ protected: static constexpr size_t MAX_TEXT_LENGTH = 16384; // Fills in and returns lookupKey_, which reuses its string buffer, so a cache hit doesn't allocate. - const TextCacheKey &LookupKey(std::string_view str, int flags = 0, float maxWidth = 0.0f, float scale = 0.0f); + const TextCacheKey &LookupKey(const FontStyle &style, std::string_view str, int flags = 0, float maxWidth = 0.0f, float scale = 0.0f); void AddDropShadow(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat srcFormat) const; TextCacheKey lookupKey_; @@ -165,13 +176,15 @@ protected: class TextDrawerWordWrapper : public WordWrapper { public: - TextDrawerWordWrapper(TextDrawer *drawer, std::string_view str, float maxW, int flags) - : WordWrapper(str, maxW, flags), drawer_(drawer) {} + TextDrawerWordWrapper(TextDrawer *drawer, const FontStyle &style, float scale, std::string_view str, float maxW, int flags) + : WordWrapper(str, maxW, flags), drawer_(drawer), style_(style), scale_(scale) {} protected: float MeasureWidth(std::string_view str) override; TextDrawer *drawer_; + FontStyle style_; + float scale_; }; // The backends can use this to query the filenames of the fonts. diff --git a/Common/Render/Text/draw_text_android.cpp b/Common/Render/Text/draw_text_android.cpp index 6623e0bd19..b95b81cccf 100644 --- a/Common/Render/Text/draw_text_android.cpp +++ b/Common/Render/Text/draw_text_android.cpp @@ -58,12 +58,10 @@ bool TextDrawerAndroid::IsReady() const { return cls_textRenderer != nullptr && method_measureText != nullptr && method_renderText != nullptr; } -void TextDrawerAndroid::SetOrCreateFont(const FontStyle &style) { +void TextDrawerAndroid::EnsureFont(const FontStyle &style) { // We will only use the default font but just for consistency let's still involve // the font name. - auto iter = fontMap_.find(style); - if (iter != fontMap_.end()) { - fontStyle_ = style; + if (fontMap_.find(style) != fontMap_.end()) { return; } @@ -98,11 +96,10 @@ void TextDrawerAndroid::SetOrCreateFont(const FontStyle &style) { // Just chose a factor that looks good, don't know what unit size is in anyway. fontMap_[style] = entry; - fontStyle_ = style; } -void TextDrawerAndroid::MeasureStringInternal(std::string_view str, float *w, float *h) { - auto iter = fontMap_.find(fontStyle_); +void TextDrawerAndroid::MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) { + auto iter = fontMap_.find(style); if (iter == fontMap_.end()) { ERROR_LOG(Log::G3D, "Missing font"); *w = 1.0f; diff --git a/Common/Render/Text/draw_text_android.h b/Common/Render/Text/draw_text_android.h index 3262aa42ab..1156619929 100644 --- a/Common/Render/Text/draw_text_android.h +++ b/Common/Render/Text/draw_text_android.h @@ -20,11 +20,11 @@ public: ~TextDrawerAndroid(); bool IsReady() const override; - void SetOrCreateFont(const FontStyle &style) override; bool DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override; protected: - void MeasureStringInternal(std::string_view str, float *w, float *h) override; + void EnsureFont(const FontStyle &style) override; + void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override; bool SupportsColorEmoji() const override { return true; } void ClearFonts() override; diff --git a/Common/Render/Text/draw_text_cocoa.h b/Common/Render/Text/draw_text_cocoa.h index 2581946bb9..c61eec39ba 100644 --- a/Common/Render/Text/draw_text_cocoa.h +++ b/Common/Render/Text/draw_text_cocoa.h @@ -16,11 +16,11 @@ public: TextDrawerCocoa(Draw::DrawContext *draw); ~TextDrawerCocoa(); - void SetOrCreateFont(const FontStyle &style) override; bool DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override; protected: - void MeasureStringInternal(std::string_view str, float *w, float *h) override; + void EnsureFont(const FontStyle &style) override; + void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override; bool SupportsColorEmoji() const override { return true; } void ClearFonts() override; diff --git a/Common/Render/Text/draw_text_cocoa.mm b/Common/Render/Text/draw_text_cocoa.mm index 449ac404d1..3dfa3fff3e 100644 --- a/Common/Render/Text/draw_text_cocoa.mm +++ b/Common/Render/Text/draw_text_cocoa.mm @@ -137,21 +137,18 @@ TextDrawerCocoa::~TextDrawerCocoa() { } // TODO: Share with other backends. -void TextDrawerCocoa::SetOrCreateFont(const FontStyle &style) { +void TextDrawerCocoa::EnsureFont(const FontStyle &style) { if (style.sizePts <= 0) { return; } - auto iter = fontMap_.find(style); - if (iter != fontMap_.end()) { - fontStyle_ = style; + if (fontMap_.find(style) != fontMap_.end()) { return; } TextDrawerFontContext *font = new TextDrawerFontContext(style, dpiScale_); fontMap_[style] = std::unique_ptr(font); - fontStyle_ = style; } void TextDrawerCocoa::ClearFonts() { @@ -163,8 +160,8 @@ void TextDrawerCocoa::ClearFonts() { } // AI added some error checks here. -void TextDrawerCocoa::MeasureStringInternal(std::string_view str, float *w, float *h) { - auto iter = fontMap_.find(fontStyle_); +void TextDrawerCocoa::MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) { + auto iter = fontMap_.find(style); NSDictionary *attributes = nil; if (iter != fontMap_.end()) { attributes = iter->second->attributes; diff --git a/Common/Render/Text/draw_text_sdl.cpp b/Common/Render/Text/draw_text_sdl.cpp index 0d6dd251a3..2cde9fae30 100644 --- a/Common/Render/Text/draw_text_sdl.cpp +++ b/Common/Render/Text/draw_text_sdl.cpp @@ -297,13 +297,7 @@ void TextDrawerSDL::PrepareFallbackFonts(std::string_view locale) { #endif } -uint32_t TextDrawerSDL::CheckMissingGlyph(std::string_view text) { - auto iter = fontMap_.find(fontStyle_); - if (iter == fontMap_.end()) { - return 0; - } - - TTF_Font *font = iter->second.first; +uint32_t TextDrawerSDL::CheckMissingGlyph(TTF_Font *font, std::string_view text) { if (!font) { return 0; } @@ -360,10 +354,8 @@ int TextDrawerSDL::FindFallbackFonts(uint32_t missingGlyph, int ptSize) { return -1; } -void TextDrawerSDL::SetOrCreateFont(const FontStyle &style) { - auto iter = fontMap_.find(style); - if (iter != fontMap_.end()) { - fontStyle_ = style; +void TextDrawerSDL::EnsureFont(const FontStyle &style) { + if (fontMap_.find(style) != fontMap_.end()) { return; } @@ -387,13 +379,12 @@ void TextDrawerSDL::SetOrCreateFont(const FontStyle &style) { } fontMap_[style] = std::make_pair(font, fileData); - fontStyle_ = style; } -void TextDrawerSDL::MeasureStringInternal(std::string_view str, float *w, float *h) { +void TextDrawerSDL::MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) { *w = 1.0f; *h = 1.0f; - auto iter = fontMap_.find(fontStyle_); + auto iter = fontMap_.find(style); if (iter == fontMap_.end()) { return; } @@ -408,10 +399,10 @@ void TextDrawerSDL::MeasureStringInternal(std::string_view str, float *w, float str = reorderedStr; } - uint32_t missingGlyph = CheckMissingGlyph(str); + uint32_t missingGlyph = CheckMissingGlyph(font, str); if (missingGlyph) { - const int ptSize = static_cast(fontStyle_.sizePts / dpiScale_ * 1.25f); + const int ptSize = static_cast(style.sizePts / dpiScale_ * 1.25f); const int fallbackFont = FindFallbackFonts(missingGlyph, ptSize); if (fallbackFont >= 0 && fallbackFont < (int)fallbackFonts_.size()) { font = fallbackFonts_[fallbackFont]; @@ -478,7 +469,7 @@ bool TextDrawerSDL::DrawStringBitmap(std::vector &bitmapData, TextStrin processedStr.push_back(' '); } - uint32_t missingGlyph = CheckMissingGlyph(processedStr); + uint32_t missingGlyph = CheckMissingGlyph(font, processedStr); if (missingGlyph) { const int ptSize = static_cast(TTF_GetFontSize(font)); diff --git a/Common/Render/Text/draw_text_sdl.h b/Common/Render/Text/draw_text_sdl.h index 34c657dd82..9744002689 100644 --- a/Common/Render/Text/draw_text_sdl.h +++ b/Common/Render/Text/draw_text_sdl.h @@ -19,18 +19,18 @@ public: TextDrawerSDL(Draw::DrawContext *draw); ~TextDrawerSDL(); - void SetOrCreateFont(const FontStyle &style) override; bool DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override; protected: - void MeasureStringInternal(std::string_view str, float *w, float *h) override; + void EnsureFont(const FontStyle &style) override; + void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override; bool SupportsColorEmoji() const override { return false; } void ClearFonts() override; private: void PrepareFallbackFonts(std::string_view locale); - uint32_t CheckMissingGlyph(std::string_view text); + uint32_t CheckMissingGlyph(TTF_Font *font, std::string_view text); int FindFallbackFonts(uint32_t missingGlyph, int ptSize); std::map> fontMap_; diff --git a/Common/Render/Text/draw_text_uwp.cpp b/Common/Render/Text/draw_text_uwp.cpp index 890f3c1d51..9242fdbb7f 100644 --- a/Common/Render/Text/draw_text_uwp.cpp +++ b/Common/Render/Text/draw_text_uwp.cpp @@ -261,21 +261,17 @@ TextDrawerUWP::~TextDrawerUWP() { delete ctx_; } -void TextDrawerUWP::SetOrCreateFont(const FontStyle &style) { +void TextDrawerUWP::EnsureFont(const FontStyle &style) { _dbg_assert_(style.sizePts > 0); - auto iter = fontMap_.find(style); - if (iter != fontMap_.end()) { - fontStyle_ = style; + if (fontMap_.find(style) != fontMap_.end()) { return; } - fontMap_[style] = std::make_unique(style, dpiScale_, m_dwriteFactory, m_fontCollection); - fontStyle_ = style; } -void TextDrawerUWP::MeasureStringInternal(std::string_view str, float *w, float *h) { +void TextDrawerUWP::MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) { IDWriteTextFormat *format = nullptr; - auto iter = fontMap_.find(fontStyle_); + auto iter = fontMap_.find(style); if (iter != fontMap_.end()) { format = iter->second->textFmt; } diff --git a/Common/Render/Text/draw_text_uwp.h b/Common/Render/Text/draw_text_uwp.h index 459008f136..95b7300078 100644 --- a/Common/Render/Text/draw_text_uwp.h +++ b/Common/Render/Text/draw_text_uwp.h @@ -20,11 +20,11 @@ public: TextDrawerUWP(Draw::DrawContext *draw); ~TextDrawerUWP(); - void SetOrCreateFont(const FontStyle &style) override; bool DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override; protected: - void MeasureStringInternal(std::string_view str, float *w, float *h) override; + void EnsureFont(const FontStyle &style) override; + void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override; bool SupportsColorEmoji() const override { return true; } void ClearFonts() override; diff --git a/Common/Render/Text/draw_text_win.cpp b/Common/Render/Text/draw_text_win.cpp index 8e2e9b8e07..9caf064660 100644 --- a/Common/Render/Text/draw_text_win.cpp +++ b/Common/Render/Text/draw_text_win.cpp @@ -117,19 +117,15 @@ TextDrawerWin32::~TextDrawerWin32() { delete ctx_; } -void TextDrawerWin32::SetOrCreateFont(const FontStyle &style) { - auto iter = fontMap_.find(style); - if (iter != fontMap_.end()) { - fontStyle_ = style; +void TextDrawerWin32::EnsureFont(const FontStyle &style) { + if (fontMap_.find(style) != fontMap_.end()) { return; } - fontMap_[style] = std::make_unique(style, dpiScale_); - fontStyle_ = style; } -void TextDrawerWin32::MeasureStringInternal(std::string_view str, float *w, float *h) { - auto iter = fontMap_.find(fontStyle_); +void TextDrawerWin32::MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) { + auto iter = fontMap_.find(style); if (iter != fontMap_.end()) { SelectObject(ctx_->hDC, iter->second->hFont); } else { diff --git a/Common/Render/Text/draw_text_win.h b/Common/Render/Text/draw_text_win.h index 1e40528395..26ebc6c1ce 100644 --- a/Common/Render/Text/draw_text_win.h +++ b/Common/Render/Text/draw_text_win.h @@ -16,11 +16,11 @@ public: TextDrawerWin32(Draw::DrawContext *draw); ~TextDrawerWin32(); - void SetOrCreateFont(const FontStyle &style) override; bool DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override; protected: - void MeasureStringInternal(std::string_view str, float *w, float *h) override; + void EnsureFont(const FontStyle &style) override; + void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override; bool SupportsColorEmoji() const override { return false; } void ClearFonts() override; diff --git a/Common/UI/Context.cpp b/Common/UI/Context.cpp index 1e4832ebc7..26928a5a03 100644 --- a/Common/UI/Context.cpp +++ b/Common/UI/Context.cpp @@ -284,19 +284,7 @@ void UIContext::MeasureText(const FontStyle &style, float scaleX, float scaleY, Draw()->SetFontScale(scaleX * sizeFactor, scaleY * sizeFactor); Draw()->MeasureText(AtlasFontFromStyle(style), str, x, y); } else { - // Switching fonts costs two lookups, and most measuring is done in the current style. - const bool switchFont = !(style == *fontStyle_); - if (switchFont) { - textDrawer_->SetOrCreateFont(style); - } - textDrawer_->SetFontScale(scaleX, scaleY); - textDrawer_->MeasureString(str, x, y); - if (switchFont) { - // Check for bad "old font". - if (fontStyle_ && fontStyle_->sizePts > 0) { - textDrawer_->SetOrCreateFont(*fontStyle_); - } - } + textDrawer_->MeasureString(style, scaleX, scaleY, str, x, y); } } @@ -307,16 +295,7 @@ void UIContext::MeasureTextRect(const FontStyle &style, float scaleX, float scal Draw()->SetFontScale(scaleX * sizeFactor, scaleY * sizeFactor); Draw()->MeasureTextRect(AtlasFontFromStyle(style), str, maxWidth, x, y, align); } else { - // Switching fonts costs two lookups, and most measuring is done in the current style. - const bool switchFont = !(style == *fontStyle_); - if (switchFont) { - textDrawer_->SetOrCreateFont(style); - } - textDrawer_->SetFontScale(scaleX, scaleY); - textDrawer_->MeasureStringRect(str, maxWidth, x, y, align); - if (switchFont) { - textDrawer_->SetOrCreateFont(*fontStyle_); - } + textDrawer_->MeasureStringRect(style, scaleX, scaleY, str, maxWidth, x, y, align); } } diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp index e3f2ec2c25..35fa45989a 100644 --- a/unittest/UnitTest.cpp +++ b/unittest/UnitTest.cpp @@ -3744,17 +3744,19 @@ bool TestFatShortNames() { class FakeTextDrawer : public TextDrawer { public: FakeTextDrawer() : TextDrawer(nullptr) {} - void SetOrCreateFont(const FontStyle &style) override { fontStyle_ = style; } bool DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override { return false; } void TestDropShadow(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat srcFormat) { AddDropShadow(bitmapData, entry, srcFormat); } + const FontStyle &CurrentStyle() const { return fontStyle_; } + int measureCalls = 0; protected: - void MeasureStringInternal(std::string_view str, float *w, float *h) override { + void EnsureFont(const FontStyle &style) override {} + void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override { measureCalls++; std::vector lines; SplitString(str, '\n', lines); @@ -3786,6 +3788,16 @@ bool TestTextDrawerCache() { drawer.MeasureString("hello", &w, &h); EXPECT_EQ_INT(drawer.measureCalls, 2); + // Measuring in another style and scale leaves the current ones alone. + const FontStyle small(FontFamily::SansSerif, 10, FontStyleFlags::Default); + drawer.MeasureString(small, 2.0f, 2.0f, "hello", &w, &h); + EXPECT_EQ_FLOAT(w, 100.0f); + EXPECT_EQ_INT(drawer.measureCalls, 3); + EXPECT_TRUE(drawer.CurrentStyle() == FontStyle(FontFamily::SansSerif, 30, FontStyleFlags::Default)); + drawer.MeasureString("hello", &w, &h); + EXPECT_EQ_FLOAT(w, 50.0f); + EXPECT_EQ_INT(drawer.measureCalls, 3); + const std::string_view para = "The quick brown fox jumps over the lazy dog, and then it does it again, and again, until the dog finally gets up and leaves."; drawer.MeasureStringRect(para, 200.0f, &w, &h, FLAG_WRAP_TEXT); // The trailing space of a wrapped line is measured too.