#include "../ui.h"
#include "uipriv.h"
#include "attrstr.h"
struct uiAttributedString {
char *s;
size_t len;
uiprivAttrList *attrs;
uint16_t *u16;
size_t u16len;
size_t *u8tou16;
size_t *u16tou8;
uiprivGraphemes *graphemes;
};
static void resize(uiAttributedString *s, size_t u8, size_t u16)
{
s->len = u8;
s->s = (char *) uiprivRealloc(s->s, (s->len + 1) * sizeof (char), "char[] (uiAttributedString)");
s->u8tou16 = (size_t *) uiprivRealloc(s->u8tou16, (s->len + 1) * sizeof (size_t), "size_t[] (uiAttributedString)");
s->u16len = u16;
s->u16 = (uint16_t *) uiprivRealloc(s->u16, (s->u16len + 1) * sizeof (uint16_t), "uint16_t[] (uiAttributedString)");
s->u16tou8 = (size_t *) uiprivRealloc(s->u16tou8, (s->u16len + 1) * sizeof (size_t), "size_t[] (uiAttributedString)");
}
uiAttributedString *uiNewAttributedString(const char *initialString)
{
uiAttributedString *s;
s = uiprivNew(uiAttributedString);
s->attrs = uiprivNewAttrList();
uiAttributedStringAppendUnattributed(s, initialString);
return s;
}
static void recomputeGraphemes(uiAttributedString *s)
{
if (s->graphemes != NULL)
return;
if (uiprivGraphemesTakesUTF16()) {
s->graphemes = uiprivNewGraphemes(s->u16, s->u16len);
return;
}
s->graphemes = uiprivNewGraphemes(s->s, s->len);
}
static void invalidateGraphemes(uiAttributedString *s)
{
if (s->graphemes == NULL)
return;
uiprivFree(s->graphemes->pointsToGraphemes);
uiprivFree(s->graphemes->graphemesToPoints);
uiprivFree(s->graphemes);
s->graphemes = NULL;
}
void uiFreeAttributedString(uiAttributedString *s)
{
uiprivFreeAttrList(s->attrs);
invalidateGraphemes(s);
uiprivFree(s->u16tou8);
uiprivFree(s->u8tou16);
uiprivFree(s->u16);
uiprivFree(s->s);
uiprivFree(s);
}
const char *uiAttributedStringString(const uiAttributedString *s)
{
return s->s;
}
size_t uiAttributedStringLen(const uiAttributedString *s)
{
return s->len;
}
static void u8u16len(const char *str, size_t *n8, size_t *n16)
{
uint32_t rune;
char buf[4];
uint16_t buf16[2];
*n8 = 0;
*n16 = 0;
while (*str) {
str = uiprivUTF8DecodeRune(str, 0, &rune);
*n8 += uiprivUTF8EncodeRune(rune, buf);
*n16 += uiprivUTF16EncodeRune(rune, buf16);
}
}
void uiAttributedStringAppendUnattributed(uiAttributedString *s, const char *str)
{
uiAttributedStringInsertAtUnattributed(s, str, s->len);
}
static int onCodepointBoundary(uiAttributedString *s, size_t at)
{
uint8_t c;
if (s->s == NULL && at == 0)
return 1;
c = (uint8_t) (s->s[at]);
return c < 0x80 || c >= 0xC0;
}
void uiAttributedStringInsertAtUnattributed(uiAttributedString *s, const char *str, size_t at)
{
uint32_t rune;
char buf[4];
uint16_t buf16[2];
size_t n8, n16; size_t old, old16;
size_t oldn8, oldn16;
size_t oldlen, old16len;
size_t at16;
size_t i;
if (!onCodepointBoundary(s, at)) {
}
at16 = 0;
if (s->u8tou16 != NULL)
at16 = s->u8tou16[at];
invalidateGraphemes(s);
u8u16len(str, &n8, &n16);
old = at;
old16 = at16;
oldlen = s->len;
old16len = s->u16len;
resize(s, s->len + n8, s->u16len + n16);
memmove(
s->s + at + n8,
s->s + at,
(oldlen - at) * sizeof (char));
memmove(
s->u16 + at16 + n16,
s->u16 + at16,
(old16len - at16) * sizeof (uint16_t));
memmove(
s->u8tou16 + at + n8,
s->u8tou16 + at,
(oldlen - at + 1) * sizeof (size_t));
memmove(
s->u16tou8 + at16 + n16,
s->u16tou8 + at16,
(old16len - at16 + 1) * sizeof (size_t));
oldn8 = n8;
oldn16 = n16;
while (*str) {
size_t n;
str = uiprivUTF8DecodeRune(str, 0, &rune);
n = uiprivUTF8EncodeRune(rune, buf);
n16 = uiprivUTF16EncodeRune(rune, buf16);
s->s[old] = buf[0];
s->u8tou16[old] = old16;
if (n > 1) {
s->s[old + 1] = buf[1];
s->u8tou16[old + 1] = old16;
}
if (n > 2) {
s->s[old + 2] = buf[2];
s->u8tou16[old + 2] = old16;
}
if (n > 3) {
s->s[old + 3] = buf[3];
s->u8tou16[old + 3] = old16;
}
s->u16[old16] = buf16[0];
s->u16tou8[old16] = old;
if (n16 > 1) {
s->u16[old16 + 1] = buf16[1];
s->u16tou8[old16 + 1] = old;
}
old += n;
old16 += n16;
}
for (i = 0; i <= oldlen - at; i++)
s->u8tou16[at + oldn8 + i] += s->u16len - old16len;
for (i = 0; i <= old16len - at16; i++)
s->u16tou8[at16 + oldn16 + i] += s->len - oldlen;
uiprivAttrListInsertCharactersUnattributed(s->attrs, at, n8);
}
void uiAttributedStringDelete(uiAttributedString *s, size_t start, size_t end)
{
size_t start16, end16;
size_t count, count16;
size_t i;
if (!onCodepointBoundary(s, start)) {
}
if (!onCodepointBoundary(s, end)) {
}
count = end - start;
start16 = s->u8tou16[start];
end16 = s->u8tou16[end];
count16 = end16 - start16;
invalidateGraphemes(s);
memmove(
s->s + start,
s->s + end,
(s->len - end) * sizeof (char));
memmove(
s->u16 + start16,
s->u16 + end16,
(s->u16len - end16) * sizeof (uint16_t));
memmove(
s->u8tou16 + start,
s->u8tou16 + end,
(s->len - end + 1) * sizeof (size_t));
memmove(
s->u16tou8 + start16,
s->u16tou8 + end16,
(s->u16len - end16 + 1) * sizeof (size_t));
for (i = 0; i <= count; i++)
s->u8tou16[start + i] -= count16;
for (i = 0; i <= count16; i++)
s->u16tou8[start16 + i] -= count;
s->s[start + count] = 0;
s->u16[start16 + count16] = 0;
uiprivAttrListRemoveCharacters(s->attrs, start, end);
resize(s, start + count, start16 + count16);
}
void uiAttributedStringSetAttribute(uiAttributedString *s, uiAttribute *a, size_t start, size_t end)
{
uiprivAttrListInsertAttribute(s->attrs, a, start, end);
}
void uiAttributedStringForEachAttribute(const uiAttributedString *s, uiAttributedStringForEachAttributeFunc f, void *data)
{
uiprivAttrListForEach(s->attrs, s, f, data);
}
size_t uiAttributedStringNumGraphemes(uiAttributedString *s)
{
recomputeGraphemes(s);
return s->graphemes->len;
}
size_t uiAttributedStringByteIndexToGrapheme(uiAttributedString *s, size_t pos)
{
recomputeGraphemes(s);
if (uiprivGraphemesTakesUTF16())
pos = s->u8tou16[pos];
return s->graphemes->pointsToGraphemes[pos];
}
size_t uiAttributedStringGraphemeToByteIndex(uiAttributedString *s, size_t pos)
{
recomputeGraphemes(s);
pos = s->graphemes->graphemesToPoints[pos];
if (uiprivGraphemesTakesUTF16())
pos = s->u16tou8[pos];
return pos;
}
const uint16_t *uiprivAttributedStringUTF16String(const uiAttributedString *s)
{
return s->u16;
}
size_t uiprivAttributedStringUTF16Len(const uiAttributedString *s)
{
return s->u16len;
}
size_t uiprivAttributedStringUTF8ToUTF16(const uiAttributedString *s, size_t n)
{
return s->u8tou16[n];
}
size_t *uiprivAttributedStringCopyUTF8ToUTF16Table(const uiAttributedString *s, size_t *n)
{
size_t *out;
size_t nbytes;
nbytes = (s->len + 1) * sizeof (size_t);
*n = s->len;
out = (size_t *) uiprivAlloc(nbytes, "size_t[] (uiAttributedString)");
memmove(out, s->u8tou16, nbytes);
return out;
}
size_t *uiprivAttributedStringCopyUTF16ToUTF8Table(const uiAttributedString *s, size_t *n)
{
size_t *out;
size_t nbytes;
nbytes = (s->u16len + 1) * sizeof (size_t);
*n = s->u16len;
out = (size_t *) uiprivAlloc(nbytes, "size_t[] (uiAttributedString)");
memmove(out, s->u16tou8, nbytes);
return out;
}