From 49e86f5e7684692fe48ac798bfa3fb2d9daf5987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 16 Oct 2024 13:00:24 +0200 Subject: [PATCH 1/4] Update the rcheevos submodule --- ext/rcheevos | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/rcheevos b/ext/rcheevos index 563230b1c2..32917bdddf 160000 --- a/ext/rcheevos +++ b/ext/rcheevos @@ -1 +1 @@ -Subproject commit 563230b1c249774b4852c944dc7cdcb952c9e8e8 +Subproject commit 32917bdddf4982e62047862c6633e7671aaaf2cb From ce980af01e5c8bd2145093e4ff70d865f67b9be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 16 Oct 2024 13:35:32 +0200 Subject: [PATCH 2/4] TextDrawer: Improve performance for text wrapping (by measuring without wrapping first) --- Common/Render/Text/draw_text.cpp | 17 +++++++++++------ Common/Render/Text/draw_text.h | 2 +- UI/BackgroundAudio.cpp | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Common/Render/Text/draw_text.cpp b/Common/Render/Text/draw_text.cpp index e70d4d6a81..a9d0f52db3 100644 --- a/Common/Render/Text/draw_text.cpp +++ b/Common/Render/Text/draw_text.cpp @@ -18,8 +18,6 @@ TextDrawer::TextDrawer(Draw::DrawContext *draw) : draw_(draw) { // These probably shouldn't be state. dpiScale_ = CalculateDPIScale(); } -TextDrawer::~TextDrawer() { -} float TextDrawerWordWrapper::MeasureWidth(std::string_view str) { float w, h; @@ -124,12 +122,19 @@ void TextDrawer::DrawString(DrawBuffer &target, std::string_view str, float x, f } void TextDrawer::MeasureStringRect(std::string_view str, const Bounds &bounds, float *w, float *h, int align) { - std::string toMeasure = std::string(str); int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); - if (wrap) { + + float plainW, plainH; + MeasureString(str, &plainW, &plainH); + + if (wrap && plainW > bounds.w) { + std::string toMeasure = std::string(str); WrapString(toMeasure, toMeasure.c_str(), bounds.w, wrap); + MeasureString(toMeasure, w, h); + } else { + *w = plainW; + *h = plainH; } - MeasureString(toMeasure, w, h); } void TextDrawer::DrawStringRect(DrawBuffer &target, std::string_view str, const Bounds &bounds, uint32_t color, int align) { @@ -186,7 +191,7 @@ void TextDrawer::OncePerFrame() { } // Drop old strings. Use a prime number to reduce clashing with other rhythms - if (frameCount_ % 23 == 0) { + if (frameCount_ % 63 == 0) { for (auto iter = cache_.begin(); iter != cache_.end();) { if (frameCount_ - iter->second->lastUsedFrame > 100) { if (iter->second->texture) diff --git a/Common/Render/Text/draw_text.h b/Common/Render/Text/draw_text.h index 3392c92e53..bb7344b561 100644 --- a/Common/Render/Text/draw_text.h +++ b/Common/Render/Text/draw_text.h @@ -42,7 +42,7 @@ struct TextMeasureEntry { class TextDrawer { public: - virtual ~TextDrawer(); + virtual ~TextDrawer() = default; virtual bool IsReady() const { return true; } virtual uint32_t SetFont(const char *fontName, int size, int flags) = 0; diff --git a/UI/BackgroundAudio.cpp b/UI/BackgroundAudio.cpp index 2dabf2e4ee..1e35d90cb5 100644 --- a/UI/BackgroundAudio.cpp +++ b/UI/BackgroundAudio.cpp @@ -571,7 +571,7 @@ public: TaskPriority Priority() const override { return TaskPriority::NORMAL; } - virtual void Run() { + virtual void Run() override { mixer_->LoadSamplesOnThread(); } private: From 3def2ddb000cb2cf83a2e05cfa6b9f089be47693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 16 Oct 2024 14:35:54 +0200 Subject: [PATCH 3/4] Avoid another allocation, this time with atlas fonts --- Common/Render/DrawBuffer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Common/Render/DrawBuffer.cpp b/Common/Render/DrawBuffer.cpp index 63c06f4c98..5310dd612b 100644 --- a/Common/Render/DrawBuffer.cpp +++ b/Common/Render/DrawBuffer.cpp @@ -521,7 +521,6 @@ void DrawBuffer::MeasureTextRect(FontID font_id, std::string_view text, const Bo return; } - std::string toMeasure = std::string(text); int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); if (wrap) { const AtlasFont *font = fontAtlas_->getFont(font_id); @@ -532,10 +531,12 @@ void DrawBuffer::MeasureTextRect(FontID font_id, std::string_view text, const Bo *h = 0.0f; return; } + std::string toMeasure = std::string(text); AtlasWordWrapper wrapper(*font, fontscalex, toMeasure, bounds.w, wrap); toMeasure = wrapper.Wrapped(); + } else { + MeasureText(font_id, text, w, h); } - MeasureText(font_id, toMeasure, w, h); } void DrawBuffer::DrawTextShadow(FontID font, std::string_view text, float x, float y, Color color, int flags) { From e49d94ad11ddec0bbae0ec5ab5eb2279b254215a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 16 Oct 2024 13:46:32 +0200 Subject: [PATCH 4/4] Unify the MeasureString caching code --- Common/Render/Text/draw_text.cpp | 29 ++++++++++ Common/Render/Text/draw_text.h | 7 ++- Common/Render/Text/draw_text_android.cpp | 48 ++++++----------- Common/Render/Text/draw_text_android.h | 2 +- Common/Render/Text/draw_text_cocoa.h | 2 +- Common/Render/Text/draw_text_cocoa.mm | 69 ++++++++++-------------- Common/Render/Text/draw_text_qt.cpp | 26 +++------ Common/Render/Text/draw_text_qt.h | 2 +- Common/Render/Text/draw_text_sdl.cpp | 53 +++++++----------- Common/Render/Text/draw_text_sdl.h | 5 +- Common/Render/Text/draw_text_uwp.cpp | 66 +++++++++-------------- Common/Render/Text/draw_text_uwp.h | 2 +- Common/Render/Text/draw_text_win.cpp | 60 ++++++++------------- Common/Render/Text/draw_text_win.h | 2 +- 14 files changed, 158 insertions(+), 215 deletions(-) diff --git a/Common/Render/Text/draw_text.cpp b/Common/Render/Text/draw_text.cpp index a9d0f52db3..6c0c9af93f 100644 --- a/Common/Render/Text/draw_text.cpp +++ b/Common/Render/Text/draw_text.cpp @@ -121,6 +121,35 @@ 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) { + if (str.empty()) { + *w = 0.0; + *h = 0.0; + return; + } + + CacheKey key{ std::string(str), fontHash_ }; + + TextMeasureEntry *entry; + auto iter = sizeCache_.find(key); + if (iter != sizeCache_.end()) { + entry = iter->second.get(); + } else { + entry = new TextMeasureEntry(); + float extW, extH; + MeasureStringInternal(str, &extW, &extH); + entry->width = extW; + entry->height = extH; + // Hm, use the old calculation? + // int h = i == lines.size() - 1 ? entry->height : metrics.tmHeight + metrics.tmExternalLeading; + sizeCache_[key] = std::unique_ptr(entry); + } + + entry->lastUsedFrame = frameCount_; + *w = entry->width * fontScaleX_ * dpiScale_; + *h = entry->height * fontScaleY_ * dpiScale_; +} + void TextDrawer::MeasureStringRect(std::string_view str, const Bounds &bounds, float *w, float *h, int align) { int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); diff --git a/Common/Render/Text/draw_text.h b/Common/Render/Text/draw_text.h index bb7344b561..8a45a850b0 100644 --- a/Common/Render/Text/draw_text.h +++ b/Common/Render/Text/draw_text.h @@ -48,8 +48,8 @@ public: virtual uint32_t SetFont(const char *fontName, int size, int flags) = 0; virtual void SetFont(uint32_t fontHandle) = 0; // Shortcut once you've set the font once. void SetFontScale(float xscale, float yscale); - virtual void MeasureString(std::string_view str, float *w, float *h) = 0; - virtual void MeasureStringRect(std::string_view str, const Bounds &bounds, float *w, float *h, int align = ALIGN_TOPLEFT); + void MeasureString(std::string_view str, float *w, float *h); + void MeasureStringRect(std::string_view str, const Bounds &bounds, float *w, float *h, int align = ALIGN_TOPLEFT); 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); @@ -69,6 +69,9 @@ public: protected: TextDrawer(Draw::DrawContext *draw); + + virtual void MeasureStringInternal(std::string_view str, float *w, float *h) = 0; + void ClearCache(); virtual bool SupportsColorEmoji() const = 0; diff --git a/Common/Render/Text/draw_text_android.cpp b/Common/Render/Text/draw_text_android.cpp index 2236cd1cbc..351d4b6d10 100644 --- a/Common/Render/Text/draw_text_android.cpp +++ b/Common/Render/Text/draw_text_android.cpp @@ -75,41 +75,23 @@ void TextDrawerAndroid::SetFont(uint32_t fontHandle) { } } -void TextDrawerAndroid::MeasureString(std::string_view str, float *w, float *h) { - if (str.empty()) { - *w = 0.0; - *h = 0.0; - return; - } - - CacheKey key{ std::string(str), fontHash_ }; - TextMeasureEntry *entry; - auto iter = sizeCache_.find(key); - if (iter != sizeCache_.end()) { - entry = iter->second.get(); +void TextDrawerAndroid::MeasureStringInternal(std::string_view str, float *w, float *h) { + float scaledSize = 14; + auto iter = fontMap_.find(fontHash_); + if (iter != fontMap_.end()) { + scaledSize = iter->second.size; } else { - float scaledSize = 14; - auto iter = fontMap_.find(fontHash_); - if (iter != fontMap_.end()) { - scaledSize = iter->second.size; - } else { - ERROR_LOG(Log::G3D, "Missing font"); - } - std::string text(str); - auto env = getEnv(); - // Unfortunate that we can't create a jstr from a std::string_view directly. - jstring jstr = env->NewStringUTF(text.c_str()); - uint32_t size = env->CallStaticIntMethod(cls_textRenderer, method_measureText, jstr, scaledSize); - env->DeleteLocalRef(jstr); - - entry = new TextMeasureEntry(); - entry->width = (size >> 16); - entry->height = (size & 0xFFFF); - sizeCache_[key] = std::unique_ptr(entry); + ERROR_LOG(Log::G3D, "Missing font"); } - entry->lastUsedFrame = frameCount_; - *w = entry->width * fontScaleX_ * dpiScale_; - *h = entry->height * fontScaleY_ * dpiScale_; + std::string text(str); + auto env = getEnv(); + // Unfortunate that we can't create a jstr from a std::string_view directly. + jstring jstr = env->NewStringUTF(text.c_str()); + uint32_t size = env->CallStaticIntMethod(cls_textRenderer, method_measureText, jstr, scaledSize); + env->DeleteLocalRef(jstr); + + *w = (size >> 16); + *h = (size & 0xFFFF); } bool TextDrawerAndroid::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) { diff --git a/Common/Render/Text/draw_text_android.h b/Common/Render/Text/draw_text_android.h index 17212aa331..3d14e31f9f 100644 --- a/Common/Render/Text/draw_text_android.h +++ b/Common/Render/Text/draw_text_android.h @@ -21,10 +21,10 @@ public: bool IsReady() const override; uint32_t SetFont(const char *fontName, int size, int flags) override; void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once. - void MeasureString(std::string_view str, float *w, float *h) 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; 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 011d523a3f..7cc555d7d5 100644 --- a/Common/Render/Text/draw_text_cocoa.h +++ b/Common/Render/Text/draw_text_cocoa.h @@ -18,10 +18,10 @@ public: uint32_t SetFont(const char *fontName, int size, int flags) override; void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once. - void MeasureString(std::string_view str, float *w, float *h) 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; 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 52b615172c..42a3660954 100644 --- a/Common/Render/Text/draw_text_cocoa.mm +++ b/Common/Render/Text/draw_text_cocoa.mm @@ -117,50 +117,35 @@ void TextDrawerCocoa::ClearFonts() { fontMap_.clear(); } -void TextDrawerCocoa::MeasureString(std::string_view str, float *w, float *h) { - CacheKey key{ std::string(str), fontHash_ }; - - TextMeasureEntry *entry; - auto iter = sizeCache_.find(key); - if (iter != sizeCache_.end()) { - entry = iter->second.get(); - } else { - // INFO_LOG(Log::System, "Measuring %.*s", (int)str.length(), str.data()); - - auto iter = fontMap_.find(fontHash_); - NSDictionary *attributes = nil; - if (iter != fontMap_.end()) { - attributes = iter->second->attributes; - } - - std::vector lines; - SplitString(str, '\n', lines); - - int extW = 0, extH = 0; - for (auto &line : lines) { - NSString *string = [[NSString alloc] initWithBytes:line.data() length:line.size() encoding: NSUTF8StringEncoding]; - NSAttributedString* as = [[NSAttributedString alloc] initWithString:string attributes:attributes]; - CTLineRef ctline = CTLineCreateWithAttributedString((CFAttributedStringRef)as); - CGFloat ascent, descent, leading; - double fWidth = CTLineGetTypographicBounds(ctline, &ascent, &descent, &leading); - - size_t width = (size_t)ceilf(fWidth); - size_t height = (size_t)ceilf(ascent + descent); - - if (width > extW) - extW = width; - extH += height; - } - - entry = new TextMeasureEntry(); - entry->width = extW; - entry->height = extH; - sizeCache_[key] = std::unique_ptr(entry); +void TextDrawerCocoa::MeasureStringInternal(std::string_view str, float *w, float *h) { + // INFO_LOG(Log::System, "Measuring %.*s", (int)str.length(), str.data()); + auto iter = fontMap_.find(fontHash_); + NSDictionary *attributes = nil; + if (iter != fontMap_.end()) { + attributes = iter->second->attributes; } - entry->lastUsedFrame = frameCount_; - *w = entry->width * fontScaleX_ * dpiScale_; - *h = entry->height * fontScaleY_ * dpiScale_; + std::vector lines; + SplitString(str, '\n', lines); + + int extW = 0, extH = 0; + for (auto &line : lines) { + NSString *string = [[NSString alloc] initWithBytes:line.data() length:line.size() encoding: NSUTF8StringEncoding]; + NSAttributedString* as = [[NSAttributedString alloc] initWithString:string attributes:attributes]; + CTLineRef ctline = CTLineCreateWithAttributedString((CFAttributedStringRef)as); + CGFloat ascent, descent, leading; + double fWidth = CTLineGetTypographicBounds(ctline, &ascent, &descent, &leading); + + size_t width = (size_t)ceilf(fWidth); + size_t height = (size_t)ceilf(ascent + descent); + + if (width > extW) + extW = width; + extH += height; + } + + *w = extW; + *h = extH; } bool TextDrawerCocoa::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) { diff --git a/Common/Render/Text/draw_text_qt.cpp b/Common/Render/Text/draw_text_qt.cpp index 050761c6e8..21a6e831c2 100644 --- a/Common/Render/Text/draw_text_qt.cpp +++ b/Common/Render/Text/draw_text_qt.cpp @@ -51,27 +51,13 @@ void TextDrawerQt::SetFont(uint32_t fontHandle) { } } -void TextDrawerQt::MeasureString(std::string_view str, float *w, float *h) { - CacheKey key{ std::string(str), fontHash_ }; +void TextDrawerQt::MeasureStringInternal(std::string_view str, float *w, float *h) { + QFont* font = fontMap_.find(fontHash_)->second; + QFontMetrics fm(*font); + QSize size = fm.size(0, QString::fromUtf8(str.data(), str.length())); - TextMeasureEntry *entry; - auto iter = sizeCache_.find(key); - if (iter != sizeCache_.end()) { - entry = iter->second.get(); - } else { - QFont* font = fontMap_.find(fontHash_)->second; - QFontMetrics fm(*font); - QSize size = fm.size(0, QString::fromUtf8(str.data(), str.length())); - - entry = new TextMeasureEntry(); - entry->width = size.width(); - entry->height = size.height(); - sizeCache_[key] = std::unique_ptr(entry); - } - - entry->lastUsedFrame = frameCount_; - *w = entry->width * fontScaleX_ * dpiScale_; - *h = entry->height * fontScaleY_ * dpiScale_; + *w = size.width(); + *h = size.height(); } bool TextDrawerQt::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) { diff --git a/Common/Render/Text/draw_text_qt.h b/Common/Render/Text/draw_text_qt.h index 62c3bdf5b2..9b740fce79 100644 --- a/Common/Render/Text/draw_text_qt.h +++ b/Common/Render/Text/draw_text_qt.h @@ -16,10 +16,10 @@ public: uint32_t SetFont(const char *fontName, int size, int flags) override; void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once. - void MeasureString(std::string_view str, float *w, float *h) 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; bool SupportsColorEmoji() const override { return false; } void ClearFonts() override; diff --git a/Common/Render/Text/draw_text_sdl.cpp b/Common/Render/Text/draw_text_sdl.cpp index cc194cb654..2d5356fc0e 100644 --- a/Common/Render/Text/draw_text_sdl.cpp +++ b/Common/Render/Text/draw_text_sdl.cpp @@ -186,15 +186,13 @@ void TextDrawerSDL::PrepareFallbackFonts(std::string_view locale) { #endif } -uint32_t TextDrawerSDL::CheckMissingGlyph(const std::string& text) { +uint32_t TextDrawerSDL::CheckMissingGlyph(std::string_view text) { TTF_Font *font = fontMap_.find(fontHash_)->second; - UTF8 utf8Decoded(text.c_str()); + UTF8 utf8Decoded(text); uint32_t missingGlyph = 0; - for (int i = 0; i < text.length(); ) { + while (!utf8Decoded.end()) { uint32_t glyph = utf8Decoded.next(); - i = utf8Decoded.byteIndex(); - if (!TTF_GlyphIsProvided32(font, glyph)) { missingGlyph = glyph; break; @@ -279,39 +277,28 @@ void TextDrawerSDL::SetFont(uint32_t fontHandle) { } } -void TextDrawerSDL::MeasureString(std::string_view str, float *w, float *h) { - CacheKey key{ std::string(str), fontHash_ }; +void TextDrawerSDL::MeasureStringInternal(std::string_view str, float *w, float *h) { + TTF_Font *font = fontMap_.find(fontHash_)->second; + int ptSize = TTF_FontHeight(font) / 1.35; - TextMeasureEntry *entry; - auto iter = sizeCache_.find(key); - if (iter != sizeCache_.end()) { - entry = iter->second.get(); - } else { - TTF_Font *font = fontMap_.find(fontHash_)->second; - int ptSize = TTF_FontHeight(font) / 1.35; - - uint32_t missingGlyph = CheckMissingGlyph(key.text); + uint32_t missingGlyph = CheckMissingGlyph(str); - if (missingGlyph) { - int fallbackFont = FindFallbackFonts(missingGlyph, ptSize); - if (fallbackFont >= 0) { - font = fallbackFonts_[fallbackFont]; - } + if (missingGlyph) { + int fallbackFont = FindFallbackFonts(missingGlyph, ptSize); + if (fallbackFont >= 0) { + font = fallbackFonts_[fallbackFont]; } - - int width = 0; - int height = 0; - TTF_SizeUTF8(font, key.text.c_str(), &width, &height); - - entry = new TextMeasureEntry(); - entry->width = width; - entry->height = height; - sizeCache_[key] = std::unique_ptr(entry); } - entry->lastUsedFrame = frameCount_; - *w = entry->width * fontScaleX_ * dpiScale_; - *h = entry->height * fontScaleY_ * dpiScale_; + int width = 0; + int height = 0; + + // Unfortunately we need to zero-terminate here. + std::string text(str); + TTF_SizeUTF8(font, text.c_str(), &width, &height); + + *w = width; + *h = height; } bool TextDrawerSDL::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) { diff --git a/Common/Render/Text/draw_text_sdl.h b/Common/Render/Text/draw_text_sdl.h index b6a2003f0b..267028638f 100644 --- a/Common/Render/Text/draw_text_sdl.h +++ b/Common/Render/Text/draw_text_sdl.h @@ -19,16 +19,17 @@ public: uint32_t SetFont(const char *fontName, int size, int flags) override; void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once. - void MeasureString(std::string_view str, float *w, float *h) 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; + bool SupportsColorEmoji() const override { return false; } void ClearFonts() override; private: void PrepareFallbackFonts(std::string_view locale); - uint32_t CheckMissingGlyph(const std::string& text); + uint32_t CheckMissingGlyph(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 aba313ff96..2169db003e 100644 --- a/Common/Render/Text/draw_text_uwp.cpp +++ b/Common/Render/Text/draw_text_uwp.cpp @@ -204,48 +204,34 @@ void TextDrawerUWP::SetFont(uint32_t fontHandle) { } } -void TextDrawerUWP::MeasureString(std::string_view str, float *w, float *h) { - CacheKey key{ std::string(str), fontHash_ }; - - TextMeasureEntry *entry; - auto iter = sizeCache_.find(key); - if (iter != sizeCache_.end()) { - entry = iter->second.get(); - } else { - IDWriteTextFormat* format = nullptr; - auto iter = fontMap_.find(fontHash_); - if (iter != fontMap_.end()) { - format = iter->second->textFmt; - } - if (!format) return; - - std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(std::string(str), "\n", "\r\n")); - - format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); - - IDWriteTextLayout* layout; - m_dwriteFactory->CreateTextLayout( - (LPWSTR)wstr.c_str(), - (int)wstr.size(), - format, - MAX_TEXT_WIDTH, - MAX_TEXT_HEIGHT, - &layout - ); - - DWRITE_TEXT_METRICS metrics; - layout->GetMetrics(&metrics); - layout->Release(); - - entry = new TextMeasureEntry(); - entry->width = (int)(metrics.width + 1.0f); - entry->height = (int)(metrics.height + 1.0f); - sizeCache_[key] = std::unique_ptr(entry); +void TextDrawerUWP::MeasureStringInternal(std::string_view str, float *w, float *h) { + IDWriteTextFormat* format = nullptr; + auto iter = fontMap_.find(fontHash_); + if (iter != fontMap_.end()) { + format = iter->second->textFmt; } + if (!format) return; - entry->lastUsedFrame = frameCount_; - *w = entry->width * fontScaleX_ * dpiScale_; - *h = entry->height * fontScaleY_ * dpiScale_; + std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(std::string(str), "\n", "\r\n")); + + format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); + + IDWriteTextLayout* layout; + m_dwriteFactory->CreateTextLayout( + (LPWSTR)wstr.c_str(), + (int)wstr.size(), + format, + MAX_TEXT_WIDTH, + MAX_TEXT_HEIGHT, + &layout + ); + + DWRITE_TEXT_METRICS metrics; + layout->GetMetrics(&metrics); + layout->Release(); + + *w = (int)(metrics.width + 1.0f); + *h = (int)(metrics.height + 1.0f); } bool TextDrawerUWP::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) { diff --git a/Common/Render/Text/draw_text_uwp.h b/Common/Render/Text/draw_text_uwp.h index 58f8fdaf71..732451db8a 100644 --- a/Common/Render/Text/draw_text_uwp.h +++ b/Common/Render/Text/draw_text_uwp.h @@ -21,10 +21,10 @@ public: uint32_t SetFont(const char *fontName, int size, int flags) override; void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once. - void MeasureString(std::string_view str, float *w, float *h) 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; 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 05b4fe354a..b49f4fd039 100644 --- a/Common/Render/Text/draw_text_win.cpp +++ b/Common/Render/Text/draw_text_win.cpp @@ -120,46 +120,30 @@ void TextDrawerWin32::SetFont(uint32_t fontHandle) { } } -void TextDrawerWin32::MeasureString(std::string_view str, float *w, float *h) { - CacheKey key{ std::string(str), fontHash_ }; - - TextMeasureEntry *entry; - auto iter = sizeCache_.find(key); - if (iter != sizeCache_.end()) { - entry = iter->second.get(); - } else { - auto iter = fontMap_.find(fontHash_); - if (iter != fontMap_.end()) { - SelectObject(ctx_->hDC, iter->second->hFont); - } - - std::string toMeasure(str); - - std::vector lines; - SplitString(toMeasure, '\n', lines); - - int extW = 0, extH = 0; - for (auto &line : lines) { - SIZE size; - std::wstring wstr = ConvertUTF8ToWString(line); - GetTextExtentPoint32(ctx_->hDC, wstr.c_str(), (int)wstr.size(), &size); - - if (size.cx > extW) - extW = size.cx; - extH += size.cy; - } - - entry = new TextMeasureEntry(); - entry->width = extW; - entry->height = extH; - // Hm, use the old calculation? - // int h = i == lines.size() - 1 ? entry->height : metrics.tmHeight + metrics.tmExternalLeading; - sizeCache_[key] = std::unique_ptr(entry); +void TextDrawerWin32::MeasureStringInternal(std::string_view str, float *w, float *h) { + auto iter = fontMap_.find(fontHash_); + if (iter != fontMap_.end()) { + SelectObject(ctx_->hDC, iter->second->hFont); } - entry->lastUsedFrame = frameCount_; - *w = entry->width * fontScaleX_ * dpiScale_; - *h = entry->height * fontScaleY_ * dpiScale_; + std::string toMeasure(str); + + std::vector lines; + SplitString(toMeasure, '\n', lines); + + int extW = 0, extH = 0; + for (auto &line : lines) { + SIZE size; + std::wstring wstr = ConvertUTF8ToWString(line); + GetTextExtentPoint32(ctx_->hDC, wstr.c_str(), (int)wstr.size(), &size); + + if (size.cx > extW) + extW = size.cx; + extH += size.cy; + } + + *w = extW; + *h = extH; } bool TextDrawerWin32::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) { diff --git a/Common/Render/Text/draw_text_win.h b/Common/Render/Text/draw_text_win.h index 24a84a5aef..6c29e002f4 100644 --- a/Common/Render/Text/draw_text_win.h +++ b/Common/Render/Text/draw_text_win.h @@ -21,10 +21,10 @@ public: uint32_t SetFont(const char *fontName, int size, int flags) override; void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once. - void MeasureString(std::string_view str, float *w, float *h) 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; bool SupportsColorEmoji() const override { return false; } void ClearFonts() override;