diff --git a/lib/GfxRenderer/GfxRenderer.cpp b/lib/GfxRenderer/GfxRenderer.cpp index fa1c61c6..88e69598 100644 --- a/lib/GfxRenderer/GfxRenderer.cpp +++ b/lib/GfxRenderer/GfxRenderer.cpp @@ -2,6 +2,18 @@ #include +namespace { +size_t utf8RemoveLastChar(std::string& str) { + if (str.empty()) return 0; + size_t pos = str.size() - 1; + while (pos > 0 && (static_cast(str[pos]) & 0xC0) == 0x80) { + --pos; + } + str.resize(pos); + return pos; +} +} // namespace + void GfxRenderer::insertFont(const int fontId, EpdFontFamily font) { fontMap.insert({fontId, font}); } void GfxRenderer::rotateCoordinates(const int x, const int y, int* rotatedX, int* rotatedY) const { @@ -415,13 +427,32 @@ void GfxRenderer::displayBuffer(const HalDisplay::RefreshMode refreshMode) const std::string GfxRenderer::truncatedText(const int fontId, const char* text, const int maxWidth, const EpdFontFamily::Style style) const { - std::string item = text; + std::string item = text ? text : ""; + if (maxWidth <= 0) { + return ""; + } + int itemWidth = getTextWidth(fontId, item.c_str(), style); - while (itemWidth > maxWidth && item.length() > 8) { - item.replace(item.length() - 5, 5, "..."); + if (itemWidth <= maxWidth) { + return item; + } + + const char* ellipsis = "..."; + const int ellipsisWidth = getTextWidth(fontId, ellipsis, style); + if (ellipsisWidth > maxWidth) { + return ""; + } + + while (!item.empty() && itemWidth + ellipsisWidth > maxWidth) { + utf8RemoveLastChar(item); itemWidth = getTextWidth(fontId, item.c_str(), style); } - return item; + + if (item.empty()) { + return ellipsis; + } + + return item + ellipsis; } // Note: Internal driver treats screen in command orientation; this library exposes a logical orientation diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 58668c68..fb30119c 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -542,8 +542,8 @@ void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const in availableTitleSpace = rendererableScreenWidth - titleMarginLeft - titleMarginRight; titleMarginLeftAdjusted = titleMarginLeft; } - while (titleWidth > availableTitleSpace && title.length() > 11) { - title.replace(title.length() - 8, 8, "..."); + if (titleWidth > availableTitleSpace) { + title = renderer.truncatedText(SMALL_FONT_ID, title.c_str(), availableTitleSpace); titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str()); } } diff --git a/src/activities/reader/TxtReaderActivity.cpp b/src/activities/reader/TxtReaderActivity.cpp index e9303de3..0d55707c 100644 --- a/src/activities/reader/TxtReaderActivity.cpp +++ b/src/activities/reader/TxtReaderActivity.cpp @@ -565,8 +565,8 @@ void TxtReaderActivity::renderStatusBar(const int orientedMarginRight, const int std::string title = txt->getTitle(); int titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str()); - while (titleWidth > availableTextWidth && title.length() > 11) { - title.replace(title.length() - 8, 8, "..."); + if (titleWidth > availableTextWidth) { + title = renderer.truncatedText(SMALL_FONT_ID, title.c_str(), availableTextWidth); titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str()); }