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