Merge pull request #19178 from hrydgard/text-draw-refactor

Text draw refactor part #1
This commit is contained in:
Henrik Rydgård 2024-05-24 13:56:47 +02:00 committed by GitHub
commit a04ad1c7f7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 75 additions and 83 deletions

View file

@ -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;
}
@ -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;
}
@ -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(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;
}
@ -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(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)) {

View file

@ -1,18 +1,21 @@
#pragma once
#include <string>
#include <string_view>
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() {}
// 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(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);
@ -26,7 +29,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_;

View file

@ -446,19 +446,20 @@ 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:
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.)
@ -473,7 +474,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 +492,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 +518,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);
@ -535,17 +536,13 @@ void DrawBuffer::MeasureTextRect(FontID font_id, const char *text, int count, co
*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();
}
MeasureTextCount(font_id, toMeasure.c_str(), (int)toMeasure.length(), w, h);
MeasureText(font_id, toMeasure, w, h);
}
void DrawBuffer::MeasureText(FontID font, const char *text, float *w, float *h) {
return MeasureTextCount(font, text, (int)strlen(text), 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);
@ -562,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) {
@ -576,18 +572,18 @@ 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)
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();
}
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<std::string> 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 = (int)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)

View file

@ -131,15 +131,13 @@ 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 DrawTextShadow(FontID font, const char *text, float x, float y, 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, std::string_view text, float x, float y, Color color = 0xFFFFFFFF, int align = 0);
void SetFontScale(float xs, float ys) {
fontscalex = xs;

View file

@ -20,13 +20,13 @@ 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;
}
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();
}

View file

@ -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,11 +90,11 @@ 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:
float MeasureWidth(const char *str, size_t bytes) override;
float MeasureWidth(std::string_view str) override;
TextDrawer *drawer_;
};

View file

@ -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()->MeasureText(style.atlasFont, str, 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, 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);
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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;

View file

@ -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;
};

View file

@ -788,15 +788,15 @@ 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) {
}
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 ' ':