Added uiAttribute handling code to the GTK+ backend. Not finished yet; not used yet.
This commit is contained in:
parent
ea473a3411
commit
d7a44a5168
|
@ -5,8 +5,6 @@
|
|||
// Notes:
|
||||
// - Each tag should only appear in quotes once (including within comments); this allows automated tools to determine what we cover and don't cover
|
||||
|
||||
typedef void (*specToOpenTypeEnumFunc)(const char *featureTag, uint32_t param, void *data);
|
||||
|
||||
static void boolspec(uiAttributeSpec *spec, const char *featureTag, specToOpenTypeEnumFunc f, void *data)
|
||||
{
|
||||
if (spec->Value != 0) {
|
||||
|
|
|
@ -101,6 +101,10 @@ struct caretDrawParams {
|
|||
extern void caretDrawParams(uiDrawContext *c, double height, struct caretDrawParams *p);
|
||||
extern void drawTextBackground(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout, size_t start, size_t end, uiDrawBrush *brush, int isSelection);
|
||||
|
||||
// opentype.c
|
||||
typedef void (*specToOpenTypeEnumFunc)(const char *featureTag, uint32_t param, void *data);
|
||||
extern void specToOpenType(uiAttributeSpec *spec, specToOpenTypeEnumFunc f, void *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -6,6 +6,7 @@ pkg_check_modules(GTK REQUIRED gtk+-3.0)
|
|||
list(APPEND _LIBUI_SOURCES
|
||||
unix/alloc.c
|
||||
unix/area.c
|
||||
unix/attrstr.c
|
||||
unix/box.c
|
||||
unix/button.c
|
||||
unix/cellrendererbutton.c
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
// 12 february 2017
|
||||
#include "uipriv_unix.h"
|
||||
|
||||
// we need to collect all the OpenType features and background blocks and add them all at once
|
||||
// TODO rename this struct to something that isn't exclusively foreach-ing?
|
||||
struct foreachParams {
|
||||
PangoAttrList *attrs;
|
||||
// keys are pointers to size_t maintained by g_new0()/g_free()
|
||||
// values are GStrings
|
||||
GHashTable *features;
|
||||
//TODO GArray *backgroundBlocks;
|
||||
};
|
||||
|
||||
static gboolean featurePosEqual(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
size_t *sa = (size_t *) a;
|
||||
size_t *sb = (size_t *) b;
|
||||
|
||||
return *sa == *sb;
|
||||
}
|
||||
|
||||
static guint featurePosHash(gconstpointer n)
|
||||
{
|
||||
size_t *sn = (size_t *) n;
|
||||
|
||||
return (guint) (*sn);
|
||||
}
|
||||
|
||||
static void freeFeatureString(gpointer s)
|
||||
{
|
||||
g_string_free((GString *) s, TRUE);
|
||||
}
|
||||
|
||||
static void ensureFeaturesInRange(struct foreachParams *p, size_t start, size_t end)
|
||||
{
|
||||
size_t i;
|
||||
size_t *key;
|
||||
GString *new;
|
||||
|
||||
for (i = start; i < end; i++) {
|
||||
new = (GString *) g_hash_table_lookup(p->features, &i);
|
||||
if (new != NULL)
|
||||
continue;
|
||||
new = g_string_new("");
|
||||
key = g_new0(size_t, 1);
|
||||
*key = i;
|
||||
g_hash_table_replace(p->features, key, new);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 /* TODO */
|
||||
static backgroundBlock mkBackgroundBlock(size_t start, size_t end, double r, double g, double b, double a)
|
||||
{
|
||||
return Block_copy(^(uiDrawContext *c, uiDrawTextLayout *layout, double x, double y) {
|
||||
uiDrawBrush brush;
|
||||
|
||||
brush.Type = uiDrawBrushTypeSolid;
|
||||
brush.R = r;
|
||||
brush.G = g;
|
||||
brush.B = b;
|
||||
brush.A = a;
|
||||
drawTextBackground(c, x, y, layout, start, end, &brush, 0);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
struct otParam {
|
||||
struct foreachParams *p;
|
||||
size_t start;
|
||||
size_t end;
|
||||
};
|
||||
|
||||
// see https://developer.mozilla.org/en/docs/Web/CSS/font-feature-settings
|
||||
static void doOpenType(const char *featureTag, uint32_t param, void *data)
|
||||
{
|
||||
struct otParam *p = (struct otParam *) data;
|
||||
size_t i;
|
||||
GString *s;
|
||||
|
||||
ensureFeaturesInRange(p->p, p->start, p->end);
|
||||
for (i = p->start; i < p->end; i++) {
|
||||
s = (GString *) g_hash_table_lookup(p->p->features, &i);
|
||||
g_string_append_printf(s, "\"%s\" %" PRIu32 ", ",
|
||||
featureTag, param);
|
||||
}
|
||||
}
|
||||
|
||||
static void addattr(struct foreachParams *p, size_t start, size_t end, PangoAttribute *attr)
|
||||
{
|
||||
if (attr == NULL) // in case of a future attribute
|
||||
return;
|
||||
attr->start_index = start;
|
||||
attr->end_index = end;
|
||||
pango_attr_list_insert(p->attrs, attr);
|
||||
}
|
||||
|
||||
static int processAttribute(uiAttributedString *s, uiAttributeSpec *spec, size_t start, size_t end, void *data)
|
||||
{
|
||||
struct foreachParams *p = (struct foreachParams *) data;
|
||||
//TODO backgroundBlock block;
|
||||
PangoGravity gravity;
|
||||
PangoUnderline underline;
|
||||
PangoLanguage *lang;
|
||||
struct otParam op;
|
||||
|
||||
switch (spec->Type) {
|
||||
case uiAttributeFamily:
|
||||
addattr(p, start, end,
|
||||
pango_attr_family_new((const char *) (spec->Value)));
|
||||
break;
|
||||
#if 0 /* TODO */
|
||||
case uiAttributeSize:
|
||||
addattr(p, start, end,
|
||||
pango_attr_size_new(cairoToPango(spec->Double)));
|
||||
break;
|
||||
case uiAttributeWeight:
|
||||
ensureFontInRange(p, start, end);
|
||||
adjustFontInRange(p, start, end, ^(struct fontParams *fp) {
|
||||
fp->desc.Weight = (uiDrawTextWeight) (spec->Value);
|
||||
});
|
||||
break;
|
||||
case uiAttributeItalic:
|
||||
ensureFontInRange(p, start, end);
|
||||
adjustFontInRange(p, start, end, ^(struct fontParams *fp) {
|
||||
fp->desc.Italic = (uiDrawTextItalic) (spec->Value);
|
||||
});
|
||||
break;
|
||||
case uiAttributeStretch:
|
||||
ensureFontInRange(p, start, end);
|
||||
adjustFontInRange(p, start, end, ^(struct fontParams *fp) {
|
||||
fp->desc.Stretch = (uiDrawTextStretch) (spec->Value);
|
||||
});
|
||||
break;
|
||||
#endif
|
||||
case uiAttributeColor:
|
||||
addattr(p, start, end,
|
||||
pango_attr_foreground_new(
|
||||
(guint16) (spec->R * 65535.0),
|
||||
(guint16) (spec->G * 65535.0),
|
||||
(guint16) (spec->B * 65535.0)));
|
||||
addattr(p, start, end,
|
||||
FUTURE_pango_attr_foreground_alpha_new(
|
||||
(guint16) (spec->A * 65535.0)));
|
||||
break;
|
||||
#if 0 /* TODO */
|
||||
case uiAttributeBackground:
|
||||
block = mkBackgroundBlock(ostart, oend,
|
||||
spec->R, spec->G, spec->B, spec->A);
|
||||
[p->backgroundBlocks addObject:block];
|
||||
Block_release(block);
|
||||
break;
|
||||
#endif
|
||||
case uiAttributeVerticalForms:
|
||||
gravity = PANGO_GRAVITY_SOUTH;
|
||||
if (spec->Value != 0)
|
||||
gravity = PANGO_GRAVITY_EAST;
|
||||
addattr(p, start, end,
|
||||
pango_attr_gravity_new(gravity));
|
||||
break;
|
||||
case uiAttributeUnderline:
|
||||
switch (spec->Value) {
|
||||
case uiDrawUnderlineStyleNone:
|
||||
underline = PANGO_UNDERLINE_NONE;
|
||||
break;
|
||||
case uiDrawUnderlineStyleSingle:
|
||||
underline = PANGO_UNDERLINE_SINGLE;
|
||||
break;
|
||||
case uiDrawUnderlineStyleDouble:
|
||||
underline = PANGO_UNDERLINE_DOUBLE;
|
||||
break;
|
||||
case uiDrawUnderlineStyleSuggestion:
|
||||
underline = PANGO_UNDERLINE_ERROR;
|
||||
break;
|
||||
}
|
||||
addattr(p, start, end,
|
||||
pango_attr_underline_new(underline));
|
||||
break;
|
||||
case uiAttributeUnderlineColor:
|
||||
switch (spec->Value) {
|
||||
case uiDrawUnderlineColorCustom:
|
||||
addattr(p, start, end,
|
||||
pango_attr_underline_color_new(
|
||||
(guint16) (spec->R * 65535.0),
|
||||
(guint16) (spec->G * 65535.0),
|
||||
(guint16) (spec->B * 65535.0)));
|
||||
break;
|
||||
case uiDrawUnderlineColorSpelling:
|
||||
// TODO GtkTextView style property error-underline-color
|
||||
addattr(p, start, end,
|
||||
pango_attr_underline_color_new(65535, 0, 0));
|
||||
break;
|
||||
case uiDrawUnderlineColorGrammar:
|
||||
// TODO find a more appropriate color
|
||||
addattr(p, start, end,
|
||||
pango_attr_underline_color_new(0, 65535, 0));
|
||||
break;
|
||||
case uiDrawUnderlineColorAuxiliary:
|
||||
// TODO find a more appropriate color
|
||||
addattr(p, start, end,
|
||||
pango_attr_underline_color_new(0, 0, 65535));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
// language strings are specified as BCP 47: https://developer.gnome.org/pango/1.30/pango-Scripts-and-Languages.html#pango-language-from-string https://www.ietf.org/rfc/rfc3066.txt
|
||||
case uiAttributeLanguage:
|
||||
lang = pango_language_from_string((const char *) (spec->Value));
|
||||
addattr(p, start, end,
|
||||
pango_attr_language_new(lang));
|
||||
// lang *cannot* be freed
|
||||
break;
|
||||
// TODO
|
||||
default:
|
||||
// handle typographic features
|
||||
op.p = p;
|
||||
op.start = start;
|
||||
op.end = end;
|
||||
// TODO check if unhandled and complain
|
||||
specToOpenType(spec, doOpenType, &op);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean applyFeatures(gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
struct foreachParams *p = (struct foreachParams *) data;
|
||||
size_t *pos = (size_t *) key;
|
||||
GString *s = (GString *) value;
|
||||
|
||||
// remove the trailing comma/space
|
||||
g_string_truncate(s, s->len - 2);
|
||||
addattr(p, *pos, 1,
|
||||
FUTURE_pango_attr_font_features_new(s->str));
|
||||
return TRUE; // always delete; we're emptying the map
|
||||
}
|
||||
|
||||
static void applyAndFreeFeatureAttributes(struct foreachParams *p)
|
||||
{
|
||||
g_hash_table_foreach_remove(p->features, applyFeatures, p);
|
||||
g_hash_table_destroy(p->features);
|
||||
}
|
||||
|
||||
PangoAttrList *attrstrToPangoAttrList(uiDrawTextLayoutParams *p/*TODO, NSArray **backgroundBlocks*/)
|
||||
{
|
||||
struct foreachParams fep;
|
||||
|
||||
fep.attrs = pango_attr_list_new();
|
||||
fep.features = g_hash_table_new_full(
|
||||
featurePosHash, featurePosEqual,
|
||||
g_free, freeFeatureString);
|
||||
uiAttributedStringForEachAttribute(p->String, processAttribute, &fep);
|
||||
applyAndFreeFeatureAttributes(&fep);
|
||||
return fep.attrs;
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
// in others, because parts of GTK+ being unstable until recently also sucks :/
|
||||
|
||||
// added in pango 1.38; we need 1.36
|
||||
static PangoAttribute *(*newFeaturesAttr)(const gchar *features) = NULL;
|
||||
static PangoAttribute *(*newFGAlphaAttr)(guint16 alpha) = NULL;
|
||||
|
||||
// added in GTK+ 3.20; we need 3.10
|
||||
|
@ -21,11 +22,19 @@ void loadFutures(void)
|
|||
if (handle == NULL)
|
||||
return;
|
||||
#define GET(var, fn) *((void **) (&var)) = dlsym(handle, #fn)
|
||||
GET(newFeaturesAttr, pango_attr_font_features_new);
|
||||
GET(newFGAlphaAttr, pango_attr_foreground_alpha_new);
|
||||
GET(gwpIterSetObjectName, gtk_widget_path_iter_set_object_name);
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
PangoAttribute *FUTURE_pango_attr_font_features_new(const gchar *features)
|
||||
{
|
||||
if (newFeaturesAttr == NULL)
|
||||
return NULL;
|
||||
return (*newFeaturesAttr)(features);
|
||||
}
|
||||
|
||||
PangoAttribute *FUTURE_pango_attr_foreground_alpha_new(guint16 alpha)
|
||||
{
|
||||
if (newFGAlphaAttr == NULL)
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <langinfo.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include "../ui.h"
|
||||
#include "../ui_unix.h"
|
||||
#include "../common/uipriv.h"
|
||||
|
@ -54,8 +55,12 @@ extern GtkCellRenderer *newCellRendererButton(void);
|
|||
|
||||
// future.c
|
||||
extern void loadFutures(void);
|
||||
extern PangoAttribute *FUTURE_pango_attr_font_features_new(const gchar *features);
|
||||
extern PangoAttribute *FUTURE_pango_attr_foreground_alpha_new(guint16 alpha);
|
||||
extern gboolean FUTURE_gtk_widget_path_iter_set_object_name(GtkWidgetPath *path, gint pos, const char *name);
|
||||
|
||||
// drawtext.c
|
||||
extern void fontdescFromPangoFontDescription(PangoFontDescription *pdesc, uiDrawFontDescriptor *uidesc);
|
||||
|
||||
// attrstr.c
|
||||
extern PangoAttrList *attrstrToPangoAttrList(uiDrawTextLayoutParams *p/*TODO, NSArray **backgroundBlocks*/);
|
||||
|
|
Loading…
Reference in New Issue