mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-28 15:58:12 +00:00
perf(ui): O(n) FullscreenMsgView wrap via getCodepointWidth virtual
The wrap loop used to memcpy a growing substring and call getTextWidth on it for every appended codepoint — O(n²) UTF-8 decoding with Lemon font, ~5-20 ms on a full e-ink redraw of a long message. Add DisplayDriver::getCodepointWidth(cp) (default: build a UTF-8 buffer and forward to getTextWidth) plus DisplayDriver::decodeCodepoint() as the shared UTF-8 walker. Override getCodepointWidth in GxEPDDisplay (direct lemonXAdvance for Lemon size 1) and SH1106Display (lemonXAdvance for Lemon, fixed 6*sz for built-in font). FullscreenMsgView now walks codepoints once and sums widths incrementally. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -160,7 +160,48 @@ public:
|
||||
virtual void translateUTF8ToBlocks(char* dest, const char* src, size_t dest_size) {
|
||||
translateUTF8Static(dest, src, dest_size);
|
||||
}
|
||||
|
||||
|
||||
// Advance a UTF-8 pointer by one codepoint, returning the decoded value.
|
||||
// Invalid sequences return 0xFFFD and consume trailing continuation bytes.
|
||||
static uint32_t decodeCodepoint(const uint8_t*& p) {
|
||||
uint8_t c = *p++;
|
||||
if (c < 0x80) return c;
|
||||
if ((c & 0xE0) == 0xC0) {
|
||||
uint32_t cp = c & 0x1F;
|
||||
if (*p) cp = (cp << 6) | (*p++ & 0x3F);
|
||||
return cp;
|
||||
}
|
||||
if ((c & 0xF0) == 0xE0) {
|
||||
uint32_t cp = c & 0x0F;
|
||||
if (*p) cp = (cp << 6) | (*p++ & 0x3F);
|
||||
if (*p) cp = (cp << 6) | (*p++ & 0x3F);
|
||||
return cp;
|
||||
}
|
||||
if ((c & 0xF8) == 0xF0) {
|
||||
uint32_t cp = c & 0x07;
|
||||
if (*p) cp = (cp << 6) | (*p++ & 0x3F);
|
||||
if (*p) cp = (cp << 6) | (*p++ & 0x3F);
|
||||
if (*p) cp = (cp << 6) | (*p++ & 0x3F);
|
||||
return cp;
|
||||
}
|
||||
while (*p && (*p & 0xC0) == 0x80) p++;
|
||||
return 0xFFFD;
|
||||
}
|
||||
|
||||
// Width of a single codepoint in pixels. Default: fall back to getTextWidth
|
||||
// on a one-codepoint UTF-8 string. Drivers can override for O(1) lookup.
|
||||
virtual uint16_t getCodepointWidth(uint32_t cp) {
|
||||
char buf[5];
|
||||
int n = 0;
|
||||
if (cp < 0x80) { buf[n++] = (char)cp; }
|
||||
else if (cp < 0x800) { buf[n++] = 0xC0 | (cp >> 6); buf[n++] = 0x80 | (cp & 0x3F); }
|
||||
else if (cp < 0x10000) { buf[n++] = 0xE0 | (cp >> 12); buf[n++] = 0x80 | ((cp >> 6) & 0x3F); buf[n++] = 0x80 | (cp & 0x3F); }
|
||||
else { buf[n++] = 0xF0 | (cp >> 18); buf[n++] = 0x80 | ((cp >> 12) & 0x3F); buf[n++] = 0x80 | ((cp >> 6) & 0x3F); buf[n++] = 0x80 | (cp & 0x3F); }
|
||||
buf[n] = '\0';
|
||||
return getTextWidth(buf);
|
||||
}
|
||||
|
||||
|
||||
// draw text with ellipsis if it exceeds max_width
|
||||
virtual void drawTextEllipsized(int x, int y, int max_width, const char* str) {
|
||||
char temp_str[256]; // reasonable buffer size
|
||||
|
||||
@@ -114,6 +114,10 @@ public:
|
||||
void drawRect(int x, int y, int w, int h) override;
|
||||
void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override;
|
||||
uint16_t getTextWidth(const char* str) override;
|
||||
uint16_t getCodepointWidth(uint32_t cp) override {
|
||||
if (_use_lemon && _text_sz == 1) return lemonXAdvance(cp, scale());
|
||||
return DisplayDriver::getCodepointWidth(cp);
|
||||
}
|
||||
void setDisplayRotation(uint8_t rot) override;
|
||||
void setFullRefreshInterval(uint8_t n) override { _full_refresh_interval = n; _partial_count = 0; }
|
||||
void endFrame() override;
|
||||
|
||||
@@ -48,6 +48,10 @@ public:
|
||||
void drawRect(int x, int y, int w, int h) override;
|
||||
void drawXbm(int x, int y, const uint8_t *bits, int w, int h) override;
|
||||
uint16_t getTextWidth(const char *str) override;
|
||||
uint16_t getCodepointWidth(uint32_t cp) override {
|
||||
if (_use_lemon) return lemonXAdvance(cp);
|
||||
return 6 * _text_sz; // built-in 5x7 font: 6 px advance per glyph
|
||||
}
|
||||
int getCharWidth() const override { return (_use_lemon ? 5 : 6) * _text_sz; }
|
||||
int getLineHeight() const override { return (_use_lemon ? 9 : 8) * _text_sz; }
|
||||
void setLemonFont(bool enabled) override { _use_lemon = enabled; _vw_dirty = true; }
|
||||
|
||||
Reference in New Issue
Block a user