mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-08-06 12:16:11 +00:00
refactor(ui): dedupe UTF-8 codepoint decoder
Three copies of the same routine: DisplayDriver::decodeCodepoint (added in the FullscreenMsgView wrap fix) plus per-driver duplicates in SH1106Display and GxEPDDisplay. Consolidate on DisplayDriver and have translateUTF8Static also route through it instead of its own inline decoder. Net: 63 lines removed, single source of truth. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
74764aed2b
commit
52a7081a13
@@ -134,23 +134,12 @@ public:
|
|||||||
size_t j = 0;
|
size_t j = 0;
|
||||||
const uint8_t* p = (const uint8_t*)src;
|
const uint8_t* p = (const uint8_t*)src;
|
||||||
while (*p && j < dest_size - 1) {
|
while (*p && j < dest_size - 1) {
|
||||||
uint8_t c = *p++;
|
if (*p < 0x80) {
|
||||||
if (c < 0x80) {
|
uint8_t c = *p++;
|
||||||
if (c >= 32) dest[j++] = c;
|
if (c >= 32) dest[j++] = c;
|
||||||
} else {
|
} else {
|
||||||
uint32_t cp = c;
|
uint32_t cp = decodeCodepoint(p);
|
||||||
if ((c & 0xE0) == 0xC0) {
|
// transliterateCodepoint already returns '\xDB' for unmapped values (incl. 0xFFFD).
|
||||||
cp = c & 0x1F;
|
|
||||||
if (*p) cp = (cp << 6) | (*p++ & 0x3F);
|
|
||||||
} else if ((c & 0xF0) == 0xE0) {
|
|
||||||
cp = c & 0x0F;
|
|
||||||
if (*p) cp = (cp << 6) | (*p++ & 0x3F);
|
|
||||||
if (*p) cp = (cp << 6) | (*p++ & 0x3F);
|
|
||||||
} else {
|
|
||||||
while (*p && (*p & 0xC0) == 0x80) p++;
|
|
||||||
dest[j++] = '\xDB';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
dest[j++] = transliterateCodepoint(cp);
|
dest[j++] = transliterateCodepoint(cp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,31 +23,6 @@ static int fontAscender(int sz, bool use_lemon, int scale) {
|
|||||||
return 0; // GFX built-in font: cursor is top-left of cell
|
return 0; // GFX built-in font: cursor is top-left of cell
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t GxEPDDisplay::decodeUtf8(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// y is the GFX baseline (display.getCursorY()), which equals original_y + 8*sc.
|
// y is the GFX baseline (display.getCursorY()), which equals original_y + 8*sc.
|
||||||
// Pixels are placed at y + yo*sc + row*sc — identical to how GFX would render
|
// Pixels are placed at y + yo*sc + row*sc — identical to how GFX would render
|
||||||
// a scaled GFX font, but bypassing GFX so multi-byte UTF-8 is decoded correctly.
|
// a scaled GFX font, but bypassing GFX so multi-byte UTF-8 is decoded correctly.
|
||||||
@@ -209,7 +184,7 @@ void GxEPDDisplay::print(const char* str) {
|
|||||||
const int sc = scale();
|
const int sc = scale();
|
||||||
const uint8_t* p = (const uint8_t*)str;
|
const uint8_t* p = (const uint8_t*)str;
|
||||||
while (*p) {
|
while (*p) {
|
||||||
uint32_t cp = decodeUtf8(p);
|
uint32_t cp = decodeCodepoint(p);
|
||||||
if (cp == '\n') { cy += Lemon.yAdvance * sc; cx = 0; }
|
if (cp == '\n') { cy += Lemon.yAdvance * sc; cx = 0; }
|
||||||
else { cx = drawLemonChar(cx, cy, cp, sc); }
|
else { cx = drawLemonChar(cx, cy, cp, sc); }
|
||||||
}
|
}
|
||||||
@@ -271,7 +246,7 @@ uint16_t GxEPDDisplay::getTextWidth(const char* str) {
|
|||||||
uint16_t total = 0;
|
uint16_t total = 0;
|
||||||
const int sc = scale();
|
const int sc = scale();
|
||||||
const uint8_t* p = (const uint8_t*)str;
|
const uint8_t* p = (const uint8_t*)str;
|
||||||
while (*p) total += lemonXAdvance(decodeUtf8(p), sc);
|
while (*p) total += lemonXAdvance(decodeCodepoint(p), sc);
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
display.setTextWrap(false);
|
display.setTextWrap(false);
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ class GxEPDDisplay : public DisplayDriver {
|
|||||||
uint8_t _full_refresh_interval = 0;
|
uint8_t _full_refresh_interval = 0;
|
||||||
uint8_t _partial_count = 0;
|
uint8_t _partial_count = 0;
|
||||||
|
|
||||||
static uint32_t decodeUtf8(const uint8_t*& p);
|
|
||||||
int16_t drawLemonChar(int16_t x, int16_t y, uint32_t cp, int sc);
|
int16_t drawLemonChar(int16_t x, int16_t y, uint32_t cp, int sc);
|
||||||
uint8_t lemonXAdvance(uint32_t cp, int sc);
|
uint8_t lemonXAdvance(uint32_t cp, int sc);
|
||||||
int scale() const { return (width() >= height()) ? 2 : 1; }
|
int scale() const { return (width() >= height()) ? 2 : 1; }
|
||||||
|
|||||||
@@ -65,31 +65,6 @@ void SH1106Display::setCursor(int x, int y)
|
|||||||
display.setCursor(x, y);
|
display.setCursor(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t SH1106Display::decodeUtf8(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t SH1106Display::drawLemonChar(int16_t x, int16_t y, uint32_t cp) {
|
int16_t SH1106Display::drawLemonChar(int16_t x, int16_t y, uint32_t cp) {
|
||||||
int sz = _text_sz;
|
int sz = _text_sz;
|
||||||
for (uint8_t i = 0; i < lemonIconCount; i++) {
|
for (uint8_t i = 0; i < lemonIconCount; i++) {
|
||||||
@@ -161,7 +136,7 @@ void SH1106Display::print(const char *str)
|
|||||||
int16_t cy = display.getCursorY();
|
int16_t cy = display.getCursorY();
|
||||||
const uint8_t* p = (const uint8_t*)str;
|
const uint8_t* p = (const uint8_t*)str;
|
||||||
while (*p) {
|
while (*p) {
|
||||||
uint32_t cp = decodeUtf8(p);
|
uint32_t cp = decodeCodepoint(p);
|
||||||
if (cp == '\n') { cy += Lemon.yAdvance; cx = 0; }
|
if (cp == '\n') { cy += Lemon.yAdvance; cx = 0; }
|
||||||
else { cx = drawLemonChar(cx, cy, cp); }
|
else { cx = drawLemonChar(cx, cy, cp); }
|
||||||
}
|
}
|
||||||
@@ -188,7 +163,7 @@ uint16_t SH1106Display::getTextWidth(const char *str)
|
|||||||
if (_use_lemon) {
|
if (_use_lemon) {
|
||||||
uint16_t width = 0;
|
uint16_t width = 0;
|
||||||
const uint8_t* p = (const uint8_t*)str;
|
const uint8_t* p = (const uint8_t*)str;
|
||||||
while (*p) width += lemonXAdvance(decodeUtf8(p));
|
while (*p) width += lemonXAdvance(decodeCodepoint(p));
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
int16_t x1, y1;
|
int16_t x1, y1;
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ class SH1106Display : public DisplayDriver
|
|||||||
int _text_sz;
|
int _text_sz;
|
||||||
|
|
||||||
bool i2c_probe(TwoWire &wire, uint8_t addr);
|
bool i2c_probe(TwoWire &wire, uint8_t addr);
|
||||||
static uint32_t decodeUtf8(const uint8_t*& p);
|
|
||||||
int16_t drawLemonChar(int16_t x, int16_t y, uint32_t cp);
|
int16_t drawLemonChar(int16_t x, int16_t y, uint32_t cp);
|
||||||
uint8_t lemonXAdvance(uint32_t cp);
|
uint8_t lemonXAdvance(uint32_t cp);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user