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