Changed the representation of an attribute type/value pair to allow more type safety and expressability.
This commit is contained in:
parent
1c1b16a206
commit
261dd4851a
|
@ -12,8 +12,7 @@ The linked list is not a ring; alist->fist->prev == NULL and alist->last->next =
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct attr {
|
struct attr {
|
||||||
uiAttribute type;
|
uiAttributeSpec spec;
|
||||||
uintptr_t val;
|
|
||||||
size_t start;
|
size_t start;
|
||||||
size_t end;
|
size_t end;
|
||||||
struct attr *prev;
|
struct attr *prev;
|
||||||
|
@ -178,8 +177,7 @@ static struct attr *attrDropRange(struct attrlist *alist, struct attr *a, size_t
|
||||||
|
|
||||||
// we'll need to split the attribute into two
|
// we'll need to split the attribute into two
|
||||||
b = uiNew(struct attr);
|
b = uiNew(struct attr);
|
||||||
b->type = a->type;
|
b->spec = a->spec;
|
||||||
b->val = a->val;
|
|
||||||
b->start = end;
|
b->start = end;
|
||||||
b->end = a->end;
|
b->end = a->end;
|
||||||
*tail = b;
|
*tail = b;
|
||||||
|
@ -223,8 +221,7 @@ static struct attr *attrSplitAt(struct attrlist *alist, struct attr *a, size_t a
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
b = uiNew(struct attr);
|
b = uiNew(struct attr);
|
||||||
b->type = a->type;
|
b->spec = a->spec;
|
||||||
b->val = a->val;
|
|
||||||
b->start = at;
|
b->start = at;
|
||||||
b->end = a->end;
|
b->end = a->end;
|
||||||
|
|
||||||
|
@ -287,7 +284,24 @@ static struct attr *attrDeleteRange(struct attrlist *alist, struct attr *a, size
|
||||||
return a->next;
|
return a->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
void attrlistInsertAttribute(struct attrlist *alist, uiAttribute type, uintptr_t val, size_t start, size_t end)
|
static int specsIdentical(struct attr *attr, uiAttributeSpec *spec)
|
||||||
|
{
|
||||||
|
if (attr->spec.Type != spec->Type)
|
||||||
|
return 0;
|
||||||
|
switch (attr->spec.Type) {
|
||||||
|
case uiAttributeFamily:
|
||||||
|
// TODO should we start copying these strings?
|
||||||
|
return strcmp((char *) (attr->spec.Value), (char *) (spec->Value)) == 0;
|
||||||
|
case uiAttributeSize:
|
||||||
|
// TODO use a closest match?
|
||||||
|
return attr->spec.Double == spec->Double;
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
// handles the rest
|
||||||
|
return attr->spec.Value == spec->Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void attrlistInsertAttribute(struct attrlist *alist, uiAttributeSpec *spec, size_t start, size_t end)
|
||||||
{
|
{
|
||||||
struct attr *a;
|
struct attr *a;
|
||||||
struct attr *before;
|
struct attr *before;
|
||||||
|
@ -309,7 +323,7 @@ void attrlistInsertAttribute(struct attrlist *alist, uiAttribute type, uintptr_t
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
// should we split this?
|
// should we split this?
|
||||||
if (before->type != type)
|
if (before->spec.Type != spec->Type)
|
||||||
goto next;
|
goto next;
|
||||||
lstart = start;
|
lstart = start;
|
||||||
lend = end;
|
lend = end;
|
||||||
|
@ -317,10 +331,8 @@ void attrlistInsertAttribute(struct attrlist *alist, uiAttribute type, uintptr_t
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
// okay so this might conflict; if the val is the same as the one we want, we need to expand the existing attribute, not fragment anything
|
// okay so this might conflict; if the val is the same as the one we want, we need to expand the existing attribute, not fragment anything
|
||||||
// TODO this might cause problems with system specific attributes, if we support those; maybe also user-specific?
|
|
||||||
// TODO will this cause problems with fonts?
|
|
||||||
// TODO will this reduce fragmentation if we first add from 0 to 2 and then from 2 to 4? or do we have to do that separately?
|
// TODO will this reduce fragmentation if we first add from 0 to 2 and then from 2 to 4? or do we have to do that separately?
|
||||||
if (before->val == val) {
|
if (specsIdentical(before, spec)) {
|
||||||
attrGrow(alist, before, start, end);
|
attrGrow(alist, before, start, end);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -335,8 +347,7 @@ void attrlistInsertAttribute(struct attrlist *alist, uiAttribute type, uintptr_t
|
||||||
|
|
||||||
// if we got here, we know we have to add the attribute before before
|
// if we got here, we know we have to add the attribute before before
|
||||||
a = uiNew(struct attr);
|
a = uiNew(struct attr);
|
||||||
a->type = type;
|
a->spec = *spec;
|
||||||
a->val = val;
|
|
||||||
a->start = start;
|
a->start = start;
|
||||||
a->end = end;
|
a->end = end;
|
||||||
attrInsertBefore(alist, a, before);
|
attrInsertBefore(alist, a, before);
|
||||||
|
@ -498,7 +509,7 @@ void attrlistRemoveAttribute(struct attrlist *alist, uiAttribute type, size_t st
|
||||||
// and at this point we're done, so
|
// and at this point we're done, so
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (a->type != type)
|
if (a->spec.Type != type)
|
||||||
goto next;
|
goto next;
|
||||||
lstart = start;
|
lstart = start;
|
||||||
lend = end;
|
lend = end;
|
||||||
|
@ -587,7 +598,7 @@ void attrlistForEach(struct attrlist *alist, uiAttributedString *s, uiAttributed
|
||||||
for (a = alist->first; a != NULL; a = a->next)
|
for (a = alist->first; a != NULL; a = a->next)
|
||||||
// TODO document this
|
// TODO document this
|
||||||
// TODO should this be return 0 to break?
|
// TODO should this be return 0 to break?
|
||||||
if ((*f)(s, a->type, a->val, a->start, a->end, data))
|
if ((*f)(s, &(a->spec), a->start, a->end, data))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -297,9 +297,9 @@ size_t uiAttributedStringGraphemeToByteIndex(uiAttributedString *s, size_t pos)
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiAttributedStringSetAttribute(uiAttributedString *s, uiAttribute type, uintptr_t value, size_t start, size_t end)
|
void uiAttributedStringSetAttribute(uiAttributedString *s, uiAttributeSpec *spec, size_t start, size_t end)
|
||||||
{
|
{
|
||||||
attrlistInsertAttribute(s->attrs, type, value, start, end);
|
attrlistInsertAttribute(s->attrs, spec, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO introduce an iterator?
|
// TODO introduce an iterator?
|
||||||
|
|
|
@ -78,7 +78,7 @@ extern size_t *attrstrCopyUTF16ToUTF8(uiAttributedString *s, size_t *n);
|
||||||
|
|
||||||
// attrlist.c
|
// attrlist.c
|
||||||
struct attrlist;
|
struct attrlist;
|
||||||
extern void attrlistInsertAttribute(struct attrlist *alist, uiAttribute type, uintptr_t val, size_t start, size_t end);
|
extern void attrlistInsertAttribute(struct attrlist *alist, uiAttributeSpec *spec, size_t start, size_t end);
|
||||||
extern void attrlistInsertCharactersUnattributed(struct attrlist *alist, size_t start, size_t count);
|
extern void attrlistInsertCharactersUnattributed(struct attrlist *alist, size_t start, size_t count);
|
||||||
extern void attrlistInsertCharactersExtendingAttributes(struct attrlist *alist, size_t start, size_t count);
|
extern void attrlistInsertCharactersExtendingAttributes(struct attrlist *alist, size_t start, size_t count);
|
||||||
extern void attrlistRemoveAttribute(struct attrlist *alist, uiAttribute type, size_t start, size_t end);
|
extern void attrlistRemoveAttribute(struct attrlist *alist, uiAttribute type, size_t start, size_t end);
|
||||||
|
|
|
@ -40,41 +40,41 @@ static void adjustFontInRange(struct foreachParams *p, size_t start, size_t end,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int processAttribute(uiAttributedString *s, uiAttribute type, uintptr_t value, size_t start, size_t end, void *data)
|
static int processAttribute(uiAttributedString *s, uiAttributeSpec *spec, size_t start, size_t end, void *data)
|
||||||
{
|
{
|
||||||
struct foreachParams *p = (struct foreachParams *) data;
|
struct foreachParams *p = (struct foreachParams *) data;
|
||||||
|
|
||||||
start = attrstrUTF8ToUTF16(s, start);
|
start = attrstrUTF8ToUTF16(s, start);
|
||||||
end = attrstrUTF8ToUTF16(s, end);
|
end = attrstrUTF8ToUTF16(s, end);
|
||||||
switch (type) {
|
switch (spec->Type) {
|
||||||
case uiAttributeFamily:
|
case uiAttributeFamily:
|
||||||
ensureFontInRange(p, start, end);
|
ensureFontInRange(p, start, end);
|
||||||
adjustFontInRange(p, start, end, ^(uiDrawFontDescriptor *desc) {
|
adjustFontInRange(p, start, end, ^(uiDrawFontDescriptor *desc) {
|
||||||
desc->Family = (char *) value;
|
desc->Family = (char *) (spec->Value);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case uiAttributeSize:
|
case uiAttributeSize:
|
||||||
ensureFontInRange(p, start, end);
|
ensureFontInRange(p, start, end);
|
||||||
adjustFontInRange(p, start, end, ^(uiDrawFontDescriptor *desc) {
|
adjustFontInRange(p, start, end, ^(uiDrawFontDescriptor *desc) {
|
||||||
desc->Size = *((double *) value);
|
desc->Size = spec->Double;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case uiAttributeWeight:
|
case uiAttributeWeight:
|
||||||
ensureFontInRange(p, start, end);
|
ensureFontInRange(p, start, end);
|
||||||
adjustFontInRange(p, start, end, ^(uiDrawFontDescriptor *desc) {
|
adjustFontInRange(p, start, end, ^(uiDrawFontDescriptor *desc) {
|
||||||
desc->Weight = (uiDrawTextWeight) value;
|
desc->Weight = (uiDrawTextWeight) (spec->Value);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case uiAttributeItalic:
|
case uiAttributeItalic:
|
||||||
ensureFontInRange(p, start, end);
|
ensureFontInRange(p, start, end);
|
||||||
adjustFontInRange(p, start, end, ^(uiDrawFontDescriptor *desc) {
|
adjustFontInRange(p, start, end, ^(uiDrawFontDescriptor *desc) {
|
||||||
desc->Italic = (uiDrawTextItalic) value;
|
desc->Italic = (uiDrawTextItalic) (spec->Value);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case uiAttributeStretch:
|
case uiAttributeStretch:
|
||||||
ensureFontInRange(p, start, end);
|
ensureFontInRange(p, start, end);
|
||||||
adjustFontInRange(p, start, end, ^(uiDrawFontDescriptor *desc) {
|
adjustFontInRange(p, start, end, ^(uiDrawFontDescriptor *desc) {
|
||||||
desc->Stretch = (uiDrawTextStretch) value;
|
desc->Stretch = (uiDrawTextStretch) (spec->Value);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
// TODO
|
// TODO
|
||||||
|
|
|
@ -5,6 +5,7 @@ static uiAttributedString *attrstr;
|
||||||
|
|
||||||
static void setupAttributedString(void)
|
static void setupAttributedString(void)
|
||||||
{
|
{
|
||||||
|
uiAttributeSpec spec;
|
||||||
size_t start, end;
|
size_t start, end;
|
||||||
const char *next;
|
const char *next;
|
||||||
|
|
||||||
|
@ -14,22 +15,20 @@ static void setupAttributedString(void)
|
||||||
start = uiAttributedStringLen(attrstr);
|
start = uiAttributedStringLen(attrstr);
|
||||||
end = start + strlen(next);
|
end = start + strlen(next);
|
||||||
uiAttributedStringAppendUnattributed(attrstr, next);
|
uiAttributedStringAppendUnattributed(attrstr, next);
|
||||||
uiAttributedStringSetAttribute(attrstr,
|
spec.Type = uiAttributeFamily;
|
||||||
uiAttributeFamily,
|
spec.Value = (uintptr_t) "Courier New";
|
||||||
(uintptr_t) "Courier New",
|
uiAttributedStringSetAttribute(attrstr, &spec, start, end);
|
||||||
start, end);
|
|
||||||
|
|
||||||
uiAttributedStringAppendUnattributed(attrstr, ", ");
|
uiAttributedStringAppendUnattributed(attrstr, ", ");
|
||||||
|
|
||||||
next = "multiple sizes";
|
next = "multiple sizes";
|
||||||
static double eighteen = 18;
|
|
||||||
start = uiAttributedStringLen(attrstr);
|
start = uiAttributedStringLen(attrstr);
|
||||||
end = start + strlen(next);
|
end = start + strlen(next);
|
||||||
uiAttributedStringAppendUnattributed(attrstr, next);
|
uiAttributedStringAppendUnattributed(attrstr, next);
|
||||||
|
spec.Type = uiAttributeSize;
|
||||||
|
spec.Double = 18;
|
||||||
uiAttributedStringSetAttribute(attrstr,
|
uiAttributedStringSetAttribute(attrstr,
|
||||||
uiAttributeSize,
|
&spec, start, end);
|
||||||
(uintptr_t) (&eighteen),
|
|
||||||
start, end);
|
|
||||||
|
|
||||||
uiAttributedStringAppendUnattributed(attrstr, ", ");
|
uiAttributedStringAppendUnattributed(attrstr, ", ");
|
||||||
|
|
||||||
|
@ -37,10 +36,9 @@ static void setupAttributedString(void)
|
||||||
start = uiAttributedStringLen(attrstr);
|
start = uiAttributedStringLen(attrstr);
|
||||||
end = start + strlen(next);
|
end = start + strlen(next);
|
||||||
uiAttributedStringAppendUnattributed(attrstr, next);
|
uiAttributedStringAppendUnattributed(attrstr, next);
|
||||||
uiAttributedStringSetAttribute(attrstr,
|
spec.Type = uiAttributeWeight;
|
||||||
uiAttributeWeight,
|
spec.Value = (uintptr_t) uiDrawTextWeightBold;
|
||||||
(uintptr_t) uiDrawTextWeightBold,
|
uiAttributedStringSetAttribute(attrstr, &spec, start, end);
|
||||||
start, end);
|
|
||||||
|
|
||||||
uiAttributedStringAppendUnattributed(attrstr, ", ");
|
uiAttributedStringAppendUnattributed(attrstr, ", ");
|
||||||
|
|
||||||
|
@ -48,10 +46,9 @@ static void setupAttributedString(void)
|
||||||
start = uiAttributedStringLen(attrstr);
|
start = uiAttributedStringLen(attrstr);
|
||||||
end = start + strlen(next);
|
end = start + strlen(next);
|
||||||
uiAttributedStringAppendUnattributed(attrstr, next);
|
uiAttributedStringAppendUnattributed(attrstr, next);
|
||||||
uiAttributedStringSetAttribute(attrstr,
|
spec.Type = uiAttributeItalic;
|
||||||
uiAttributeItalic,
|
spec.Value = (uintptr_t) uiDrawTextItalicItalic;
|
||||||
(uintptr_t) uiDrawTextItalicItalic,
|
uiAttributedStringSetAttribute(attrstr, &spec, start, end);
|
||||||
start, end);
|
|
||||||
|
|
||||||
uiAttributedStringAppendUnattributed(attrstr, ", ");
|
uiAttributedStringAppendUnattributed(attrstr, ", ");
|
||||||
|
|
||||||
|
@ -59,10 +56,9 @@ static void setupAttributedString(void)
|
||||||
start = uiAttributedStringLen(attrstr);
|
start = uiAttributedStringLen(attrstr);
|
||||||
end = start + strlen(next);
|
end = start + strlen(next);
|
||||||
uiAttributedStringAppendUnattributed(attrstr, next);
|
uiAttributedStringAppendUnattributed(attrstr, next);
|
||||||
uiAttributedStringSetAttribute(attrstr,
|
spec.Type = uiAttributeStretch;
|
||||||
uiAttributeStretch,
|
spec.Value = (uintptr_t) uiDrawTextStretchCondensed;
|
||||||
(uintptr_t) uiDrawTextStretchCondensed,
|
uiAttributedStringSetAttribute(attrstr, &spec, start, end);
|
||||||
start, end);
|
|
||||||
|
|
||||||
uiAttributedStringAppendUnattributed(attrstr, ", ");
|
uiAttributedStringAppendUnattributed(attrstr, ", ");
|
||||||
|
|
||||||
|
|
11
ui_attrstr.h
11
ui_attrstr.h
|
@ -1,4 +1,5 @@
|
||||||
typedef struct uiAttributedString uiAttributedString;
|
typedef struct uiAttributedString uiAttributedString;
|
||||||
|
typedef struct uiAttributeSpec uiAttributeSpec;
|
||||||
|
|
||||||
_UI_ENUM(uiAttribute) {
|
_UI_ENUM(uiAttribute) {
|
||||||
// TODO once we allow loading fonts in memory we can't use just one pointer anymore
|
// TODO once we allow loading fonts in memory we can't use just one pointer anymore
|
||||||
|
@ -13,7 +14,13 @@ _UI_ENUM(uiAttribute) {
|
||||||
// TODO uiAttributeCustom,
|
// TODO uiAttributeCustom,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (*uiAttributedStringForEachAttributeFunc)(uiAttributedString *s, uiAttribute type, uintptr_t value, size_t start, size_t end, void *data);
|
struct uiAttributeSpec {
|
||||||
|
uiAttribute Type;
|
||||||
|
uintptr_t Value;
|
||||||
|
double Double;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef int (*uiAttributedStringForEachAttributeFunc)(uiAttributedString *s, uiAttributeSpec *spec, size_t start, size_t end, void *data);
|
||||||
|
|
||||||
// @role uiAttributedString constructor
|
// @role uiAttributedString constructor
|
||||||
// uiNewAttributedString() creates a new uiAttributedString from
|
// uiNewAttributedString() creates a new uiAttributedString from
|
||||||
|
@ -39,7 +46,7 @@ _UI_EXTERN void uiAttributedStringDelete(uiAttributedString *s, size_t start, si
|
||||||
_UI_EXTERN size_t uiAttributedStringNumGraphemes(uiAttributedString *s);
|
_UI_EXTERN size_t uiAttributedStringNumGraphemes(uiAttributedString *s);
|
||||||
_UI_EXTERN size_t uiAttributedStringByteIndexToGrapheme(uiAttributedString *s, size_t pos);
|
_UI_EXTERN size_t uiAttributedStringByteIndexToGrapheme(uiAttributedString *s, size_t pos);
|
||||||
_UI_EXTERN size_t uiAttributedStringGraphemeToByteIndex(uiAttributedString *s, size_t pos);
|
_UI_EXTERN size_t uiAttributedStringGraphemeToByteIndex(uiAttributedString *s, size_t pos);
|
||||||
_UI_EXTERN void uiAttributedStringSetAttribute(uiAttributedString *s, uiAttribute type, uintptr_t value, size_t start, size_t end);
|
_UI_EXTERN void uiAttributedStringSetAttribute(uiAttributedString *s, uiAttributeSpec *spec, size_t start, size_t end);
|
||||||
_UI_EXTERN void uiAttributedStringForEachAttribute(uiAttributedString *s, uiAttributedStringForEachAttributeFunc f, void *data);
|
_UI_EXTERN void uiAttributedStringForEachAttribute(uiAttributedString *s, uiAttributedStringForEachAttributeFunc f, void *data);
|
||||||
|
|
||||||
typedef struct uiDrawFontDescriptor uiDrawFontDescriptor;
|
typedef struct uiDrawFontDescriptor uiDrawFontDescriptor;
|
||||||
|
|
Loading…
Reference in New Issue