/* * Copyright (C) 2021 Mikhail Burakov. This file is part of Pui. * * Pui is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Pui is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Pui. If not, see <https://www.gnu.org/licenses/>. */ #include "font.h" extern uint32_t kCp00[256 * 3]; extern uint32_t kCp04[256 * 3]; static int GetUnicode(const char** str) { const char* character = *str; if ((character[0] & 0xf8) == 0xf0 && (character[1] & 0xc0) == 0x80 && (character[2] & 0xc0) == 0x80 && (character[3] & 0xc0) == 0x80) { (*str) += 4; return ((character[0] & 0x07) << 18) | ((character[1] & 0x3f) << 12) | ((character[2] & 0x3f) << 6) | (character[3] & 0x3f); } if ((character[0] & 0xf0) == 0xe0 && (character[1] & 0xc0) == 0x80 && (character[2] & 0xc0) == 0x80) { (*str) += 3; return ((character[0] & 0x0f) << 12) | ((character[1] & 0x3f) << 6) | (character[2] & 0x3f); } if ((character[0] & 0xe0) == 0xc0 && (character[1] & 0xc0) == 0x80) { (*str) += 2; return ((character[0] & 0x1f) << 6) | (character[1] & 0x3f); } if ((character[0] & 0x80) == 0x00) { (*str) += 1; return character[0]; } return -1; } static size_t GlyphWidth(int point) { const uint32_t* page; switch (point >> 8) { case 0: if (point == 0x20) return 4; page = kCp00; break; case 4: page = kCp04; point &= 0xff; break; default: return 0; } uint32_t glyph = page[point * 3]; return (glyph >> 24) + 1; } static void BlockRender(uint32_t block, uint32_t* buffer, size_t stride, uint32_t color) { for (size_t counter = 31; block; block >>= 1, counter--) { if (!(block & 1)) continue; size_t x = counter & 0x7u; size_t y = counter >> 3u; buffer[x + y * stride] = color; } } static void GlyphRender(int point, uint32_t* buffer, size_t stride, uint32_t color) { const uint32_t* page; switch (point >> 8) { case 0: if (point == 0x20) return; page = kCp00; break; case 4: page = kCp04; point &= 0xff; break; default: return; } const uint32_t* glyph = page + point * 3; BlockRender(glyph[2], buffer + stride * 7, stride, color); BlockRender(glyph[1], buffer + stride * 3, stride, color); BlockRender(glyph[0] & 0xffffff, buffer - stride, stride, color); } size_t PuiStringWidth(const char* str) { size_t result = 0; for (;;) { int cp = GetUnicode(&str); if (cp < 1) break; result += GlyphWidth(cp); } return result; } size_t PuiStringCut(const char* str, size_t width) { size_t result = 0; for (size_t current = 0;;) { const char* before = str; int cp = GetUnicode(&str); if (cp < 1) break; current += GlyphWidth(cp); if (current >= width) break; result += (size_t)(str - before); } return result; } void PuiStringRender(const char* str, void* buffer, size_t stride, uint32_t color) { for (uint32_t* ptr = buffer;;) { int cp = GetUnicode(&str); if (cp < 1) break; GlyphRender(cp, ptr, stride, color); ptr += GlyphWidth(cp); } }