TextDrawer: Remove the current font and scale

Drawing now takes the style and scale too, like measuring, so the text
drawers have no font state left. UIContext keeps its current style and
passes it, and fills it in from the theme if nothing has set one yet.
PPGe passes its one font.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-27 11:54:10 +01:00
1 parent dc1e9e50fc
commit 4c7dd44351
16 files changed
+64 -108

No files matched your search

+13 -22
View File
@@ -90,23 +90,13 @@ const std::string &TextDrawer::WrapString(const FontStyle &style, float scale, s
return entry.wrapped;
}
void TextDrawer::SetOrCreateFont(const FontStyle &style) {
EnsureFont(style);
fontStyle_ = style;
}
void TextDrawer::SetFontScale(float xscale, float yscale) {
fontScaleX_ = xscale;
fontScaleY_ = yscale;
}
float TextDrawer::CalculateDPIScale() const {
if (ignoreGlobalDpi_)
return dpiScale_;
return g_display.dpi_scale_y;
}
void TextDrawer::DrawString(DrawBuffer &target, std::string_view str, float x, float y, uint32_t color, int align) {
void TextDrawer::DrawString(DrawBuffer &target, const FontStyle &style, float scaleX, float scaleY, std::string_view str, float x, float y, uint32_t color, int align) {
using namespace Draw;
if (str.empty()) {
return;
@@ -117,7 +107,7 @@ void TextDrawer::DrawString(DrawBuffer &target, std::string_view str, float x, f
TextStringEntry *entry;
auto [iter, inserted] = cache_.try_emplace(LookupKey(fontStyle_, str, align & FLAG_DROP_SHADOW));
auto [iter, inserted] = cache_.try_emplace(LookupKey(style, str, align & FLAG_DROP_SHADOW));
if (!inserted) {
entry = iter->second.get();
entry->lastUsedFrame = frameCount_;
@@ -152,7 +142,8 @@ void TextDrawer::DrawString(DrawBuffer &target, std::string_view str, float x, f
// because we need white. Well, we could using swizzle, but not all our backends support that.
TextureDesc desc{};
std::vector<uint8_t> bitmapData;
if (!DrawStringBitmap(bitmapData, *entry, bitmapFormat, str, align, emoji)) {
EnsureFont(style);
if (!DrawStringBitmap(style, bitmapData, *entry, bitmapFormat, str, align, emoji)) {
// Nothing drawn. The entry without a texture records that fact.
return;
}
@@ -178,15 +169,15 @@ void TextDrawer::DrawString(DrawBuffer &target, std::string_view str, float x, f
draw_->BindTexture(0, entry->texture);
// Okay, the texture is bound, let's draw.
float w = (float)entry->width * (fontScaleX_ * dpiScale_);
float h = (float)entry->height * (fontScaleY_ * dpiScale_);
float w = (float)entry->width * (scaleX * dpiScale_);
float h = (float)entry->height * (scaleY * dpiScale_);
float u = (float)(entry->width + entry->shadowPad * 2) / (float)entry->bmWidth;
float v = (float)(entry->height + entry->shadowPad * 2) / (float)entry->bmHeight;
DrawBuffer::DoAlign(align, &x, &y, &w, &h);
// Align by the text, then grow the quad to include the shadow padding.
const float padX = entry->shadowPad * (fontScaleX_ * dpiScale_);
const float padY = entry->shadowPad * (fontScaleY_ * dpiScale_);
const float padX = entry->shadowPad * (scaleX * dpiScale_);
const float padY = entry->shadowPad * (scaleY * dpiScale_);
target.DrawTexRect(x - padX, y - padY, x + w + padX, y + h + padY, 0.0f, 0.0f, u, v, color);
target.Flush(true);
}
@@ -239,7 +230,7 @@ void TextDrawer::MeasureStringRect(const FontStyle &style, float scaleX, float s
}
}
void TextDrawer::DrawStringRect(DrawBuffer &target, std::string_view str, const Bounds &bounds, uint32_t color, int align) {
void TextDrawer::DrawStringRect(DrawBuffer &target, const FontStyle &style, float scaleX, float scaleY, std::string_view str, const Bounds &bounds, uint32_t color, int align) {
if (bounds.w < 0.0f || bounds.h < 0.0f) {
return;
}
@@ -262,17 +253,18 @@ 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(fontStyle_, fontScaleX_, str, bounds.w, wrap)) : str, x, y, color, align);
DrawString(target, style, scaleX, scaleY, wrap ? std::string_view(WrapString(style, scaleX, str, bounds.w, wrap)) : str, x, y, color, align);
}
bool TextDrawer::DrawStringBitmapRect(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, const Bounds &bounds, int align, bool fullColor) {
bool TextDrawer::DrawStringBitmapRect(const FontStyle &style, float scale, std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, const Bounds &bounds, int align, bool fullColor) {
// Clamp the size to something sane.
if (str.size() > MAX_TEXT_LENGTH) {
str = str.substr(0, MAX_TEXT_LENGTH);
}
const int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT);
return DrawStringBitmap(bitmapData, entry, texFormat, wrap ? std::string_view(WrapString(fontStyle_, fontScaleX_, str, bounds.w, wrap)) : str, align, fullColor);
EnsureFont(style);
return DrawStringBitmap(style, bitmapData, entry, texFormat, wrap ? std::string_view(WrapString(style, scale, str, bounds.w, wrap)) : str, align, fullColor);
}
void TextDrawer::AddDropShadow(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat srcFormat) const {
@@ -311,7 +303,6 @@ void TextDrawer::ClearCache() {
cache_.clear();
sizeCache_.clear();
wrapCache_.clear();
fontStyle_ = {};
}
void TextDrawer::OncePerFrame() {
+7 -20
View File
@@ -71,25 +71,14 @@ public:
virtual ~TextDrawer() = default;
virtual bool IsReady() const { return true; }
// Sets the font and scale that drawing uses.
void SetOrCreateFont(const FontStyle &style);
void SetFontScale(float xscale, float yscale);
// Measuring doesn't depend on the current font and scale.
// The font and scale are passed to each call. The fonts are created as they're first used.
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);
virtual bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) = 0;
bool DrawStringBitmapRect(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, const Bounds &bounds, int align, bool fullColor);
void DrawString(DrawBuffer &target, const FontStyle &style, float scaleX, float scaleY, std::string_view str, float x, float y, uint32_t color, int align = ALIGN_TOPLEFT);
void DrawStringRect(DrawBuffer &target, const FontStyle &style, float scaleX, float scaleY, std::string_view str, const Bounds &bounds, uint32_t color, int align);
// Rasterizes at scale 1, wrapping to bounds as if drawn at scale.
bool DrawStringBitmapRect(const FontStyle &style, float scale, std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, const Bounds &bounds, int align, bool fullColor);
// Use for housekeeping like throwing out old strings.
void OncePerFrame();
@@ -113,8 +102,9 @@ protected:
// 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.
// Implementations of these 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;
virtual bool DrawStringBitmap(const FontStyle &style, std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) = 0;
void ClearCache();
@@ -154,11 +144,8 @@ protected:
Draw::DrawContext *draw_;
int frameCount_ = 0;
float fontScaleX_ = 1.0f;
float fontScaleY_ = 1.0f;
float dpiScale_ = 1.0f;
bool ignoreGlobalDpi_ = false;
FontStyle fontStyle_{};
// We will clamp strings to this length to avoid various degenenerate behaviors.k
static constexpr size_t MAX_TEXT_LENGTH = 16384;
+2 -2
View File
@@ -124,13 +124,13 @@ void TextDrawerAndroid::MeasureStringInternal(const FontStyle &style, std::strin
*h = (float)(size & 0xFFFF);
}
bool TextDrawerAndroid::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) {
bool TextDrawerAndroid::DrawStringBitmap(const FontStyle &style, std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) {
if (str.empty()) {
bitmapData.clear();
return false;
}
auto iter = fontMap_.find(fontStyle_);
auto iter = fontMap_.find(style);
if (iter == fontMap_.end()) {
ERROR_LOG(Log::G3D, "Missing font");
return false;
+1 -1
View File
@@ -20,11 +20,11 @@ public:
~TextDrawerAndroid();
bool IsReady() const override;
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
protected:
void EnsureFont(const FontStyle &style) override;
void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override;
bool DrawStringBitmap(const FontStyle &style, std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
bool SupportsColorEmoji() const override { return true; }
void ClearFonts() override;
+1 -1
View File
@@ -16,11 +16,11 @@ public:
TextDrawerCocoa(Draw::DrawContext *draw);
~TextDrawerCocoa();
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
protected:
void EnsureFont(const FontStyle &style) override;
void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override;
bool DrawStringBitmap(const FontStyle &style, std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
bool SupportsColorEmoji() const override { return true; }
void ClearFonts() override;
+5 -5
View File
@@ -223,13 +223,13 @@ void TextDrawerCocoa::MeasureStringInternal(const FontStyle &style, std::string_
*h = ceilf(extH);
}
bool TextDrawerCocoa::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) {
bool TextDrawerCocoa::DrawStringBitmap(const FontStyle &style, std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) {
if (str.empty()) {
bitmapData.clear();
return false;
}
auto iter = fontMap_.find(fontStyle_);
auto iter = fontMap_.find(style);
if (iter == fontMap_.end()) {
return false;
}
@@ -258,10 +258,10 @@ bool TextDrawerCocoa::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStr
// Figure out how big an image we need.
// We re-use MeasureString here.
float w, h;
MeasureString(str, &w, &h);
MeasureString(style, 1.0f, 1.0f, str, &w, &h);
// Reverse the DPI scale that MeasureString baked in.
w /= (dpiScale_ * fontScaleX_);
h /= (dpiScale_ * fontScaleY_);
w /= dpiScale_;
h /= dpiScale_;
int width = (int)ceilf(w);
int height = (int)ceilf(h);
+2 -2
View File
@@ -436,7 +436,7 @@ void TextDrawerSDL::MeasureStringInternal(const FontStyle &style, std::string_vi
*h = (float)extH;
}
bool TextDrawerSDL::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) {
bool TextDrawerSDL::DrawStringBitmap(const FontStyle &style, std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) {
_dbg_assert_(!fullColor)
if (str.empty()) {
@@ -444,7 +444,7 @@ bool TextDrawerSDL::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStrin
return false;
}
auto fontIter = fontMap_.find(fontStyle_);
auto fontIter = fontMap_.find(style);
if (fontIter == fontMap_.end()) {
ERROR_LOG(Log::G3D, "Font style not in map");
return false;
+1 -1
View File
@@ -19,11 +19,11 @@ public:
TextDrawerSDL(Draw::DrawContext *draw);
~TextDrawerSDL();
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
protected:
void EnsureFont(const FontStyle &style) override;
void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override;
bool DrawStringBitmap(const FontStyle &style, std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
bool SupportsColorEmoji() const override { return false; }
void ClearFonts() override;
+2 -2
View File
@@ -300,7 +300,7 @@ void TextDrawerUWP::MeasureStringInternal(const FontStyle &style, std::string_vi
*h = (int)(metrics.height + 1.0f);
}
bool TextDrawerUWP::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) {
bool TextDrawerUWP::DrawStringBitmap(const FontStyle &style, std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) {
if (str.empty()) {
bitmapData.clear();
return false;
@@ -310,7 +310,7 @@ bool TextDrawerUWP::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStrin
SIZE size;
IDWriteTextFormat *format = nullptr;
auto iter = fontMap_.find(fontStyle_);
auto iter = fontMap_.find(style);
if (iter != fontMap_.end()) {
format = iter->second->textFmt;
}
+1 -1
View File
@@ -20,11 +20,11 @@ public:
TextDrawerUWP(Draw::DrawContext *draw);
~TextDrawerUWP();
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
protected:
void EnsureFont(const FontStyle &style) override;
void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override;
bool DrawStringBitmap(const FontStyle &style, std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
bool SupportsColorEmoji() const override { return true; }
void ClearFonts() override;
+2 -2
View File
@@ -154,14 +154,14 @@ void TextDrawerWin32::MeasureStringInternal(const FontStyle &style, std::string_
*h = extH;
}
bool TextDrawerWin32::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) {
bool TextDrawerWin32::DrawStringBitmap(const FontStyle &style, std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) {
if (str.empty()) {
bitmapData.clear();
return false;
}
std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(str, "\n", "\r\n"));
auto iter = fontMap_.find(fontStyle_);
auto iter = fontMap_.find(style);
if (iter != fontMap_.end()) {
SelectObject(ctx_->hDC, iter->second->hFont);
}
+1 -1
View File
@@ -16,11 +16,11 @@ public:
TextDrawerWin32(Draw::DrawContext *draw);
~TextDrawerWin32();
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
protected:
void EnsureFont(const FontStyle &style) override;
void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override;
bool DrawStringBitmap(const FontStyle &style, std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
bool SupportsColorEmoji() const override { return false; }
void ClearFonts() override;
+6 -8
View File
@@ -42,6 +42,10 @@ void UIContext::Init(Draw::DrawContext *thin3d, Draw::Pipeline *uipipe, Draw::Pi
void UIContext::BeginFrame() {
frameStartTime_ = time_now_d();
// Text drawn before anything set a style uses the theme's.
if (fontStyle_->sizePts <= 0 && theme) {
*fontStyle_ = theme->uiFont;
}
if (atlasInvalid_ || !uitexture_) {
if (uitexture_) {
uitexture_->Release();
@@ -266,10 +270,6 @@ void UIContext::SetFontScale(float scaleX, float scaleY) {
void UIContext::SetFontStyle(const FontStyle &fontStyle) {
*fontStyle_ = fontStyle;
if (textDrawer_) {
textDrawer_->SetFontScale(fontScaleX_, fontScaleY_);
textDrawer_->SetOrCreateFont(fontStyle);
}
}
static FontID AtlasFontFromStyle(const FontStyle &style) {
@@ -314,8 +314,7 @@ void UIContext::DrawText(std::string_view str, float x, float y, uint32_t color,
if (useFontTexture)
Flush();
} else {
textDrawer_->SetFontScale(fontScaleX_, fontScaleY_);
textDrawer_->DrawString(*Draw(), str, x, y, color, align);
textDrawer_->DrawString(*Draw(), *fontStyle_, fontScaleX_, fontScaleY_, str, x, y, color, align);
}
RebindTexture();
}
@@ -340,11 +339,10 @@ void UIContext::DrawTextRect(std::string_view str, const Bounds &bounds, uint32_
if (useFontTexture)
Flush();
} else {
textDrawer_->SetFontScale(fontScaleX_, fontScaleY_);
Bounds rounded = bounds;
rounded.x = floorf(rounded.x);
rounded.y = floorf(rounded.y);
textDrawer_->DrawStringRect(*Draw(), str, rounded, color, align);
textDrawer_->DrawStringRect(*Draw(), *fontStyle_, fontScaleX_, fontScaleY_, str, rounded, color, align);
}
RebindTexture();
}
+6 -10
View File
@@ -115,6 +115,7 @@ static AtlasTextMetrics char_lines_metrics;
static bool textDrawerInited = false;
static TextDrawer *textDrawer = nullptr;
static const FontStyle textDrawerFont(FontFamily::SansSerif, 18, FontStyleFlags::Default);
struct PPGeTextDrawerCacheKey {
bool operator < (const PPGeTextDrawerCacheKey &other) const {
if (align != other.align)
@@ -769,9 +770,7 @@ static bool HasTextDrawer() {
// Should we pass a draw_? Yes! UWP requires it.
textDrawer = TextDrawer::Create(g_draw);
if (textDrawer) {
textDrawer->SetFontScale(1.0f, 1.0f);
textDrawer->SetForcedDPIScale(1.0f);
textDrawer->SetOrCreateFont(FontStyle(FontFamily::SansSerif, 18, FontStyleFlags::Default));
}
textDrawerInited = true;
return textDrawer != nullptr;
@@ -786,11 +785,10 @@ void PPGeMeasureText(float *w, float *h, std::string_view text, float scale, int
if (HasTextDrawer()) {
float mw, mh;
textDrawer->SetFontScale(scale, scale);
int dtalign = (WrapType & PPGE_LINE_WRAP_WORD) ? FLAG_WRAP_TEXT : 0;
if (WrapType & PPGE_LINE_USE_ELLIPSIS)
dtalign |= FLAG_ELLIPSIZE_TEXT;
textDrawer->MeasureStringRect(s, wrapWidth <= 0 ? 480.0f : wrapWidth, &mw, &mh, dtalign);
textDrawer->MeasureStringRect(textDrawerFont, scale, scale, s, wrapWidth <= 0 ? 480.0f : wrapWidth, &mw, &mh, dtalign);
if (w)
*w = mw;
@@ -920,10 +918,9 @@ static PPGeTextDrawerImage PPGeGetTextImage(std::string_view text, const PPGeSty
cacheItem->second.entry.lastUsedFrame = gpuStats.totals.numFlips;
} else {
std::vector<uint8_t> bitmapData;
textDrawer->SetFontScale(style.scale, style.scale);
Bounds b(0, 0, maxWidth, 272.0f);
std::string cleaned = ReplaceAll(text, "\r", "");
textDrawer->DrawStringBitmapRect(bitmapData, im.entry, Draw::DataFormat::R8_UNORM, cleaned.c_str(), b, tdalign, false);
textDrawer->DrawStringBitmapRect(textDrawerFont, style.scale, bitmapData, im.entry, Draw::DataFormat::R8_UNORM, cleaned.c_str(), b, tdalign, false);
int bufwBytes = ((im.entry.bmWidth + 31) / 32) * 16;
u32 sz = bufwBytes * (im.entry.bmHeight + 1);
@@ -1125,16 +1122,15 @@ void PPGeDrawTextWrapped(std::string_view text, float x, float y, float wrapWidt
float actualWidth, actualHeight;
Bounds b(0, 0, wrapWidth <= 0 ? 480.0f - x : wrapWidth, wrapHeight);
int tdalign = 0;
textDrawer->SetFontScale(style.scale, style.scale);
textDrawer->MeasureStringRect(s, b.w, &actualWidth, &actualHeight, tdalign | FLAG_WRAP_TEXT);
textDrawer->MeasureStringRect(textDrawerFont, style.scale, style.scale, s, b.w, &actualWidth, &actualHeight, tdalign | FLAG_WRAP_TEXT);
// Check if we need to scale the text down to fit better.
PPGeStyle adjustedStyle = style;
if (wrapHeight != 0.0f && actualHeight > wrapHeight) {
// Cheap way to get the line height.
float oneLine, twoLines;
textDrawer->MeasureString("|", &actualWidth, &oneLine);
textDrawer->MeasureStringRect("|\n|", 480, &actualWidth, &twoLines);
textDrawer->MeasureString(textDrawerFont, style.scale, style.scale, "|", &actualWidth, &oneLine);
textDrawer->MeasureStringRect(textDrawerFont, style.scale, style.scale, "|\n|", 480, &actualWidth, &twoLines);
float lineHeight = twoLines - oneLine;
if (actualHeight > wrapHeight * maxScaleDown) {
-4
View File
@@ -1005,10 +1005,6 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) {
ui_draw2d.Init(g_draw, texColorPipeline);
uiContext->Init(g_draw, texColorPipeline, colorPipeline, &ui_draw2d);
if (uiContext->Text()) {
// This seems unnecessary.
// uiContext->Text()->SetOrCreateFont(FontStyle(FontID::invalid(), FontFamily::SansSerif, 20, FontStyleFlags::Default));
}
g_screenManager->setUIContext(uiContext);
// Live before the queue is processed: a removal that comes in while the outputs' swapchains are being
+14 -26
View File
@@ -3744,18 +3744,16 @@ bool TestFatShortNames() {
class FakeTextDrawer : public TextDrawer {
public:
FakeTextDrawer() : TextDrawer(nullptr) {}
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override { return false; }
void TestDropShadow(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat srcFormat) {
AddDropShadow(bitmapData, entry, srcFormat);
}
const FontStyle &CurrentStyle() const { return fontStyle_; }
int measureCalls = 0;
protected:
void EnsureFont(const FontStyle &style) override {}
bool DrawStringBitmap(const FontStyle &style, std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override { return false; }
void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override {
measureCalls++;
std::vector<std::string_view> lines;
@@ -3774,49 +3772,40 @@ protected:
bool TestTextDrawerCache() {
FakeTextDrawer drawer;
drawer.SetForcedDPIScale(1.0f);
drawer.SetOrCreateFont(FontStyle(FontFamily::SansSerif, 20, FontStyleFlags::Default));
const FontStyle font20(FontFamily::SansSerif, 20, FontStyleFlags::Default);
const FontStyle font30(FontFamily::SansSerif, 30, FontStyleFlags::Default);
float w, h;
drawer.MeasureString("hello", &w, &h);
drawer.MeasureString(font20, 1.0f, 1.0f, "hello", &w, &h);
EXPECT_EQ_FLOAT(w, 50.0f);
EXPECT_EQ_FLOAT(h, 20.0f);
drawer.MeasureString("hello", &w, &h);
drawer.MeasureString(font20, 1.0f, 1.0f, "hello", &w, &h);
EXPECT_EQ_INT(drawer.measureCalls, 1);
// A different style is a different cache entry.
drawer.SetOrCreateFont(FontStyle(FontFamily::SansSerif, 30, FontStyleFlags::Default));
drawer.MeasureString("hello", &w, &h);
// A different style is a different cache entry, but a different scale isn't.
drawer.MeasureString(font30, 1.0f, 1.0f, "hello", &w, &h);
EXPECT_EQ_INT(drawer.measureCalls, 2);
drawer.MeasureString(font30, 2.0f, 2.0f, "hello", &w, &h);
EXPECT_EQ_FLOAT(w, 100.0f);
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);
drawer.MeasureStringRect(font30, 1.0f, 1.0f, para, 200.0f, &w, &h, FLAG_WRAP_TEXT);
// The trailing space of a wrapped line is measured too.
EXPECT_TRUE(w <= 210.0f);
EXPECT_TRUE(h > 20.0f);
float w2, h2;
int callsBefore = drawer.measureCalls;
drawer.MeasureStringRect(para, 200.0f, &w2, &h2, FLAG_WRAP_TEXT);
drawer.MeasureStringRect(font30, 1.0f, 1.0f, para, 200.0f, &w2, &h2, FLAG_WRAP_TEXT);
EXPECT_EQ_FLOAT(w, w2);
EXPECT_EQ_FLOAT(h, h2);
EXPECT_EQ_INT(drawer.measureCalls, callsBefore);
// Scaling the font changes where the text wraps.
drawer.SetFontScale(0.5f, 0.5f);
drawer.MeasureStringRect(para, 200.0f, &w2, &h2, FLAG_WRAP_TEXT);
drawer.MeasureStringRect(font30, 0.5f, 0.5f, para, 200.0f, &w2, &h2, FLAG_WRAP_TEXT);
EXPECT_TRUE(h2 < h * 0.5f);
drawer.SetFontScale(1.0f, 1.0f);
drawer.MeasureStringRect(para, 200.0f, &w, &h, FLAG_ELLIPSIZE_TEXT);
drawer.MeasureStringRect(font30, 1.0f, 1.0f, para, 200.0f, &w, &h, FLAG_ELLIPSIZE_TEXT);
EXPECT_EQ_FLOAT(h, 20.0f);
EXPECT_TRUE(w <= 200.0f);
@@ -3830,7 +3819,6 @@ bool TestTextDrawerCache() {
}
drawer.TestDropShadow(bitmap, entry, Draw::DataFormat::R8_UNORM);
};
drawer.SetOrCreateFont(FontStyle(FontFamily::SansSerif, 24, FontStyleFlags::Default));
TextStringEntry entry1(0), entry2(0);
std::vector<uint8_t> bitmap;
shadowTest(1.0f, entry1, bitmap);