mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-15 10:40:01 +01:00
TextDrawer: Measure in a given style without switching fonts
Measuring took the current font and scale, so UIContext switched to the style being measured and back. On first draw the font to switch back to could be an empty one, which the UWP drawer asserts on. MeasureString and MeasureStringRect now take the style and scale, and the backends' MeasureStringInternal measures in the style it's given. SetOrCreateFont, which sets the font drawing uses, is shared, and the backends only implement EnsureFont, which creates a font if needed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
57161a245e
commit
dc1e9e50fc
14 files changed
+98
-111
No files matched your search
@@ -65,31 +65,36 @@ TextDrawer::TextDrawer(Draw::DrawContext *draw) : draw_(draw) {
|
||||
|
||||
float TextDrawerWordWrapper::MeasureWidth(std::string_view str) {
|
||||
float w, h;
|
||||
drawer_->MeasureString(str, &w, &h);
|
||||
drawer_->MeasureString(style_, scale_, scale_, str, &w, &h);
|
||||
return w;
|
||||
}
|
||||
|
||||
const TextCacheKey &TextDrawer::LookupKey(std::string_view str, int flags, float maxWidth, float scale) {
|
||||
const TextCacheKey &TextDrawer::LookupKey(const FontStyle &style, std::string_view str, int flags, float maxWidth, float scale) {
|
||||
lookupKey_.text.assign(str.data(), str.size());
|
||||
lookupKey_.style = fontStyle_;
|
||||
lookupKey_.style = style;
|
||||
lookupKey_.flags = flags;
|
||||
lookupKey_.maxWidth = maxWidth;
|
||||
lookupKey_.scale = scale;
|
||||
return lookupKey_;
|
||||
}
|
||||
|
||||
const std::string &TextDrawer::WrapString(std::string_view str, float maxW, int flags) {
|
||||
const std::string &TextDrawer::WrapString(const FontStyle &style, float scale, std::string_view str, float maxW, int flags) {
|
||||
// The wrapper measures in scaled units, so the result depends on the scale too.
|
||||
auto [iter, inserted] = wrapCache_.try_emplace(LookupKey(str, flags, maxW, fontScaleX_));
|
||||
auto [iter, inserted] = wrapCache_.try_emplace(LookupKey(style, str, flags, maxW, scale));
|
||||
TextWrapEntry &entry = iter->second;
|
||||
entry.lastUsedFrame = frameCount_;
|
||||
if (inserted) {
|
||||
TextDrawerWordWrapper wrapper(this, str, maxW, flags);
|
||||
TextDrawerWordWrapper wrapper(this, style, scale, str, maxW, flags);
|
||||
entry.wrapped = wrapper.Wrapped();
|
||||
}
|
||||
return entry.wrapped;
|
||||
}
|
||||
|
||||
void TextDrawer::SetOrCreateFont(const FontStyle &style) {
|
||||
EnsureFont(style);
|
||||
fontStyle_ = style;
|
||||
}
|
||||
|
||||
void TextDrawer::SetFontScale(float xscale, float yscale) {
|
||||
fontScaleX_ = xscale;
|
||||
fontScaleY_ = yscale;
|
||||
@@ -112,7 +117,7 @@ void TextDrawer::DrawString(DrawBuffer &target, std::string_view str, float x, f
|
||||
|
||||
TextStringEntry *entry;
|
||||
|
||||
auto [iter, inserted] = cache_.try_emplace(LookupKey(str, align & FLAG_DROP_SHADOW));
|
||||
auto [iter, inserted] = cache_.try_emplace(LookupKey(fontStyle_, str, align & FLAG_DROP_SHADOW));
|
||||
if (!inserted) {
|
||||
entry = iter->second.get();
|
||||
entry->lastUsedFrame = frameCount_;
|
||||
@@ -186,7 +191,7 @@ void TextDrawer::DrawString(DrawBuffer &target, std::string_view str, float x, f
|
||||
target.Flush(true);
|
||||
}
|
||||
|
||||
void TextDrawer::MeasureString(std::string_view str, float *w, float *h) {
|
||||
void TextDrawer::MeasureString(const FontStyle &style, float scaleX, float scaleY, std::string_view str, float *w, float *h) {
|
||||
if (str.empty()) {
|
||||
*w = 0.0f;
|
||||
*h = 0.0f;
|
||||
@@ -198,11 +203,12 @@ void TextDrawer::MeasureString(std::string_view str, float *w, float *h) {
|
||||
str = str.substr(0, MAX_TEXT_LENGTH);
|
||||
}
|
||||
|
||||
auto [iter, inserted] = sizeCache_.try_emplace(LookupKey(str));
|
||||
auto [iter, inserted] = sizeCache_.try_emplace(LookupKey(style, str));
|
||||
TextMeasureEntry &entry = iter->second;
|
||||
if (inserted) {
|
||||
float extW, extH;
|
||||
MeasureStringInternal(str, &extW, &extH);
|
||||
EnsureFont(style);
|
||||
float extW = 0.0f, extH = 0.0f;
|
||||
MeasureStringInternal(style, str, &extW, &extH);
|
||||
entry.width = extW;
|
||||
entry.height = extH;
|
||||
// Hm, use the old calculation?
|
||||
@@ -210,11 +216,11 @@ void TextDrawer::MeasureString(std::string_view str, float *w, float *h) {
|
||||
}
|
||||
|
||||
entry.lastUsedFrame = frameCount_;
|
||||
*w = entry.width * fontScaleX_ * dpiScale_;
|
||||
*h = entry.height * fontScaleY_ * dpiScale_;
|
||||
*w = entry.width * scaleX * dpiScale_;
|
||||
*h = entry.height * scaleY * dpiScale_;
|
||||
}
|
||||
|
||||
void TextDrawer::MeasureStringRect(std::string_view str, float maxWidth, float *w, float *h, int align) {
|
||||
void TextDrawer::MeasureStringRect(const FontStyle &style, float scaleX, float scaleY, std::string_view str, float maxWidth, float *w, float *h, int align) {
|
||||
const int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT);
|
||||
|
||||
// Clamp the size to something sane.
|
||||
@@ -223,10 +229,10 @@ void TextDrawer::MeasureStringRect(std::string_view str, float maxWidth, float *
|
||||
}
|
||||
|
||||
float plainW, plainH;
|
||||
MeasureString(str, &plainW, &plainH);
|
||||
MeasureString(style, scaleX, scaleY, str, &plainW, &plainH);
|
||||
|
||||
if (wrap && plainW > maxWidth) {
|
||||
MeasureString(WrapString(str, maxWidth, wrap), w, h);
|
||||
MeasureString(style, scaleX, scaleY, WrapString(style, scaleX, str, maxWidth, wrap), w, h);
|
||||
} else {
|
||||
*w = plainW;
|
||||
*h = plainH;
|
||||
@@ -256,7 +262,7 @@ void TextDrawer::DrawStringRect(DrawBuffer &target, std::string_view str, const
|
||||
}
|
||||
|
||||
const int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT);
|
||||
DrawString(target, wrap ? std::string_view(WrapString(str, bounds.w, wrap)) : str, x, y, color, align);
|
||||
DrawString(target, wrap ? std::string_view(WrapString(fontStyle_, fontScaleX_, str, bounds.w, wrap)) : str, x, y, color, align);
|
||||
}
|
||||
|
||||
bool TextDrawer::DrawStringBitmapRect(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, const Bounds &bounds, int align, bool fullColor) {
|
||||
@@ -266,7 +272,7 @@ bool TextDrawer::DrawStringBitmapRect(std::vector<uint8_t> &bitmapData, TextStri
|
||||
}
|
||||
|
||||
const int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT);
|
||||
return DrawStringBitmap(bitmapData, entry, texFormat, wrap ? std::string_view(WrapString(str, bounds.w, wrap)) : str, align, fullColor);
|
||||
return DrawStringBitmap(bitmapData, entry, texFormat, wrap ? std::string_view(WrapString(fontStyle_, fontScaleX_, str, bounds.w, wrap)) : str, align, fullColor);
|
||||
}
|
||||
|
||||
void TextDrawer::AddDropShadow(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat srcFormat) const {
|
||||
|
||||
@@ -71,11 +71,20 @@ public:
|
||||
virtual ~TextDrawer() = default;
|
||||
|
||||
virtual bool IsReady() const { return true; }
|
||||
virtual void SetOrCreateFont(const FontStyle &style) = 0;
|
||||
|
||||
// Sets the font and scale that drawing uses.
|
||||
void SetOrCreateFont(const FontStyle &style);
|
||||
void SetFontScale(float xscale, float yscale);
|
||||
void MeasureString(std::string_view str, float *w, float *h);
|
||||
void MeasureStringRect(std::string_view str, float maxWidth, float *w, float *h, int align = ALIGN_TOPLEFT);
|
||||
|
||||
// Measuring doesn't depend on the current font and scale.
|
||||
void MeasureString(const FontStyle &style, float scaleX, float scaleY, std::string_view str, float *w, float *h);
|
||||
void MeasureStringRect(const FontStyle &style, float scaleX, float scaleY, std::string_view str, float maxWidth, float *w, float *h, int align = ALIGN_TOPLEFT);
|
||||
// In the current font and scale.
|
||||
void MeasureString(std::string_view str, float *w, float *h) {
|
||||
MeasureString(fontStyle_, fontScaleX_, fontScaleY_, str, w, h);
|
||||
}
|
||||
void MeasureStringRect(std::string_view str, float maxWidth, float *w, float *h, int align = ALIGN_TOPLEFT) {
|
||||
MeasureStringRect(fontStyle_, fontScaleX_, fontScaleY_, str, maxWidth, w, h, align);
|
||||
}
|
||||
|
||||
void DrawString(DrawBuffer &target, std::string_view str, float x, float y, uint32_t color, int align = ALIGN_TOPLEFT);
|
||||
void DrawStringRect(DrawBuffer &target, std::string_view str, const Bounds &bounds, uint32_t color, int align);
|
||||
@@ -102,8 +111,10 @@ public:
|
||||
protected:
|
||||
TextDrawer(Draw::DrawContext *draw);
|
||||
|
||||
// Implementations of this must handle multi-line strings.
|
||||
virtual void MeasureStringInternal(std::string_view str, float *w, float *h) = 0;
|
||||
// Creates the font for style, if it isn't already.
|
||||
virtual void EnsureFont(const FontStyle &style) = 0;
|
||||
// Implementations of this must handle multi-line strings. EnsureFont has been called for style.
|
||||
virtual void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) = 0;
|
||||
|
||||
void ClearCache();
|
||||
|
||||
@@ -111,7 +122,7 @@ protected:
|
||||
virtual void ClearFonts() = 0;
|
||||
|
||||
// Wraps and/or ellipsizes, caching the result. The reference stays valid until the next OncePerFrame.
|
||||
const std::string &WrapString(std::string_view str, float maxWidth, int flags);
|
||||
const std::string &WrapString(const FontStyle &style, float scale, std::string_view str, float maxWidth, int flags);
|
||||
|
||||
// v has the 8-bit alpha.
|
||||
static u16 AlphaToPremul4444(u32 v) {
|
||||
@@ -153,7 +164,7 @@ protected:
|
||||
static constexpr size_t MAX_TEXT_LENGTH = 16384;
|
||||
|
||||
// Fills in and returns lookupKey_, which reuses its string buffer, so a cache hit doesn't allocate.
|
||||
const TextCacheKey &LookupKey(std::string_view str, int flags = 0, float maxWidth = 0.0f, float scale = 0.0f);
|
||||
const TextCacheKey &LookupKey(const FontStyle &style, std::string_view str, int flags = 0, float maxWidth = 0.0f, float scale = 0.0f);
|
||||
void AddDropShadow(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat srcFormat) const;
|
||||
|
||||
TextCacheKey lookupKey_;
|
||||
@@ -165,13 +176,15 @@ protected:
|
||||
|
||||
class TextDrawerWordWrapper : public WordWrapper {
|
||||
public:
|
||||
TextDrawerWordWrapper(TextDrawer *drawer, std::string_view str, float maxW, int flags)
|
||||
: WordWrapper(str, maxW, flags), drawer_(drawer) {}
|
||||
TextDrawerWordWrapper(TextDrawer *drawer, const FontStyle &style, float scale, std::string_view str, float maxW, int flags)
|
||||
: WordWrapper(str, maxW, flags), drawer_(drawer), style_(style), scale_(scale) {}
|
||||
|
||||
protected:
|
||||
float MeasureWidth(std::string_view str) override;
|
||||
|
||||
TextDrawer *drawer_;
|
||||
FontStyle style_;
|
||||
float scale_;
|
||||
};
|
||||
|
||||
// The backends can use this to query the filenames of the fonts.
|
||||
|
||||
@@ -58,12 +58,10 @@ bool TextDrawerAndroid::IsReady() const {
|
||||
return cls_textRenderer != nullptr && method_measureText != nullptr && method_renderText != nullptr;
|
||||
}
|
||||
|
||||
void TextDrawerAndroid::SetOrCreateFont(const FontStyle &style) {
|
||||
void TextDrawerAndroid::EnsureFont(const FontStyle &style) {
|
||||
// We will only use the default font but just for consistency let's still involve
|
||||
// the font name.
|
||||
auto iter = fontMap_.find(style);
|
||||
if (iter != fontMap_.end()) {
|
||||
fontStyle_ = style;
|
||||
if (fontMap_.find(style) != fontMap_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -98,11 +96,10 @@ void TextDrawerAndroid::SetOrCreateFont(const FontStyle &style) {
|
||||
|
||||
// Just chose a factor that looks good, don't know what unit size is in anyway.
|
||||
fontMap_[style] = entry;
|
||||
fontStyle_ = style;
|
||||
}
|
||||
|
||||
void TextDrawerAndroid::MeasureStringInternal(std::string_view str, float *w, float *h) {
|
||||
auto iter = fontMap_.find(fontStyle_);
|
||||
void TextDrawerAndroid::MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) {
|
||||
auto iter = fontMap_.find(style);
|
||||
if (iter == fontMap_.end()) {
|
||||
ERROR_LOG(Log::G3D, "Missing font");
|
||||
*w = 1.0f;
|
||||
|
||||
@@ -20,11 +20,11 @@ public:
|
||||
~TextDrawerAndroid();
|
||||
|
||||
bool IsReady() const override;
|
||||
void SetOrCreateFont(const FontStyle &style) override;
|
||||
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
|
||||
|
||||
protected:
|
||||
void MeasureStringInternal(std::string_view str, float *w, float *h) override;
|
||||
void EnsureFont(const FontStyle &style) override;
|
||||
void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override;
|
||||
bool SupportsColorEmoji() const override { return true; }
|
||||
|
||||
void ClearFonts() override;
|
||||
|
||||
@@ -16,11 +16,11 @@ public:
|
||||
TextDrawerCocoa(Draw::DrawContext *draw);
|
||||
~TextDrawerCocoa();
|
||||
|
||||
void SetOrCreateFont(const FontStyle &style) override;
|
||||
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
|
||||
|
||||
protected:
|
||||
void MeasureStringInternal(std::string_view str, float *w, float *h) override;
|
||||
void EnsureFont(const FontStyle &style) override;
|
||||
void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override;
|
||||
bool SupportsColorEmoji() const override { return true; }
|
||||
|
||||
void ClearFonts() override;
|
||||
|
||||
@@ -137,21 +137,18 @@ TextDrawerCocoa::~TextDrawerCocoa() {
|
||||
}
|
||||
|
||||
// TODO: Share with other backends.
|
||||
void TextDrawerCocoa::SetOrCreateFont(const FontStyle &style) {
|
||||
void TextDrawerCocoa::EnsureFont(const FontStyle &style) {
|
||||
if (style.sizePts <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto iter = fontMap_.find(style);
|
||||
if (iter != fontMap_.end()) {
|
||||
fontStyle_ = style;
|
||||
if (fontMap_.find(style) != fontMap_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TextDrawerFontContext *font = new TextDrawerFontContext(style, dpiScale_);
|
||||
|
||||
fontMap_[style] = std::unique_ptr<TextDrawerFontContext>(font);
|
||||
fontStyle_ = style;
|
||||
}
|
||||
|
||||
void TextDrawerCocoa::ClearFonts() {
|
||||
@@ -163,8 +160,8 @@ void TextDrawerCocoa::ClearFonts() {
|
||||
}
|
||||
|
||||
// AI added some error checks here.
|
||||
void TextDrawerCocoa::MeasureStringInternal(std::string_view str, float *w, float *h) {
|
||||
auto iter = fontMap_.find(fontStyle_);
|
||||
void TextDrawerCocoa::MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) {
|
||||
auto iter = fontMap_.find(style);
|
||||
NSDictionary *attributes = nil;
|
||||
if (iter != fontMap_.end()) {
|
||||
attributes = iter->second->attributes;
|
||||
|
||||
@@ -297,13 +297,7 @@ void TextDrawerSDL::PrepareFallbackFonts(std::string_view locale) {
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t TextDrawerSDL::CheckMissingGlyph(std::string_view text) {
|
||||
auto iter = fontMap_.find(fontStyle_);
|
||||
if (iter == fontMap_.end()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
TTF_Font *font = iter->second.first;
|
||||
uint32_t TextDrawerSDL::CheckMissingGlyph(TTF_Font *font, std::string_view text) {
|
||||
if (!font) {
|
||||
return 0;
|
||||
}
|
||||
@@ -360,10 +354,8 @@ int TextDrawerSDL::FindFallbackFonts(uint32_t missingGlyph, int ptSize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void TextDrawerSDL::SetOrCreateFont(const FontStyle &style) {
|
||||
auto iter = fontMap_.find(style);
|
||||
if (iter != fontMap_.end()) {
|
||||
fontStyle_ = style;
|
||||
void TextDrawerSDL::EnsureFont(const FontStyle &style) {
|
||||
if (fontMap_.find(style) != fontMap_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -387,13 +379,12 @@ void TextDrawerSDL::SetOrCreateFont(const FontStyle &style) {
|
||||
}
|
||||
|
||||
fontMap_[style] = std::make_pair(font, fileData);
|
||||
fontStyle_ = style;
|
||||
}
|
||||
|
||||
void TextDrawerSDL::MeasureStringInternal(std::string_view str, float *w, float *h) {
|
||||
void TextDrawerSDL::MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) {
|
||||
*w = 1.0f;
|
||||
*h = 1.0f;
|
||||
auto iter = fontMap_.find(fontStyle_);
|
||||
auto iter = fontMap_.find(style);
|
||||
if (iter == fontMap_.end()) {
|
||||
return;
|
||||
}
|
||||
@@ -408,10 +399,10 @@ void TextDrawerSDL::MeasureStringInternal(std::string_view str, float *w, float
|
||||
str = reorderedStr;
|
||||
}
|
||||
|
||||
uint32_t missingGlyph = CheckMissingGlyph(str);
|
||||
uint32_t missingGlyph = CheckMissingGlyph(font, str);
|
||||
|
||||
if (missingGlyph) {
|
||||
const int ptSize = static_cast<int>(fontStyle_.sizePts / dpiScale_ * 1.25f);
|
||||
const int ptSize = static_cast<int>(style.sizePts / dpiScale_ * 1.25f);
|
||||
const int fallbackFont = FindFallbackFonts(missingGlyph, ptSize);
|
||||
if (fallbackFont >= 0 && fallbackFont < (int)fallbackFonts_.size()) {
|
||||
font = fallbackFonts_[fallbackFont];
|
||||
@@ -478,7 +469,7 @@ bool TextDrawerSDL::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStrin
|
||||
processedStr.push_back(' ');
|
||||
}
|
||||
|
||||
uint32_t missingGlyph = CheckMissingGlyph(processedStr);
|
||||
uint32_t missingGlyph = CheckMissingGlyph(font, processedStr);
|
||||
|
||||
if (missingGlyph) {
|
||||
const int ptSize = static_cast<int>(TTF_GetFontSize(font));
|
||||
|
||||
@@ -19,18 +19,18 @@ public:
|
||||
TextDrawerSDL(Draw::DrawContext *draw);
|
||||
~TextDrawerSDL();
|
||||
|
||||
void SetOrCreateFont(const FontStyle &style) override;
|
||||
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
|
||||
|
||||
protected:
|
||||
void MeasureStringInternal(std::string_view str, float *w, float *h) override;
|
||||
void EnsureFont(const FontStyle &style) override;
|
||||
void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override;
|
||||
|
||||
bool SupportsColorEmoji() const override { return false; }
|
||||
void ClearFonts() override;
|
||||
|
||||
private:
|
||||
void PrepareFallbackFonts(std::string_view locale);
|
||||
uint32_t CheckMissingGlyph(std::string_view text);
|
||||
uint32_t CheckMissingGlyph(TTF_Font *font, std::string_view text);
|
||||
int FindFallbackFonts(uint32_t missingGlyph, int ptSize);
|
||||
|
||||
std::map<FontStyle, std::pair<TTF_Font *, uint8_t *>> fontMap_;
|
||||
|
||||
@@ -261,21 +261,17 @@ TextDrawerUWP::~TextDrawerUWP() {
|
||||
delete ctx_;
|
||||
}
|
||||
|
||||
void TextDrawerUWP::SetOrCreateFont(const FontStyle &style) {
|
||||
void TextDrawerUWP::EnsureFont(const FontStyle &style) {
|
||||
_dbg_assert_(style.sizePts > 0);
|
||||
auto iter = fontMap_.find(style);
|
||||
if (iter != fontMap_.end()) {
|
||||
fontStyle_ = style;
|
||||
if (fontMap_.find(style) != fontMap_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
fontMap_[style] = std::make_unique<TextDrawerFontContext>(style, dpiScale_, m_dwriteFactory, m_fontCollection);
|
||||
fontStyle_ = style;
|
||||
}
|
||||
|
||||
void TextDrawerUWP::MeasureStringInternal(std::string_view str, float *w, float *h) {
|
||||
void TextDrawerUWP::MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) {
|
||||
IDWriteTextFormat *format = nullptr;
|
||||
auto iter = fontMap_.find(fontStyle_);
|
||||
auto iter = fontMap_.find(style);
|
||||
if (iter != fontMap_.end()) {
|
||||
format = iter->second->textFmt;
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@ public:
|
||||
TextDrawerUWP(Draw::DrawContext *draw);
|
||||
~TextDrawerUWP();
|
||||
|
||||
void SetOrCreateFont(const FontStyle &style) override;
|
||||
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
|
||||
|
||||
protected:
|
||||
void MeasureStringInternal(std::string_view str, float *w, float *h) override;
|
||||
void EnsureFont(const FontStyle &style) override;
|
||||
void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override;
|
||||
bool SupportsColorEmoji() const override { return true; }
|
||||
void ClearFonts() override;
|
||||
|
||||
|
||||
@@ -117,19 +117,15 @@ TextDrawerWin32::~TextDrawerWin32() {
|
||||
delete ctx_;
|
||||
}
|
||||
|
||||
void TextDrawerWin32::SetOrCreateFont(const FontStyle &style) {
|
||||
auto iter = fontMap_.find(style);
|
||||
if (iter != fontMap_.end()) {
|
||||
fontStyle_ = style;
|
||||
void TextDrawerWin32::EnsureFont(const FontStyle &style) {
|
||||
if (fontMap_.find(style) != fontMap_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
fontMap_[style] = std::make_unique<TextDrawerFontContext>(style, dpiScale_);
|
||||
fontStyle_ = style;
|
||||
}
|
||||
|
||||
void TextDrawerWin32::MeasureStringInternal(std::string_view str, float *w, float *h) {
|
||||
auto iter = fontMap_.find(fontStyle_);
|
||||
void TextDrawerWin32::MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) {
|
||||
auto iter = fontMap_.find(style);
|
||||
if (iter != fontMap_.end()) {
|
||||
SelectObject(ctx_->hDC, iter->second->hFont);
|
||||
} else {
|
||||
|
||||
@@ -16,11 +16,11 @@ public:
|
||||
TextDrawerWin32(Draw::DrawContext *draw);
|
||||
~TextDrawerWin32();
|
||||
|
||||
void SetOrCreateFont(const FontStyle &style) override;
|
||||
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
|
||||
|
||||
protected:
|
||||
void MeasureStringInternal(std::string_view str, float *w, float *h) override;
|
||||
void EnsureFont(const FontStyle &style) override;
|
||||
void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override;
|
||||
bool SupportsColorEmoji() const override { return false; }
|
||||
void ClearFonts() override;
|
||||
|
||||
|
||||
+2
-23
@@ -284,19 +284,7 @@ void UIContext::MeasureText(const FontStyle &style, float scaleX, float scaleY,
|
||||
Draw()->SetFontScale(scaleX * sizeFactor, scaleY * sizeFactor);
|
||||
Draw()->MeasureText(AtlasFontFromStyle(style), str, x, y);
|
||||
} else {
|
||||
// Switching fonts costs two lookups, and most measuring is done in the current style.
|
||||
const bool switchFont = !(style == *fontStyle_);
|
||||
if (switchFont) {
|
||||
textDrawer_->SetOrCreateFont(style);
|
||||
}
|
||||
textDrawer_->SetFontScale(scaleX, scaleY);
|
||||
textDrawer_->MeasureString(str, x, y);
|
||||
if (switchFont) {
|
||||
// Check for bad "old font".
|
||||
if (fontStyle_ && fontStyle_->sizePts > 0) {
|
||||
textDrawer_->SetOrCreateFont(*fontStyle_);
|
||||
}
|
||||
}
|
||||
textDrawer_->MeasureString(style, scaleX, scaleY, str, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,16 +295,7 @@ void UIContext::MeasureTextRect(const FontStyle &style, float scaleX, float scal
|
||||
Draw()->SetFontScale(scaleX * sizeFactor, scaleY * sizeFactor);
|
||||
Draw()->MeasureTextRect(AtlasFontFromStyle(style), str, maxWidth, x, y, align);
|
||||
} else {
|
||||
// Switching fonts costs two lookups, and most measuring is done in the current style.
|
||||
const bool switchFont = !(style == *fontStyle_);
|
||||
if (switchFont) {
|
||||
textDrawer_->SetOrCreateFont(style);
|
||||
}
|
||||
textDrawer_->SetFontScale(scaleX, scaleY);
|
||||
textDrawer_->MeasureStringRect(str, maxWidth, x, y, align);
|
||||
if (switchFont) {
|
||||
textDrawer_->SetOrCreateFont(*fontStyle_);
|
||||
}
|
||||
textDrawer_->MeasureStringRect(style, scaleX, scaleY, str, maxWidth, x, y, align);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-2
@@ -3744,17 +3744,19 @@ bool TestFatShortNames() {
|
||||
class FakeTextDrawer : public TextDrawer {
|
||||
public:
|
||||
FakeTextDrawer() : TextDrawer(nullptr) {}
|
||||
void SetOrCreateFont(const FontStyle &style) override { fontStyle_ = style; }
|
||||
bool DrawStringBitmap(std::vector<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 MeasureStringInternal(std::string_view str, float *w, float *h) override {
|
||||
void EnsureFont(const FontStyle &style) override {}
|
||||
void MeasureStringInternal(const FontStyle &style, std::string_view str, float *w, float *h) override {
|
||||
measureCalls++;
|
||||
std::vector<std::string_view> lines;
|
||||
SplitString(str, '\n', lines);
|
||||
@@ -3786,6 +3788,16 @@ bool TestTextDrawerCache() {
|
||||
drawer.MeasureString("hello", &w, &h);
|
||||
EXPECT_EQ_INT(drawer.measureCalls, 2);
|
||||
|
||||
// Measuring in another style and scale leaves the current ones alone.
|
||||
const FontStyle small(FontFamily::SansSerif, 10, FontStyleFlags::Default);
|
||||
drawer.MeasureString(small, 2.0f, 2.0f, "hello", &w, &h);
|
||||
EXPECT_EQ_FLOAT(w, 100.0f);
|
||||
EXPECT_EQ_INT(drawer.measureCalls, 3);
|
||||
EXPECT_TRUE(drawer.CurrentStyle() == FontStyle(FontFamily::SansSerif, 30, FontStyleFlags::Default));
|
||||
drawer.MeasureString("hello", &w, &h);
|
||||
EXPECT_EQ_FLOAT(w, 50.0f);
|
||||
EXPECT_EQ_INT(drawer.measureCalls, 3);
|
||||
|
||||
const std::string_view para = "The quick brown fox jumps over the lazy dog, and then it does it again, and again, until the dog finally gets up and leaves.";
|
||||
drawer.MeasureStringRect(para, 200.0f, &w, &h, FLAG_WRAP_TEXT);
|
||||
// The trailing space of a wrapped line is measured too.
|
||||
|
||||
Reference in new issue
Block a user