From 0f94482d36f81b429887eb70278013cfc559fd61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 24 May 2024 12:21:08 +0200 Subject: [PATCH 1/5] More string_view in text drawing --- Common/UI/Context.cpp | 25 ++++++++++--------------- Common/UI/Context.h | 7 +++---- Common/UI/PopupScreens.cpp | 8 ++++---- Common/UI/View.cpp | 18 +++++++++--------- Common/UI/View.h | 2 +- 5 files changed, 27 insertions(+), 33 deletions(-) diff --git a/Common/UI/Context.cpp b/Common/UI/Context.cpp index a60325a61c..2c4accc268 100644 --- a/Common/UI/Context.cpp +++ b/Common/UI/Context.cpp @@ -206,35 +206,30 @@ void UIContext::SetFontStyle(const UI::FontStyle &fontStyle) { } } -void UIContext::MeasureText(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, float *x, float *y, int align) const { - _dbg_assert_(str != nullptr); - MeasureTextCount(style, scaleX, scaleY, str, (int)strlen(str), x, y, align); -} - -void UIContext::MeasureTextCount(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, int count, float *x, float *y, int align) const { - _dbg_assert_(str != nullptr); +void UIContext::MeasureText(const UI::FontStyle &style, float scaleX, float scaleY, std::string_view str, float *x, float *y, int align) const { + _dbg_assert_(str.data() != nullptr); if (!textDrawer_ || (align & FLAG_DYNAMIC_ASCII)) { float sizeFactor = (float)style.sizePts / 24.0f; Draw()->SetFontScale(scaleX * sizeFactor, scaleY * sizeFactor); - Draw()->MeasureTextCount(style.atlasFont, str, count, x, y); + Draw()->MeasureTextCount(style.atlasFont, str.data(), str.length(), x, y); } else { textDrawer_->SetFont(style.fontName.c_str(), style.sizePts, style.flags); textDrawer_->SetFontScale(scaleX, scaleY); - textDrawer_->MeasureString(str, count, x, y); + textDrawer_->MeasureString(str.data(), str.length(), x, y); textDrawer_->SetFont(fontStyle_->fontName.c_str(), fontStyle_->sizePts, fontStyle_->flags); } } -void UIContext::MeasureTextRect(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, int count, const Bounds &bounds, float *x, float *y, int align) const { - _dbg_assert_(str != nullptr); +void UIContext::MeasureTextRect(const UI::FontStyle &style, float scaleX, float scaleY, std::string_view str, const Bounds &bounds, float *x, float *y, int align) const { + _dbg_assert_(str.data() != nullptr); if (!textDrawer_ || (align & FLAG_DYNAMIC_ASCII)) { float sizeFactor = (float)style.sizePts / 24.0f; Draw()->SetFontScale(scaleX * sizeFactor, scaleY * sizeFactor); - Draw()->MeasureTextRect(style.atlasFont, str, count, bounds, x, y, align); + Draw()->MeasureTextRect(style.atlasFont, str.data(), str.length(), bounds, x, y, align); } else { textDrawer_->SetFont(style.fontName.c_str(), style.sizePts, style.flags); textDrawer_->SetFontScale(scaleX, scaleY); - textDrawer_->MeasureStringRect(str, count, bounds, x, y, align); + textDrawer_->MeasureStringRect(str.data(), str.length(), bounds, x, y, align); textDrawer_->SetFont(fontStyle_->fontName.c_str(), fontStyle_->sizePts, fontStyle_->flags); } } @@ -291,10 +286,10 @@ void UIContext::DrawTextRect(const char *str, const Bounds &bounds, uint32_t col static constexpr float MIN_TEXT_SCALE = 0.7f; -float UIContext::CalculateTextScale(const char *text, float availWidth, float availHeight) const { +float UIContext::CalculateTextScale(std::string_view str, float availWidth, float availHeight) const { float actualWidth, actualHeight; Bounds availBounds(0, 0, availWidth, availHeight); - MeasureTextRect(theme->uiFont, 1.0f, 1.0f, text, (int)strlen(text), availBounds, &actualWidth, &actualHeight, ALIGN_VCENTER); + MeasureTextRect(theme->uiFont, 1.0f, 1.0f, str, availBounds, &actualWidth, &actualHeight, ALIGN_VCENTER); if (actualWidth > availWidth) { return std::max(MIN_TEXT_SCALE, availWidth / actualWidth); } diff --git a/Common/UI/Context.h b/Common/UI/Context.h index b64fd1f1ad..e1f7e61aa7 100644 --- a/Common/UI/Context.h +++ b/Common/UI/Context.h @@ -82,9 +82,8 @@ public: void SetFontStyle(const UI::FontStyle &style); const UI::FontStyle &GetFontStyle() { return *fontStyle_; } void SetFontScale(float scaleX, float scaleY); - void MeasureTextCount(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, int count, float *x, float *y, int align = 0) const; - void MeasureText(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, float *x, float *y, int align = 0) const; - void MeasureTextRect(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, int count, const Bounds &bounds, float *x, float *y, int align = 0) const; + void MeasureText(const UI::FontStyle &style, float scaleX, float scaleY, std::string_view str, float *x, float *y, int align = 0) const; + void MeasureTextRect(const UI::FontStyle &style, float scaleX, float scaleY, std::string_view str, const Bounds &bounds, float *x, float *y, int align = 0) const; void DrawText(const char *str, float x, float y, uint32_t color, int align = 0); void DrawTextShadow(const char *str, float x, float y, uint32_t color, int align = 0); void DrawTextRect(const char *str, const Bounds &bounds, uint32_t color, int align = 0); @@ -92,7 +91,7 @@ public: // Will squeeze the text into the bounds if needed. void DrawTextRectSqueeze(const char *str, const Bounds &bounds, uint32_t color, int align = 0); - float CalculateTextScale(const char *text, float availWidth, float availHeight) const; + float CalculateTextScale(std::string_view str, float availWidth, float availHeight) const; void FillRect(const UI::Drawable &drawable, const Bounds &bounds); void DrawRectDropShadow(const Bounds &bounds, float radius, float alpha, uint32_t color = 0); diff --git a/Common/UI/PopupScreens.cpp b/Common/UI/PopupScreens.cpp index d3d8cf04f5..956b82de26 100644 --- a/Common/UI/PopupScreens.cpp +++ b/Common/UI/PopupScreens.cpp @@ -596,7 +596,7 @@ void AbstractChoiceWithValueDisplay::GetContentDimensionsBySpec(const UIContext Bounds availBounds(0, 0, availWidth, vert.size); float valueW, valueH; - dc.MeasureTextRect(dc.theme->uiFont, scale, scale, valueText.c_str(), (int)valueText.size(), availBounds, &valueW, &valueH, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); + dc.MeasureTextRect(dc.theme->uiFont, scale, scale, valueText, availBounds, &valueW, &valueH, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); valueW += paddingX; // Give the choice itself less space to grow in, so it shrinks if needed. @@ -641,7 +641,7 @@ void AbstractChoiceWithValueDisplay::Draw(UIContext &dc) { float w, h; Bounds availBounds(0, 0, availWidth, bounds_.h); - dc.MeasureTextRect(dc.theme->uiFont, scale, scale, valueText.c_str(), (int)valueText.size(), availBounds, &w, &h, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); + dc.MeasureTextRect(dc.theme->uiFont, scale, scale, valueText, availBounds, &w, &h, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT); textPadding_.right = w + paddingX; Choice::Draw(dc); @@ -662,10 +662,10 @@ void AbstractChoiceWithValueDisplay::Draw(UIContext &dc) { } } -float AbstractChoiceWithValueDisplay::CalculateValueScale(const UIContext &dc, const std::string &valueText, float availWidth) const { +float AbstractChoiceWithValueDisplay::CalculateValueScale(const UIContext &dc, std::string_view valueText, float availWidth) const { float actualWidth, actualHeight; Bounds availBounds(0, 0, availWidth, bounds_.h); - dc.MeasureTextRect(dc.theme->uiFont, 1.0f, 1.0f, valueText.c_str(), (int)valueText.size(), availBounds, &actualWidth, &actualHeight); + dc.MeasureTextRect(dc.theme->uiFont, 1.0f, 1.0f, valueText, availBounds, &actualWidth, &actualHeight); if (actualWidth > availWidth) { return std::max(0.8f, availWidth / actualWidth); } diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index 697a2b52ac..a824776bee 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -483,10 +483,10 @@ void Choice::GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, } if (horiz.type != EXACTLY && layoutParams_->width > 0.0f && availWidth > layoutParams_->width) availWidth = layoutParams_->width; - float scale = dc.CalculateTextScale(text_.c_str(), availWidth, bounds_.h); + float scale = dc.CalculateTextScale(text_, availWidth, bounds_.h); Bounds availBounds(0, 0, availWidth, vert.size); float textW = 0.0f, textH = 0.0f; - dc.MeasureTextRect(dc.theme->uiFont, scale, scale, text_.c_str(), (int)text_.size(), availBounds, &textW, &textH, FLAG_WRAP_TEXT); + dc.MeasureTextRect(dc.theme->uiFont, scale, scale, text_, availBounds, &textW, &textH, FLAG_WRAP_TEXT); totalH = std::max(totalH, textH); totalW += textW; } @@ -580,7 +580,7 @@ void InfoItem::Draw(UIContext &dc) { Bounds padBounds = bounds_.Expand(-paddingX, 0); float leftWidth, leftHeight; - dc.MeasureTextRect(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), (int)text_.size(), padBounds, &leftWidth, &leftHeight, ALIGN_VCENTER); + dc.MeasureTextRect(dc.theme->uiFont, 1.0f, 1.0f, text_, padBounds, &leftWidth, &leftHeight, ALIGN_VCENTER); dc.SetFontStyle(dc.theme->uiFont); dc.DrawTextRect(text_.c_str(), padBounds, style.fgColor, ALIGN_VCENTER); @@ -616,7 +616,7 @@ void ItemHeader::GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec hor bounds.h = vert.size == 0 ? MAX_ITEM_SIZE : vert.size; } ApplyBoundsBySpec(bounds, horiz, vert); - dc.MeasureTextRect(dc.theme->uiFontSmall, 1.0f, 1.0f, text_.c_str(), (int)text_.length(), bounds, &w, &h, ALIGN_LEFT | ALIGN_VCENTER); + dc.MeasureTextRect(dc.theme->uiFontSmall, 1.0f, 1.0f, text_, bounds, &w, &h, ALIGN_LEFT | ALIGN_VCENTER); } std::string ItemHeader::DescribeText() const { @@ -658,7 +658,7 @@ void CollapsibleHeader::GetContentDimensionsBySpec(const UIContext &dc, MeasureS bounds.h = vert.size == 0 ? MAX_ITEM_SIZE : vert.size; } ApplyBoundsBySpec(bounds, horiz, vert); - dc.MeasureTextRect(dc.theme->uiFontSmall, 1.0f, 1.0f, text_.c_str(), (int)text_.length(), bounds, &w, &h, ALIGN_LEFT | ALIGN_VCENTER); + dc.MeasureTextRect(dc.theme->uiFontSmall, 1.0f, 1.0f, text_, bounds, &w, &h, ALIGN_LEFT | ALIGN_VCENTER); } void CollapsibleHeader::GetContentDimensions(const UIContext &dc, float &w, float &h) const { @@ -840,11 +840,11 @@ void CheckBox::GetContentDimensions(const UIContext &dc, float &w, float &h) con } if (!text_.empty()) { - float scale = dc.CalculateTextScale(text_.c_str(), availWidth, bounds_.h); + float scale = dc.CalculateTextScale(text_, availWidth, bounds_.h); float actualWidth, actualHeight; Bounds availBounds(0, 0, availWidth, bounds_.h); - dc.MeasureTextRect(dc.theme->uiFont, scale, scale, text_.c_str(), (int)text_.size(), availBounds, &actualWidth, &actualHeight, ALIGN_VCENTER | FLAG_WRAP_TEXT); + dc.MeasureTextRect(dc.theme->uiFont, scale, scale, text_, availBounds, &actualWidth, &actualHeight, ALIGN_VCENTER | FLAG_WRAP_TEXT); h = std::max(actualHeight, ITEM_HEIGHT); } else { h = std::max(imageH, ITEM_HEIGHT); @@ -1043,7 +1043,7 @@ void TextView::GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz if (bullet_) { bounds.w -= bulletOffset; } - dc.MeasureTextRect(small_ ? dc.theme->uiFontSmall : dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), (int)text_.length(), bounds, &w, &h, textAlign_); + dc.MeasureTextRect(small_ ? dc.theme->uiFontSmall : dc.theme->uiFont, 1.0f, 1.0f, text_, bounds, &w, &h, textAlign_); w += pad_ * 2.0f; h += pad_ * 2.0f; if (bullet_) { @@ -1141,7 +1141,7 @@ void TextEdit::Draw(UIContext &dc) { if (HasFocus()) { // Hack to find the caret position. Might want to find a better way... - dc.MeasureTextCount(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), caret_, &w, &h, ALIGN_VCENTER | ALIGN_LEFT | align_); + dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.substr(0, caret_), &w, &h, ALIGN_VCENTER | ALIGN_LEFT | align_); float caretX = w - scrollPos_; if (caretX > bounds_.w) { scrollPos_ += caretX - bounds_.w; diff --git a/Common/UI/View.h b/Common/UI/View.h index 42af14edab..97923f2819 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -826,7 +826,7 @@ public: protected: virtual std::string ValueText() const = 0; - float CalculateValueScale(const UIContext &dc, const std::string &valueText, float availWidth) const; + float CalculateValueScale(const UIContext &dc, std::string_view valueText, float availWidth) const; bool passwordDisplay_ = false; }; From d39d4270e11aed484f9ad6191342fc9ad9863c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 24 May 2024 12:29:10 +0200 Subject: [PATCH 2/5] More std::string_view --- Common/Render/DrawBuffer.cpp | 25 +++++++++++-------------- Common/Render/DrawBuffer.h | 8 +++----- Common/UI/Context.cpp | 4 ++-- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/Common/Render/DrawBuffer.cpp b/Common/Render/DrawBuffer.cpp index 8e29732394..31f5232624 100644 --- a/Common/Render/DrawBuffer.cpp +++ b/Common/Render/DrawBuffer.cpp @@ -473,7 +473,7 @@ float AtlasWordWrapper::MeasureWidth(const char *str, size_t bytes) { return w; } -void DrawBuffer::MeasureTextCount(FontID font, const char *text, int count, float *w, float *h) { +void DrawBuffer::MeasureText(FontID font, std::string_view text, float *w, float *h) { const AtlasFont *atlasfont = fontAtlas_->getFont(font); if (!atlasfont) atlasfont = atlas->getFont(font); @@ -491,7 +491,7 @@ void DrawBuffer::MeasureTextCount(FontID font, const char *text, int count, floa while (true) { if (utf.end()) break; - if (utf.byteIndex() >= count) + if (utf.byteIndex() >= text.length()) break; cval = utf.next(); // Translate non-breaking space to space. @@ -517,14 +517,14 @@ void DrawBuffer::MeasureTextCount(FontID font, const char *text, int count, floa if (h) *h = atlasfont->height * fontscaley * lines; } -void DrawBuffer::MeasureTextRect(FontID font_id, const char *text, int count, const Bounds &bounds, float *w, float *h, int align) { - if (!text || font_id.isInvalid()) { +void DrawBuffer::MeasureTextRect(FontID font_id, std::string_view text, const Bounds &bounds, float *w, float *h, int align) { + if (text.empty() || font_id.isInvalid()) { *w = 0.0f; *h = 0.0f; return; } - std::string toMeasure = std::string(text, count); + std::string toMeasure = std::string(text); int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); if (wrap) { const AtlasFont *font = fontAtlas_->getFont(font_id); @@ -538,11 +538,7 @@ void DrawBuffer::MeasureTextRect(FontID font_id, const char *text, int count, co AtlasWordWrapper wrapper(*font, fontscalex, toMeasure.c_str(), bounds.w, wrap); toMeasure = wrapper.Wrapped(); } - MeasureTextCount(font_id, toMeasure.c_str(), (int)toMeasure.length(), w, h); -} - -void DrawBuffer::MeasureText(FontID font, const char *text, float *w, float *h) { - return MeasureTextCount(font, text, (int)strlen(text), w, h); + MeasureText(font_id, toMeasure, w, h); } void DrawBuffer::DrawTextShadow(FontID font, const char *text, float x, float y, Color color, int flags) { @@ -587,7 +583,7 @@ void DrawBuffer::DrawTextRect(FontID font, const char *text, float x, float y, f } float totalWidth, totalHeight; - MeasureTextRect(font, toDraw.c_str(), (int)toDraw.size(), Bounds(x, y, w, h), &totalWidth, &totalHeight, align); + MeasureTextRect(font, toDraw, Bounds(x, y, w, h), &totalWidth, &totalHeight, align); std::vector lines; SplitString(toDraw, '\n', lines); @@ -606,21 +602,22 @@ void DrawBuffer::DrawTextRect(FontID font, const char *text, float x, float y, f DrawText(font, line.c_str(), x, baseY, color, align); float tw, th; - MeasureText(font, line.c_str(), &tw, &th); + MeasureText(font, line, &tw, &th); baseY += th; } } // ROTATE_* doesn't yet work right. -void DrawBuffer::DrawText(FontID font, const char *text, float x, float y, Color color, int align) { +void DrawBuffer::DrawText(FontID font, std::string_view text, float x, float y, Color color, int align) { // rough estimate - size_t textLen = strlen(text); + int textLen = text.length(); if (count_ + textLen * 6 > MAX_VERTS) { Flush(true); if (textLen * 6 >= MAX_VERTS) { textLen = std::min(MAX_VERTS / 6 - 10, (int)textLen); } } + text = text.substr(0, textLen); const AtlasFont *atlasfont = fontAtlas_->getFont(font); if (!atlasfont) diff --git a/Common/Render/DrawBuffer.h b/Common/Render/DrawBuffer.h index c8ac2815f4..52458818fd 100644 --- a/Common/Render/DrawBuffer.h +++ b/Common/Render/DrawBuffer.h @@ -131,14 +131,12 @@ public: // This is only 6 triangles, much cheaper. void DrawImage2GridH(ImageID atlas_image, float x1, float y1, float x2, Color color = COLOR(0xFFFFFF), float scale = 1.0); - void MeasureText(FontID font, const char *text, float *w, float *h); + void MeasureText(FontID font, std::string_view text, float *w, float *h); - // NOTE: Count is in plain chars not utf-8 chars! - void MeasureTextCount(FontID font, const char *text, int count, float *w, float *h); - void MeasureTextRect(FontID font, const char *text, int count, const Bounds &bounds, float *w, float *h, int align = 0); + void MeasureTextRect(FontID font, std::string_view text, const Bounds &bounds, float *w, float *h, int align = 0); void DrawTextRect(FontID font, const char *text, float x, float y, float w, float h, Color color = 0xFFFFFFFF, int align = 0); - void DrawText(FontID font, const char *text, float x, float y, Color color = 0xFFFFFFFF, int align = 0); + void DrawText(FontID font, std::string_view text, float x, float y, Color color = 0xFFFFFFFF, int align = 0); void DrawTextShadow(FontID font, const char *text, float x, float y, Color color = 0xFFFFFFFF, int align = 0); void SetFontScale(float xs, float ys) { diff --git a/Common/UI/Context.cpp b/Common/UI/Context.cpp index 2c4accc268..33c4ef2692 100644 --- a/Common/UI/Context.cpp +++ b/Common/UI/Context.cpp @@ -211,7 +211,7 @@ void UIContext::MeasureText(const UI::FontStyle &style, float scaleX, float scal if (!textDrawer_ || (align & FLAG_DYNAMIC_ASCII)) { float sizeFactor = (float)style.sizePts / 24.0f; Draw()->SetFontScale(scaleX * sizeFactor, scaleY * sizeFactor); - Draw()->MeasureTextCount(style.atlasFont, str.data(), str.length(), x, y); + Draw()->MeasureText(style.atlasFont, str, x, y); } else { textDrawer_->SetFont(style.fontName.c_str(), style.sizePts, style.flags); textDrawer_->SetFontScale(scaleX, scaleY); @@ -225,7 +225,7 @@ void UIContext::MeasureTextRect(const UI::FontStyle &style, float scaleX, float if (!textDrawer_ || (align & FLAG_DYNAMIC_ASCII)) { float sizeFactor = (float)style.sizePts / 24.0f; Draw()->SetFontScale(scaleX * sizeFactor, scaleY * sizeFactor); - Draw()->MeasureTextRect(style.atlasFont, str.data(), str.length(), bounds, x, y, align); + Draw()->MeasureTextRect(style.atlasFont, str, bounds, x, y, align); } else { textDrawer_->SetFont(style.fontName.c_str(), style.sizePts, style.flags); textDrawer_->SetFontScale(scaleX, scaleY); From f6ca8101e05e5eb591c988743a18afea6ceaa1a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 24 May 2024 12:39:20 +0200 Subject: [PATCH 3/5] Start getting string_view into WordWrapper --- Common/Data/Text/WrapText.cpp | 8 ++++---- Common/Data/Text/WrapText.h | 3 ++- Common/Render/DrawBuffer.cpp | 6 +++--- Common/Render/Text/draw_text.cpp | 4 ++-- Common/Render/Text/draw_text.h | 2 +- unittest/UnitTest.cpp | 4 ++-- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Common/Data/Text/WrapText.cpp b/Common/Data/Text/WrapText.cpp index 3f9474e8ca..4da742f5be 100644 --- a/Common/Data/Text/WrapText.cpp +++ b/Common/Data/Text/WrapText.cpp @@ -167,7 +167,7 @@ void WordWrapper::AppendWord(int endIndex, int lastChar, bool addNewline) { if (lastLineStart_ != out_.size()) { // To account for kerning around spaces, we recalculate the entire line width. - x_ = MeasureWidth(out_.c_str() + lastLineStart_, out_.size() - lastLineStart_); + x_ = MeasureWidth(std::string_view(out_.c_str() + lastLineStart_, out_.size() - lastLineStart_)); } else { x_ = 0.0f; } @@ -179,7 +179,7 @@ void WordWrapper::AppendWord(int endIndex, int lastChar, bool addNewline) { void WordWrapper::Wrap() { // First, let's check if it fits as-is. size_t len = strlen(str_); - if (MeasureWidth(str_, len) <= maxW_) { + if (MeasureWidth(std::string_view(str_, len)) <= maxW_) { // If it fits, we don't need to go through each character. out_ = str_; return; @@ -190,7 +190,7 @@ void WordWrapper::Wrap() { out_.reserve(len + len / 16); if (flags_ & FLAG_ELLIPSIZE_TEXT) { - ellipsisWidth_ = MeasureWidth("...", 3); + ellipsisWidth_ = MeasureWidth("..."); } for (UTF8 utf(str_); !utf.end(); ) { @@ -219,7 +219,7 @@ void WordWrapper::Wrap() { } // Measure the entire word for kerning purposes. May not be 100% perfect. - float newWordWidth = MeasureWidth(str_ + lastIndex_, afterIndex - lastIndex_); + float newWordWidth = MeasureWidth(std::string_view(str_ + lastIndex_, afterIndex - lastIndex_)); // Is this the end of a word (space)? We'll also output up to a soft hyphen. if (wordWidth_ > 0.0f && IsSpaceOrShy(c)) { diff --git a/Common/Data/Text/WrapText.h b/Common/Data/Text/WrapText.h index d51f860362..98ec8d3159 100644 --- a/Common/Data/Text/WrapText.h +++ b/Common/Data/Text/WrapText.h @@ -1,6 +1,7 @@ #pragma once #include +#include class WordWrapper { public: @@ -12,7 +13,7 @@ public: std::string Wrapped(); protected: - virtual float MeasureWidth(const char *str, size_t bytes) = 0; + virtual float MeasureWidth(std::string_view str) = 0; void Wrap(); bool WrapBeforeWord(); void AppendWord(int endIndex, int lastChar, bool addNewline); diff --git a/Common/Render/DrawBuffer.cpp b/Common/Render/DrawBuffer.cpp index 31f5232624..0c3ec5fc40 100644 --- a/Common/Render/DrawBuffer.cpp +++ b/Common/Render/DrawBuffer.cpp @@ -450,15 +450,15 @@ public: } protected: - float MeasureWidth(const char *str, size_t bytes) override; + float MeasureWidth(std::string_view str) override; const AtlasFont &atlasfont_; const float scale_; }; -float AtlasWordWrapper::MeasureWidth(const char *str, size_t bytes) { +float AtlasWordWrapper::MeasureWidth(std::string_view str) { float w = 0.0f; - for (UTF8 utf(str); utf.byteIndex() < (int)bytes; ) { + for (UTF8 utf(str); !utf.end(); ) { uint32_t c = utf.next(); if (c == '&') { // Skip ampersand prefixes ("&&" is an ampersand.) diff --git a/Common/Render/Text/draw_text.cpp b/Common/Render/Text/draw_text.cpp index cb09dbda98..44fb0f2493 100644 --- a/Common/Render/Text/draw_text.cpp +++ b/Common/Render/Text/draw_text.cpp @@ -20,9 +20,9 @@ TextDrawer::TextDrawer(Draw::DrawContext *draw) : draw_(draw) { TextDrawer::~TextDrawer() { } -float TextDrawerWordWrapper::MeasureWidth(const char *str, size_t bytes) { +float TextDrawerWordWrapper::MeasureWidth(std::string_view str) { float w, h; - drawer_->MeasureString(str, bytes, &w, &h); + drawer_->MeasureString(str.data(), str.length(), &w, &h); return w; } diff --git a/Common/Render/Text/draw_text.h b/Common/Render/Text/draw_text.h index 252029b8a3..949fc2a3e8 100644 --- a/Common/Render/Text/draw_text.h +++ b/Common/Render/Text/draw_text.h @@ -94,7 +94,7 @@ public: : WordWrapper(str, maxW, flags), drawer_(drawer) {} protected: - float MeasureWidth(const char *str, size_t bytes) override; + float MeasureWidth(std::string_view str) override; TextDrawer *drawer_; }; diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp index 0fa08b8ed8..c3cc9eb276 100644 --- a/unittest/UnitTest.cpp +++ b/unittest/UnitTest.cpp @@ -793,10 +793,10 @@ public: } protected: - float MeasureWidth(const char *str, size_t bytes) override { + float MeasureWidth(std::string_view str) override { // Simple case for unit testing. int w = 0; - for (UTF8 utf(str); !utf.end() && (size_t)utf.byteIndex() < bytes; ) { + for (UTF8 utf(str); !utf.end(); ) { uint32_t c = utf.next(); switch (c) { case ' ': From 4b45bde38fe2e9e4d0a4ac614a3bcbc8e8359778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 24 May 2024 12:43:38 +0200 Subject: [PATCH 4/5] Convert WordWrapper to use std::string_view --- Common/Data/Text/WrapText.cpp | 10 +++++----- Common/Data/Text/WrapText.h | 4 ++-- Common/Render/DrawBuffer.cpp | 9 +++++---- Common/Render/Text/draw_text.cpp | 2 +- Common/Render/Text/draw_text.h | 4 ++-- unittest/UnitTest.cpp | 2 +- 6 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Common/Data/Text/WrapText.cpp b/Common/Data/Text/WrapText.cpp index 4da742f5be..68335db1a9 100644 --- a/Common/Data/Text/WrapText.cpp +++ b/Common/Data/Text/WrapText.cpp @@ -141,7 +141,7 @@ void WordWrapper::AppendWord(int endIndex, int lastChar, bool addNewline) { // This will include the newline. if (x_ <= maxW_) { - out_.append(str_ + lastWordStartIndex, str_ + endIndex); + out_.append(str_.data() + lastWordStartIndex, str_.data() + endIndex); } else { scanForNewline_ = true; } @@ -178,10 +178,10 @@ void WordWrapper::AppendWord(int endIndex, int lastChar, bool addNewline) { void WordWrapper::Wrap() { // First, let's check if it fits as-is. - size_t len = strlen(str_); - if (MeasureWidth(std::string_view(str_, len)) <= maxW_) { + size_t len = str_.length(); + if (MeasureWidth(str_) <= maxW_) { // If it fits, we don't need to go through each character. - out_ = str_; + out_ = std::string(str_); return; } @@ -219,7 +219,7 @@ void WordWrapper::Wrap() { } // Measure the entire word for kerning purposes. May not be 100% perfect. - float newWordWidth = MeasureWidth(std::string_view(str_ + lastIndex_, afterIndex - lastIndex_)); + float newWordWidth = MeasureWidth(str_.substr(lastIndex_, afterIndex - lastIndex_)); // Is this the end of a word (space)? We'll also output up to a soft hyphen. if (wordWidth_ > 0.0f && IsSpaceOrShy(c)) { diff --git a/Common/Data/Text/WrapText.h b/Common/Data/Text/WrapText.h index 98ec8d3159..e08e064665 100644 --- a/Common/Data/Text/WrapText.h +++ b/Common/Data/Text/WrapText.h @@ -5,7 +5,7 @@ class WordWrapper { public: - WordWrapper(const char *str, float maxW, int flags) + WordWrapper(std::string_view str, float maxW, int flags) : str_(str), maxW_(maxW), flags_(flags) { } virtual ~WordWrapper() {} @@ -27,7 +27,7 @@ protected: return IsSpace(c) || IsShy(c); } - const char *const str_; + const std::string_view str_; const float maxW_; const int flags_; std::string out_; diff --git a/Common/Render/DrawBuffer.cpp b/Common/Render/DrawBuffer.cpp index 0c3ec5fc40..d2920a7035 100644 --- a/Common/Render/DrawBuffer.cpp +++ b/Common/Render/DrawBuffer.cpp @@ -446,7 +446,8 @@ void DrawBuffer::DrawImage2GridH(ImageID atlas_image, float x1, float y1, float class AtlasWordWrapper : public WordWrapper { public: // Note: maxW may be height if rotated. - AtlasWordWrapper(const AtlasFont &atlasfont, float scale, const char *str, float maxW, int flags) : WordWrapper(str, maxW, flags), atlasfont_(atlasfont), scale_(scale) { + AtlasWordWrapper(const AtlasFont &atlasfont, float scale, std::string_view str, float maxW, int flags) + : WordWrapper(str, maxW, flags), atlasfont_(atlasfont), scale_(scale) { } protected: @@ -535,7 +536,7 @@ void DrawBuffer::MeasureTextRect(FontID font_id, std::string_view text, const Bo *h = 0.0f; return; } - AtlasWordWrapper wrapper(*font, fontscalex, toMeasure.c_str(), bounds.w, wrap); + AtlasWordWrapper wrapper(*font, fontscalex, toMeasure, bounds.w, wrap); toMeasure = wrapper.Wrapped(); } MeasureText(font_id, toMeasure, w, h); @@ -578,7 +579,7 @@ void DrawBuffer::DrawTextRect(FontID font, const char *text, float x, float y, f if (!atlasfont) atlasfont = atlas->getFont(font); if (wrap && atlasfont) { - AtlasWordWrapper wrapper(*atlasfont, fontscalex, toDraw.c_str(), w, wrap); + AtlasWordWrapper wrapper(*atlasfont, fontscalex, toDraw, w, wrap); toDraw = wrapper.Wrapped(); } @@ -610,7 +611,7 @@ void DrawBuffer::DrawTextRect(FontID font, const char *text, float x, float y, f // ROTATE_* doesn't yet work right. void DrawBuffer::DrawText(FontID font, std::string_view text, float x, float y, Color color, int align) { // rough estimate - int textLen = text.length(); + int textLen = (int)text.length(); if (count_ + textLen * 6 > MAX_VERTS) { Flush(true); if (textLen * 6 >= MAX_VERTS) { diff --git a/Common/Render/Text/draw_text.cpp b/Common/Render/Text/draw_text.cpp index 44fb0f2493..ee618ba969 100644 --- a/Common/Render/Text/draw_text.cpp +++ b/Common/Render/Text/draw_text.cpp @@ -26,7 +26,7 @@ float TextDrawerWordWrapper::MeasureWidth(std::string_view str) { return w; } -void TextDrawer::WrapString(std::string &out, const char *str, float maxW, int flags) { +void TextDrawer::WrapString(std::string &out, std::string_view str, float maxW, int flags) { TextDrawerWordWrapper wrapper(this, str, maxW, flags); out = wrapper.Wrapped(); } diff --git a/Common/Render/Text/draw_text.h b/Common/Render/Text/draw_text.h index 949fc2a3e8..3558733848 100644 --- a/Common/Render/Text/draw_text.h +++ b/Common/Render/Text/draw_text.h @@ -67,7 +67,7 @@ protected: Draw::DrawContext *draw_; virtual void ClearCache() = 0; - void WrapString(std::string &out, const char *str, float maxWidth, int flags); + void WrapString(std::string &out, std::string_view str, float maxWidth, int flags); struct CacheKey { bool operator < (const CacheKey &other) const { @@ -90,7 +90,7 @@ protected: class TextDrawerWordWrapper : public WordWrapper { public: - TextDrawerWordWrapper(TextDrawer *drawer, const char *str, float maxW, int flags) + TextDrawerWordWrapper(TextDrawer *drawer, std::string_view str, float maxW, int flags) : WordWrapper(str, maxW, flags), drawer_(drawer) {} protected: diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp index c3cc9eb276..e482b6f0e2 100644 --- a/unittest/UnitTest.cpp +++ b/unittest/UnitTest.cpp @@ -788,7 +788,7 @@ static bool TestAndroidContentURI() { class UnitTestWordWrapper : public WordWrapper { public: - UnitTestWordWrapper(const char *str, float maxW, int flags) + UnitTestWordWrapper(std::string_view str, float maxW, int flags) : WordWrapper(str, maxW, flags) { } From 8112e51c1308c67f6ad4235d066d8930e8dcb05f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 24 May 2024 13:42:49 +0200 Subject: [PATCH 5/5] More string_view --- Common/Data/Text/WrapText.h | 2 ++ Common/Render/DrawBuffer.cpp | 7 +++---- Common/Render/DrawBuffer.h | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Common/Data/Text/WrapText.h b/Common/Data/Text/WrapText.h index e08e064665..1392307aca 100644 --- a/Common/Data/Text/WrapText.h +++ b/Common/Data/Text/WrapText.h @@ -10,10 +10,12 @@ public: } virtual ~WordWrapper() {} + // TODO: This should return a vector of std::string_view for the lines, instead of building up a new string. std::string Wrapped(); protected: virtual float MeasureWidth(std::string_view str) = 0; + void Wrap(); bool WrapBeforeWord(); void AppendWord(int endIndex, int lastChar, bool addNewline); diff --git a/Common/Render/DrawBuffer.cpp b/Common/Render/DrawBuffer.cpp index d2920a7035..bf646db680 100644 --- a/Common/Render/DrawBuffer.cpp +++ b/Common/Render/DrawBuffer.cpp @@ -542,7 +542,7 @@ void DrawBuffer::MeasureTextRect(FontID font_id, std::string_view text, const Bo MeasureText(font_id, toMeasure, w, h); } -void DrawBuffer::DrawTextShadow(FontID font, const char *text, float x, float y, Color color, int flags) { +void DrawBuffer::DrawTextShadow(FontID font, std::string_view text, float x, float y, Color color, int flags) { uint32_t alpha = (color >> 1) & 0xFF000000; DrawText(font, text, x + 2, y + 2, alpha, flags); DrawText(font, text, x, y, color, flags); @@ -559,9 +559,8 @@ void DrawBuffer::DoAlign(int flags, float *x, float *y, float *w, float *h) { } } - // TODO: Actually use the rect properly, take bounds. -void DrawBuffer::DrawTextRect(FontID font, const char *text, float x, float y, float w, float h, Color color, int align) { +void DrawBuffer::DrawTextRect(FontID font, std::string_view text, float x, float y, float w, float h, Color color, int align) { if (align & ALIGN_HCENTER) { x += w / 2; } else if (align & ALIGN_RIGHT) { @@ -573,7 +572,7 @@ void DrawBuffer::DrawTextRect(FontID font, const char *text, float x, float y, f y += h; } - std::string toDraw = text; + std::string toDraw(text); int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); const AtlasFont *atlasfont = fontAtlas_->getFont(font); if (!atlasfont) diff --git a/Common/Render/DrawBuffer.h b/Common/Render/DrawBuffer.h index 52458818fd..58dea63698 100644 --- a/Common/Render/DrawBuffer.h +++ b/Common/Render/DrawBuffer.h @@ -135,9 +135,9 @@ public: void MeasureTextRect(FontID font, std::string_view text, const Bounds &bounds, float *w, float *h, int align = 0); - void DrawTextRect(FontID font, const char *text, float x, float y, float w, float h, Color color = 0xFFFFFFFF, int align = 0); + void DrawTextRect(FontID font, std::string_view text, float x, float y, float w, float h, Color color = 0xFFFFFFFF, int align = 0); void DrawText(FontID font, std::string_view text, float x, float y, Color color = 0xFFFFFFFF, int align = 0); - void DrawTextShadow(FontID font, const char *text, float x, float y, Color color = 0xFFFFFFFF, int align = 0); + void DrawTextShadow(FontID font, std::string_view text, float x, float y, Color color = 0xFFFFFFFF, int align = 0); void SetFontScale(float xs, float ys) { fontscalex = xs;