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:
|
// 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
|
// - 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)
|
static void boolspec(uiAttributeSpec *spec, const char *featureTag, specToOpenTypeEnumFunc f, void *data)
|
||||||
{
|
{
|
||||||
if (spec->Value != 0) {
|
if (spec->Value != 0) {
|
||||||
|
|
|
@ -101,6 +101,10 @@ struct caretDrawParams {
|
||||||
extern void caretDrawParams(uiDrawContext *c, double height, struct caretDrawParams *p);
|
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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,6 +6,7 @@ pkg_check_modules(GTK REQUIRED gtk+-3.0)
|
||||||
list(APPEND _LIBUI_SOURCES
|
list(APPEND _LIBUI_SOURCES
|
||||||
unix/alloc.c
|
unix/alloc.c
|
||||||
unix/area.c
|
unix/area.c
|
||||||
|
unix/attrstr.c
|
||||||
unix/box.c
|
unix/box.c
|
||||||
unix/button.c
|
unix/button.c
|
||||||
unix/cellrendererbutton.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 :/
|
// in others, because parts of GTK+ being unstable until recently also sucks :/
|
||||||
|
|
||||||
// added in pango 1.38; we need 1.36
|
// added in pango 1.38; we need 1.36
|
||||||
|
static PangoAttribute *(*newFeaturesAttr)(const gchar *features) = NULL;
|
||||||
static PangoAttribute *(*newFGAlphaAttr)(guint16 alpha) = NULL;
|
static PangoAttribute *(*newFGAlphaAttr)(guint16 alpha) = NULL;
|
||||||
|
|
||||||
// added in GTK+ 3.20; we need 3.10
|
// added in GTK+ 3.20; we need 3.10
|
||||||
|
@ -21,11 +22,19 @@ void loadFutures(void)
|
||||||
if (handle == NULL)
|
if (handle == NULL)
|
||||||
return;
|
return;
|
||||||
#define GET(var, fn) *((void **) (&var)) = dlsym(handle, #fn)
|
#define GET(var, fn) *((void **) (&var)) = dlsym(handle, #fn)
|
||||||
|
GET(newFeaturesAttr, pango_attr_font_features_new);
|
||||||
GET(newFGAlphaAttr, pango_attr_foreground_alpha_new);
|
GET(newFGAlphaAttr, pango_attr_foreground_alpha_new);
|
||||||
GET(gwpIterSetObjectName, gtk_widget_path_iter_set_object_name);
|
GET(gwpIterSetObjectName, gtk_widget_path_iter_set_object_name);
|
||||||
dlclose(handle);
|
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)
|
PangoAttribute *FUTURE_pango_attr_foreground_alpha_new(guint16 alpha)
|
||||||
{
|
{
|
||||||
if (newFGAlphaAttr == NULL)
|
if (newFGAlphaAttr == NULL)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <langinfo.h>
|
#include <langinfo.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include "../ui.h"
|
#include "../ui.h"
|
||||||
#include "../ui_unix.h"
|
#include "../ui_unix.h"
|
||||||
#include "../common/uipriv.h"
|
#include "../common/uipriv.h"
|
||||||
|
@ -54,8 +55,12 @@ extern GtkCellRenderer *newCellRendererButton(void);
|
||||||
|
|
||||||
// future.c
|
// future.c
|
||||||
extern void loadFutures(void);
|
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 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);
|
extern gboolean FUTURE_gtk_widget_path_iter_set_object_name(GtkWidgetPath *path, gint pos, const char *name);
|
||||||
|
|
||||||
// drawtext.c
|
// drawtext.c
|
||||||
extern void fontdescFromPangoFontDescription(PangoFontDescription *pdesc, uiDrawFontDescriptor *uidesc);
|
extern void fontdescFromPangoFontDescription(PangoFontDescription *pdesc, uiDrawFontDescriptor *uidesc);
|
||||||
|
|
||||||
|
// attrstr.c
|
||||||
|
extern PangoAttrList *attrstrToPangoAttrList(uiDrawTextLayoutParams *p/*TODO, NSArray **backgroundBlocks*/);
|
||||||
|
|
Loading…
Reference in New Issue