// 19 february 2018 #include "../ui.h" #include "uipriv.h" #include "attrstr.h" struct uiAttribute { int owned; size_t refcount; uiAttributeType type; union { const char *family; double size; uiTextWeight weight; uiTextItalic italic; uiTextStretch stretch; struct { double r; double g; double b; double a; // put this here so we can reuse this structure uiUnderlineColor underlineColor; } color; uiUnderline underline; uiOpenTypeFeatures *features; } u; }; static uiAttribute *newAttribute(uiAttributeType type) { uiAttribute *a; a = uiprivNew(uiAttribute); a->ownedByUser = 1; a->refcount = 0; a->type = type; return a; } // returns a to allow expressions like b = uiprivAttributeRetain(a) // TODO would this allow us to copy attributes between strings in a foreach func, and if so, should that be allowed? uiAttribute *uiprivAttributeRetain(uiAttribute *a) { a->ownedByUser = 0; a->refcount++; return a; } static void destroy(uiAttribute *a) { switch (a->type) { case uiAttributeTypeFamily: uiprivFree(a->u.family); break; case uiAttributeTypeFeatures: uiFreeOpenTypeFeatures(a->u.features); break; } uiprivFree(a); } void uiprivAttributeRelease(uiAttribute *a) { if (a->ownedByUser) /* TODO implementation bug: we can't release an attribute we don't own */; a->refcount--; if (a->refcount == 0) destroy(a); } void uiFreeAttribute(uiAttribute *a) { if (!a->ownedByUser) /* TODO user bug: you can't free an attribute you don't own */; destroy(a); } uiAttributeType uiAttributeGetType(const uiAttribute *a) { return a->type; } uiAttribute *uiNewFamilyAttribute(const char *family) { uiAttribute *a; a = newAttribute(uiAttributeTypeFamily); a->u.family = uiprivStrdup(family); return a; } const char *uiAttributeFamily(const uiAttribute *a) { return a->u.family; } uiAttribute *uiNewSizeAttribute(double size) { uiAttribute *a; a = newAttribute(uiAttributeTypeSize); a->u.size = size; return a; } double uiAttributeSize(const uiAttribute *a) { return a->u.size; } uiAttribute *uiNewWeightAttribute(uiTextWeight weight) { uiAttribute *a; a = newAttribute(uiAttributeTypeWeight); a->u.weight = weight; return a; } uiTextWeight uiAttributeWeight(const uiAttribute *a) { return a->u.weight; } uiAttribute *uiNewItalicAttribute(uiTextItalic italic) { uiAttribute *a; a = newAttribute(uiAttributeTypeItalic); a->u.italic = italic; return a; } uiTextItalic uiAttributeItalic(const uiAttribute *a) { return a->u.italic; } uiAttribute *uiNewStretchAttribute(uiTextStretch stretch) { uiAttribute *a; a = newAttribute(uiAttributeTypeStretch); a->u.stretch = stretch; return a; } uiTextStretch uiAttributeStretch(const uiAttribute *a) { return a->u.stretch; } uiAttribute *uiNewColorAttribute(double r, double g, double b, double a) { uiAttribute *at; at = newAttribute(uiAttributeTypeColor); at->u.color.r = r; at->u.color.g = g; at->u.color.b = b; at->u.color.a = a; return at; } void uiAttributeColor(const uiAttribute *a, double *r, double *g, double *b, double *alpha) { *r = a->u.color.r; *g = a->u.color.g; *b = a->u.color.b; *alpha = a->u.color.a; } uiAttribute *uiNewBackgroundAttribute(double r, double g, double b, double a) { uiAttribute *at; at = newAttribute(uiAttributeTypeBackgroundColor); at->u.color.r = r; at->u.color.g = g; at->u.color.b = b; at->u.color.a = a; return at; } uiAttribute *uiNewUnderlineAttribute(uiUnderline u) { uiAttribute *a; a = newAttribute(uiAttributeTypeUnderline); a->u.underline = u; return a; } uiUnderline uiAttributeUnderline(const uiAttribute *a) { return a->u.underline; } uiAttribute *uiNewUnderlineColorAttribute(uiUnderlineColor u, double r, double g, double b, double a) { uiAttribute *at; at = uiNewColorAttribute(r, g, b, a); at->type = uiAttributeTypeUnderlineColor; at->u.color.underlineColor = u; return at; } void uiAttributeUnderline(const uiAttribute *a, uiUnderlineColor *u, double *r, double *g, double *b, double *alpha) { *u = a->u.color.underlineColor; uiAttributeColor(a, r, g, b, alpha); } uiAttribute *uiNewFeaturesAttribute(const uiOpenTypeFeatures *otf) { uiAttribute *a; a = newAttribute(uiAttributeTypeFeatures); a->u.features = uiOpenTypeFeaturesClone(otf); return a; } const uiOpenTypeFeatures *uiAttributeFeatures(const uiAttribute *a) { return a->u.features; } int uiprivAttributeEqual(const uiAttribute *a, const uiAttribute *b) { if (a == b) return 1; if (a->type != b->type) return 0; switch (a->type) { case uiAttributeTypeFamily: return uiprivStricmp(a->u.family, b->u.family); case uiAttributeTypeSize: // TODO is the use of == correct? return a->u.size == b->u.size; case uiAttributeTypeWeight: return a->u.weight == b->u.weight; case uiAttributeTypeItalic: return a->u.italic == b->u.italic; case uiAttributeTypeStretch: return a->u.stretch == b->u.stretch; case uiAttributeTypeUnderline: return a->u.underline == b->u.underline; case uiAttributeTypeUnderlineColor: if (a->u.color.underlineColor != b->u.color.underlineColor) return 0; // fall through case uiAttributeTypeColor: case uiAttributeTypeBackground: // TODO is the use of == correct? return (a->u.color.r == b->u.color.r) && (a->u.color.g == b->u.color.g) && (a->u.color.b == b->u.color.b) && (a->u.color.a == b->u.color.a); case uiAttributeTypeFeatures: return uiprivOpenTypeFeaturesEqual(a->u.features, b->u.features); } // TODO should not be reached return 0; }