From 261dd4851afbaa099935552851ec1c68f5ea9eb6 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sun, 12 Feb 2017 14:11:25 -0500 Subject: [PATCH] Changed the representation of an attribute type/value pair to allow more type safety and expressability. --- common/attrlist.c | 41 +++++++++++++++++++++------------- common/attrstr.c | 4 ++-- common/uipriv.h | 2 +- darwin/attrstr.m | 14 ++++++------ examples/drawtext/attributes.c | 36 +++++++++++++---------------- ui_attrstr.h | 11 +++++++-- 6 files changed, 61 insertions(+), 47 deletions(-) diff --git a/common/attrlist.c b/common/attrlist.c index f65120f7..5afb862f 100644 --- a/common/attrlist.c +++ b/common/attrlist.c @@ -12,8 +12,7 @@ The linked list is not a ring; alist->fist->prev == NULL and alist->last->next = */ struct attr { - uiAttribute type; - uintptr_t val; + uiAttributeSpec spec; size_t start; size_t end; 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 b = uiNew(struct attr); - b->type = a->type; - b->val = a->val; + b->spec = a->spec; b->start = end; b->end = a->end; *tail = b; @@ -223,8 +221,7 @@ static struct attr *attrSplitAt(struct attrlist *alist, struct attr *a, size_t a return NULL; b = uiNew(struct attr); - b->type = a->type; - b->val = a->val; + b->spec = a->spec; b->start = at; b->end = a->end; @@ -287,7 +284,24 @@ static struct attr *attrDeleteRange(struct attrlist *alist, struct attr *a, size 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 *before; @@ -309,7 +323,7 @@ void attrlistInsertAttribute(struct attrlist *alist, uiAttribute type, uintptr_t goto next; // should we split this? - if (before->type != type) + if (before->spec.Type != spec->Type) goto next; lstart = start; lend = end; @@ -317,10 +331,8 @@ void attrlistInsertAttribute(struct attrlist *alist, uiAttribute type, uintptr_t 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 - // 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? - if (before->val == val) { + if (specsIdentical(before, spec)) { attrGrow(alist, before, start, end); 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 a = uiNew(struct attr); - a->type = type; - a->val = val; + a->spec = *spec; a->start = start; a->end = end; 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 break; } - if (a->type != type) + if (a->spec.Type != type) goto next; lstart = start; lend = end; @@ -587,7 +598,7 @@ void attrlistForEach(struct attrlist *alist, uiAttributedString *s, uiAttributed for (a = alist->first; a != NULL; a = a->next) // TODO document this // 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; } diff --git a/common/attrstr.c b/common/attrstr.c index 93e4e8f4..9c12a532 100644 --- a/common/attrstr.c +++ b/common/attrstr.c @@ -297,9 +297,9 @@ size_t uiAttributedStringGraphemeToByteIndex(uiAttributedString *s, size_t 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? diff --git a/common/uipriv.h b/common/uipriv.h index 73c7eeb0..9d0dc8e6 100644 --- a/common/uipriv.h +++ b/common/uipriv.h @@ -78,7 +78,7 @@ extern size_t *attrstrCopyUTF16ToUTF8(uiAttributedString *s, size_t *n); // attrlist.c 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 attrlistInsertCharactersExtendingAttributes(struct attrlist *alist, size_t start, size_t count); extern void attrlistRemoveAttribute(struct attrlist *alist, uiAttribute type, size_t start, size_t end); diff --git a/darwin/attrstr.m b/darwin/attrstr.m index d1298944..16f7fb92 100644 --- a/darwin/attrstr.m +++ b/darwin/attrstr.m @@ -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; start = attrstrUTF8ToUTF16(s, start); end = attrstrUTF8ToUTF16(s, end); - switch (type) { + switch (spec->Type) { case uiAttributeFamily: ensureFontInRange(p, start, end); adjustFontInRange(p, start, end, ^(uiDrawFontDescriptor *desc) { - desc->Family = (char *) value; + desc->Family = (char *) (spec->Value); }); break; case uiAttributeSize: ensureFontInRange(p, start, end); adjustFontInRange(p, start, end, ^(uiDrawFontDescriptor *desc) { - desc->Size = *((double *) value); + desc->Size = spec->Double; }); break; case uiAttributeWeight: ensureFontInRange(p, start, end); adjustFontInRange(p, start, end, ^(uiDrawFontDescriptor *desc) { - desc->Weight = (uiDrawTextWeight) value; + desc->Weight = (uiDrawTextWeight) (spec->Value); }); break; case uiAttributeItalic: ensureFontInRange(p, start, end); adjustFontInRange(p, start, end, ^(uiDrawFontDescriptor *desc) { - desc->Italic = (uiDrawTextItalic) value; + desc->Italic = (uiDrawTextItalic) (spec->Value); }); break; case uiAttributeStretch: ensureFontInRange(p, start, end); adjustFontInRange(p, start, end, ^(uiDrawFontDescriptor *desc) { - desc->Stretch = (uiDrawTextStretch) value; + desc->Stretch = (uiDrawTextStretch) (spec->Value); }); break; // TODO diff --git a/examples/drawtext/attributes.c b/examples/drawtext/attributes.c index 428c1275..c2a91889 100644 --- a/examples/drawtext/attributes.c +++ b/examples/drawtext/attributes.c @@ -5,6 +5,7 @@ static uiAttributedString *attrstr; static void setupAttributedString(void) { + uiAttributeSpec spec; size_t start, end; const char *next; @@ -14,22 +15,20 @@ static void setupAttributedString(void) start = uiAttributedStringLen(attrstr); end = start + strlen(next); uiAttributedStringAppendUnattributed(attrstr, next); - uiAttributedStringSetAttribute(attrstr, - uiAttributeFamily, - (uintptr_t) "Courier New", - start, end); + spec.Type = uiAttributeFamily; + spec.Value = (uintptr_t) "Courier New"; + uiAttributedStringSetAttribute(attrstr, &spec, start, end); uiAttributedStringAppendUnattributed(attrstr, ", "); next = "multiple sizes"; - static double eighteen = 18; start = uiAttributedStringLen(attrstr); end = start + strlen(next); uiAttributedStringAppendUnattributed(attrstr, next); + spec.Type = uiAttributeSize; + spec.Double = 18; uiAttributedStringSetAttribute(attrstr, - uiAttributeSize, - (uintptr_t) (&eighteen), - start, end); + &spec, start, end); uiAttributedStringAppendUnattributed(attrstr, ", "); @@ -37,10 +36,9 @@ static void setupAttributedString(void) start = uiAttributedStringLen(attrstr); end = start + strlen(next); uiAttributedStringAppendUnattributed(attrstr, next); - uiAttributedStringSetAttribute(attrstr, - uiAttributeWeight, - (uintptr_t) uiDrawTextWeightBold, - start, end); + spec.Type = uiAttributeWeight; + spec.Value = (uintptr_t) uiDrawTextWeightBold; + uiAttributedStringSetAttribute(attrstr, &spec, start, end); uiAttributedStringAppendUnattributed(attrstr, ", "); @@ -48,10 +46,9 @@ static void setupAttributedString(void) start = uiAttributedStringLen(attrstr); end = start + strlen(next); uiAttributedStringAppendUnattributed(attrstr, next); - uiAttributedStringSetAttribute(attrstr, - uiAttributeItalic, - (uintptr_t) uiDrawTextItalicItalic, - start, end); + spec.Type = uiAttributeItalic; + spec.Value = (uintptr_t) uiDrawTextItalicItalic; + uiAttributedStringSetAttribute(attrstr, &spec, start, end); uiAttributedStringAppendUnattributed(attrstr, ", "); @@ -59,10 +56,9 @@ static void setupAttributedString(void) start = uiAttributedStringLen(attrstr); end = start + strlen(next); uiAttributedStringAppendUnattributed(attrstr, next); - uiAttributedStringSetAttribute(attrstr, - uiAttributeStretch, - (uintptr_t) uiDrawTextStretchCondensed, - start, end); + spec.Type = uiAttributeStretch; + spec.Value = (uintptr_t) uiDrawTextStretchCondensed; + uiAttributedStringSetAttribute(attrstr, &spec, start, end); uiAttributedStringAppendUnattributed(attrstr, ", "); diff --git a/ui_attrstr.h b/ui_attrstr.h index 87eac1cf..096bcc4e 100644 --- a/ui_attrstr.h +++ b/ui_attrstr.h @@ -1,4 +1,5 @@ typedef struct uiAttributedString uiAttributedString; +typedef struct uiAttributeSpec uiAttributeSpec; _UI_ENUM(uiAttribute) { // 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, }; -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 // 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 uiAttributedStringByteIndexToGrapheme(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); typedef struct uiDrawFontDescriptor uiDrawFontDescriptor;