nuclear@24: /* nuclear@24: libdrawtext - a simple library for fast text rendering in OpenGL nuclear@24: Copyright (C) 2011 John Tsiombikas nuclear@24: nuclear@24: This program is free software: you can redistribute it and/or modify nuclear@24: it under the terms of the GNU Lesser General Public License as published by nuclear@24: the Free Software Foundation, either version 3 of the License, or nuclear@24: (at your option) any later version. nuclear@24: nuclear@24: This program is distributed in the hope that it will be useful, nuclear@24: but WITHOUT ANY WARRANTY; without even the implied warranty of nuclear@24: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nuclear@24: GNU Lesser General Public License for more details. nuclear@24: nuclear@24: You should have received a copy of the GNU Lesser General Public License nuclear@24: along with this program. If not, see . nuclear@24: */ nuclear@24: #include "drawtext.h" nuclear@24: nuclear@24: #define U8_IS_FIRST(x) (((((x) >> 7) & 1) == 0) || ((((x) >> 6) & 3) == 3)) nuclear@24: nuclear@24: static const char first_mask[] = { nuclear@24: 0, nuclear@24: 0x7f, /* single byte, 7 bits valid */ nuclear@24: 0x1f, /* two-bytes, 5 bits valid */ nuclear@24: 0xf, /* three-bytes, 4 bits valid */ nuclear@24: 0x7 /* four-bytes, 3 bits valid */ nuclear@24: }; nuclear@24: static const char first_shift[] = { 0, 7, 5, 4, 3 }; /* see above */ nuclear@24: nuclear@24: #define CONT_PREFIX 0x80 nuclear@24: #define CONT_MASK 0x3f nuclear@24: #define CONT_SHIFT 6 nuclear@24: nuclear@24: /* last charcodes for 1, 2, 3 or 4-byte utf8 chars */ nuclear@24: static const int utf8_lastcode[] = { 0x7f, 0x7ff, 0xfff, 0x1fffff }; nuclear@24: nuclear@24: #define prefix_mask(x) (~first_mask[x]) nuclear@24: #define prefix(x) ((prefix_mask(x) << 1) & 0xff) nuclear@24: nuclear@24: nuclear@24: char *dtx_utf8_next_char(char *str) nuclear@24: { nuclear@24: return str + dtx_utf8_nbytes(str); nuclear@24: } nuclear@24: nuclear@24: int dtx_utf8_char_code(const char *str) nuclear@24: { nuclear@24: int i, nbytes, shift, code = 0; nuclear@24: int mask; nuclear@24: nuclear@24: if(!U8_IS_FIRST(*str)) { nuclear@24: return -1; nuclear@24: } nuclear@24: nuclear@24: nbytes = dtx_utf8_nbytes(str); nuclear@24: mask = first_mask[nbytes]; nuclear@24: shift = 0; nuclear@24: nuclear@24: for(i=0; i> (7 - i)) & 1) == 0) { nuclear@24: break; nuclear@24: } nuclear@24: numset++; nuclear@24: } nuclear@24: nuclear@24: if(!numset) { nuclear@24: return 1; nuclear@24: } nuclear@24: return numset; nuclear@24: } nuclear@24: nuclear@24: int dtx_utf8_char_count(const char *str) nuclear@24: { nuclear@24: int n = 0; nuclear@24: nuclear@24: while(*str) { nuclear@24: n++; nuclear@24: str = dtx_utf8_next_char((char*)str); nuclear@24: } nuclear@24: return n; nuclear@24: } nuclear@24: nuclear@24: size_t dtx_utf8_from_char_code(int code, char *buf) nuclear@24: { nuclear@24: size_t nbytes = 0; nuclear@24: int i; nuclear@24: nuclear@24: for(i=0; i<4; i++) { nuclear@24: if(code <= utf8_lastcode[i]) { nuclear@24: nbytes = i + 1; nuclear@24: break; nuclear@24: } nuclear@24: } nuclear@24: nuclear@24: if(!nbytes && buf) { nuclear@24: for(i=0; i 0) { nuclear@24: mask = CONT_MASK; nuclear@24: shift = CONT_SHIFT; nuclear@24: prefix = CONT_PREFIX; nuclear@24: } else { nuclear@24: mask = first_mask[nbytes]; nuclear@24: shift = first_shift[nbytes]; nuclear@24: prefix = prefix(nbytes); nuclear@24: } nuclear@24: nuclear@24: buf[idx] = (code & mask) | (prefix & ~mask); nuclear@24: code >>= shift; nuclear@24: } nuclear@24: } nuclear@24: return nbytes; nuclear@24: } nuclear@24: nuclear@24: size_t dtx_utf8_from_string(const wchar_t *str, char *buf) nuclear@24: { nuclear@24: size_t nbytes = 0; nuclear@24: char *ptr = buf; nuclear@24: nuclear@24: while(*str) { nuclear@24: int cbytes = dtx_utf8_from_char_code(*str++, ptr); nuclear@24: if(ptr) { nuclear@24: ptr += cbytes; nuclear@24: } nuclear@24: nbytes += cbytes; nuclear@24: } nuclear@24: return nbytes; nuclear@24: }