mirror of
https://github.com/torlando-tech/pyxis.git
synced 2026-08-25 12:09:49 +00:00
112 lines
3.5 KiB
C++
112 lines
3.5 KiB
C++
#include "NomadNetGlyphs.h"
|
|
#include "../Fonts/NomadNetFontCoverage.h"
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
|
|
namespace UI::LXMF::NomadNet {
|
|
namespace {
|
|
|
|
bool decode_utf8(const std::string& value, std::size_t offset,
|
|
uint32_t& codepoint, std::size_t& length) {
|
|
const auto lead = static_cast<uint8_t>(value[offset]);
|
|
if (lead <= 0x7f) {
|
|
codepoint = lead;
|
|
length = 1;
|
|
return true;
|
|
}
|
|
|
|
std::size_t continuation = 0;
|
|
if (lead >= 0xc2 && lead <= 0xdf) {
|
|
codepoint = lead & 0x1f;
|
|
continuation = 1;
|
|
} else if (lead >= 0xe0 && lead <= 0xef) {
|
|
codepoint = lead & 0x0f;
|
|
continuation = 2;
|
|
} else if (lead >= 0xf0 && lead <= 0xf4) {
|
|
codepoint = lead & 0x07;
|
|
continuation = 3;
|
|
} else {
|
|
length = 1;
|
|
return false;
|
|
}
|
|
|
|
length = continuation + 1;
|
|
if (offset + length > value.size()) {
|
|
length = 1;
|
|
return false;
|
|
}
|
|
for (std::size_t i = 1; i <= continuation; ++i) {
|
|
const auto byte = static_cast<uint8_t>(value[offset + i]);
|
|
if ((byte & 0xc0) != 0x80) {
|
|
length = 1;
|
|
return false;
|
|
}
|
|
codepoint = (codepoint << 6) | (byte & 0x3f);
|
|
}
|
|
if ((continuation == 1 && codepoint < 0x80) ||
|
|
(continuation == 2 && codepoint < 0x800) ||
|
|
(continuation == 3 && codepoint < 0x10000) ||
|
|
(codepoint >= 0xd800 && codepoint <= 0xdfff) ||
|
|
codepoint > 0x10ffff) {
|
|
length = 1;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
std::size_t display_codepoint(uint32_t codepoint, char utf8[5]) {
|
|
if (!nomadnet_font_has_codepoint(codepoint) || codepoint > 0x10ffff ||
|
|
(codepoint >= 0xd800 && codepoint <= 0xdfff)) {
|
|
utf8[0] = '?';
|
|
utf8[1] = '\0';
|
|
return 1;
|
|
}
|
|
std::size_t length = 0;
|
|
if (codepoint <= 0x7f) {
|
|
utf8[length++] = static_cast<char>(codepoint);
|
|
} else if (codepoint <= 0x7ff) {
|
|
utf8[length++] = static_cast<char>(0xc0 | (codepoint >> 6));
|
|
utf8[length++] = static_cast<char>(0x80 | (codepoint & 0x3f));
|
|
} else if (codepoint <= 0xffff) {
|
|
utf8[length++] = static_cast<char>(0xe0 | (codepoint >> 12));
|
|
utf8[length++] = static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f));
|
|
utf8[length++] = static_cast<char>(0x80 | (codepoint & 0x3f));
|
|
} else {
|
|
utf8[length++] = static_cast<char>(0xf0 | (codepoint >> 18));
|
|
utf8[length++] = static_cast<char>(0x80 | ((codepoint >> 12) & 0x3f));
|
|
utf8[length++] = static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f));
|
|
utf8[length++] = static_cast<char>(0x80 | (codepoint & 0x3f));
|
|
}
|
|
utf8[length] = '\0';
|
|
return length;
|
|
}
|
|
|
|
void visit_display_text(const std::string& utf8, DisplayTextVisitor visitor, void* context) {
|
|
static const char replacement = '?';
|
|
for (std::size_t offset = 0; offset < utf8.size();) {
|
|
uint32_t codepoint = 0;
|
|
std::size_t length = 1;
|
|
if (!decode_utf8(utf8, offset, codepoint, length) ||
|
|
!nomadnet_font_has_codepoint(codepoint)) {
|
|
visitor(&replacement, 1, context);
|
|
} else {
|
|
visitor(utf8.data() + offset, length, context);
|
|
}
|
|
offset += length;
|
|
}
|
|
}
|
|
|
|
std::string display_text(const std::string& utf8) {
|
|
std::string output;
|
|
output.reserve(utf8.size());
|
|
visit_display_text(utf8, [](const char* bytes, std::size_t length, void* context) {
|
|
static_cast<std::string*>(context)->append(bytes, length);
|
|
}, &output);
|
|
return output;
|
|
}
|
|
|
|
} // namespace UI::LXMF::NomadNet
|