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