diff options
Diffstat (limited to 'src/glibext/gbuffersegment.c')
-rw-r--r-- | src/glibext/gbuffersegment.c | 524 |
1 files changed, 184 insertions, 340 deletions
diff --git a/src/glibext/gbuffersegment.c b/src/glibext/gbuffersegment.c index 31f1840..df20887 100644 --- a/src/glibext/gbuffersegment.c +++ b/src/glibext/gbuffersegment.c @@ -25,10 +25,13 @@ #include <stdbool.h> +#include <stdlib.h> #include <string.h> #include "../common/fnv1a.h" +#include "../gtkext/gtkblockview.h" +#include "../gtkext/support.h" @@ -36,6 +39,23 @@ #define COLOR_NOT_SET 0 #define COLOR_SET 1 +/* Propriétés de rendu */ +typedef struct _rendering_pattern_t +{ + GdkColor foreground; /* Couleur d'impression */ + + cairo_font_slant_t slant; /* Style d'impression */ + cairo_font_weight_t weight; /* Poids de la police */ + +} rendering_pattern_t; + +/* Compléments à Cairo */ + +#define CAIRO_FONT_SLANT_COUNT 3 +#define CAIRO_FONT_WEIGHT_COUNT 2 + +#define CAIRO_FONTS_COUNT (CAIRO_FONT_SLANT_COUNT * CAIRO_FONT_WEIGHT_COUNT) +#define CAIRO_FONT_INDEX(s, w) ((s) * CAIRO_FONT_SLANT_COUNT + (w)) /* Fragment de caractères aux propriétés communes (instance) */ struct _GBufferSegment @@ -45,19 +65,15 @@ struct _GBufferSegment char *text; /* Texte brut conservé */ fnv64_t hash; /* Empreinte pour comparaisons */ - PangoAttrList *attribs; /* Propriétés du rendu */ + rendering_pattern_t *pattern; /* Propriétés du rendu */ SegRenderingStyle style; /* Apparence du segment */ GdkColor cache_bg; /* Fond d'impression */ - GdkColor cache_fg; /* Couleur d'impression #1 */ - GdkColor cache_alt_fg; /* Couleur d'impression #2 */ - GdkColor *cache_used_fg; /* Couleur d'impression utile */ - - PangoGlyphString *glyphs; /* Caractères traités */ - PangoFontDescription *desc; /* Description de police */ + GdkColor alt_fg; /* Couleur d'impression bis */ + GdkColor *used_fg; /* Couleur d'impression utile */ - PangoRectangle logical; /* Dimension du texte */ + cairo_text_extents_t extents; /* Dimensions du texte */ }; @@ -66,11 +82,8 @@ struct _GBufferSegmentClass { GObjectClass parent; /* A laisser en premier */ - PangoGlyphString *ascii_glyphs; /* Caractères ASCII prêts */ - PangoFont *ascii_font; /* Police utilisée pour ASCII */ - bool ascii_ready; /* Utilisation possible ? */ - - bool ascii_init_done; /* Initialisation tentée ? */ + cairo_t *font_ctxts[CAIRO_FONTS_COUNT]; /* Contextes de police */ + rendering_pattern_t patterns[RTT_COUNT];/* Modèles d'impression */ }; @@ -81,270 +94,117 @@ static void g_buffer_segment_class_init(GBufferSegmentClass *); /* Procède à l'initialisation d'un fragment de texte. */ static void g_buffer_segment_init(GBufferSegment *); +/* Définit les dernières propriétés de rendu restantes. */ +static void g_buffer_segment_prepare(GBufferSegment *, const char *); - - - - - - -static bool ascii_glyph_table_init(GBufferSegmentClass *class, PangoContext *context) -{ - gint i; /* Boucle de parcours */ - char ascii_chars[128]; /* Table de caractères ASCII */ - PangoAttrList *attribs; /* Liste d'attributs (vide) */ - GList *list; /* Liste d'éléments distincts */ - - if (!class->ascii_init_done) - { - class->ascii_init_done = true; - - /* Construction d'une chaîne adéquate */ - - for (i = 0; i < 128; ++i) - switch (i) - { - case 0 ... 31: - ascii_chars[i] = '?'; - break; - case 32 ... 127: - ascii_chars[i] = i; - break; - default: - ascii_chars[i] = '?'; - break; - } - - /* Analyse de la chaîne créée */ - - attribs = pango_attr_list_new(); - list = pango_itemize(context, ascii_chars, 0, 128, attribs, NULL); - - class->ascii_ready = (list != NULL && list->next == NULL); - - if (class->ascii_ready) - { - PangoItem *item; - //int width; - - item = (PangoItem *)list->data; - //width = gui.char_width * PANGO_SCALE; - - /* Remember the shape engine used for ASCII. */ - //default_shape_engine = item->analysis.shape_engine; - - class->ascii_font = item->analysis.font; - g_object_ref(class->ascii_font); - - class->ascii_glyphs = pango_glyph_string_new(); - - pango_shape(ascii_chars, 128, &item->analysis, class->ascii_glyphs); - - class->ascii_ready = (class->ascii_glyphs->num_glyphs == 128); - - - -#if 0 - for (i = 0; i < class->ascii_glyphs->num_glyphs; i++) - { - PangoGlyphGeometry *geom; - - geom = &class->ascii_glyphs->glyphs[i].geometry; - //geom->x_offset += MAX(0, width - geom->width) / 2; - //geom->width = /*width*/8 * PANGO_SCALE; - } -#endif - - } - - //g_list_foreach(list, (GFunc)&pango_item_free, NULL); - //g_list_free(list); - - //pango_attr_list_unref(attribs); - - } - - return class->ascii_ready; - -} - - - - - +/* Détermine le type du fragment de caractères aux propriétés communes. */ +G_DEFINE_TYPE(GBufferSegment, g_buffer_segment, G_TYPE_OBJECT); /****************************************************************************** * * -* Paramètres : context = contexte Pango pour l'analyse des caractères. * -* attribs = propriétés de la zone de texte. * -* text = chaîne de caractères à traiter. * -* length = quantité de ces caractères. * +* Paramètres : class = classe de composant GTK à initialiser. * * * -* Description : Crée un nouveau fragment de texte avec des propriétés. * +* Description : Procède à l'initialisation d'une classe de fragment de texte.* * * -* Retour : Composant GTK créé. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static void g_buffer_segment_prepare(GBufferSegment *segment, PangoContext *context, PangoAttrList *attribs, const char *text, size_t length) +static void g_buffer_segment_class_init(GBufferSegmentClass *class) { - PangoGlyphString *glyphs; /* Caractères traités */ - bool must_use_pango; /* Passage par Pango obligé ? */ - PangoAttrIterator *iterator; /* Guide de parcours */ - PangoAttribute *attrib; /* Attribut générique */ - - GList *item_list; - PangoItem *item; - - //PangoRectangle logical; - - - const char *max; - const char *iter; - - GBufferSegmentClass *class; - - size_t i; - - PangoGlyphInfo *info; - gint *log_clusters; - PangoGlyphInfo *ref; - - PangoFont *font; /* Modèle de police */ - PangoFontDescription *desc; /* Description de cette police */ - - - - - glyphs = pango_glyph_string_new(); - - - - - - - /* Existe-t-il des attributs particuliers ? */ - - must_use_pango = false; - - iterator = pango_attr_list_get_iterator(attribs); - - attrib = pango_attr_iterator_get(iterator, PANGO_ATTR_WEIGHT); - must_use_pango |= (attrib != NULL); - - attrib = pango_attr_iterator_get(iterator, PANGO_ATTR_STYLE); - must_use_pango |= (attrib != NULL); - - pango_attr_iterator_destroy(iterator); - - if (must_use_pango) - goto not_ascii; - - - - - - - - - /** - * Petite astuce empruntée à Vim... - * (cf. src/gui_gtk_x11.c, fonction gui_gtk2_draw_string()). - * On essaie de traiter à la main les morceaux de - * texte. Pour ceux en ASCII pur, le gain est non négligeable. - */ - - max = text + length; - - goto not_ascii; - - for (iter = text; iter < max; iter++) - if (*iter & 0x80) - goto not_ascii; - - class = G_BUFFER_SEGMENT_GET_CLASS(segment); - - if (!ascii_glyph_table_init(class, context)) - goto not_ascii; - - pango_glyph_string_set_size(glyphs, length); - - info = glyphs->glyphs; - log_clusters = glyphs->log_clusters; - ref = class->ascii_glyphs->glyphs; - - for (i = 0; i < length; i++) - { - info[i] = ref[(unsigned int)text[i]]; - log_clusters[i] = i; - } - - font = class->ascii_font; - - goto next; - - not_ascii: - - item_list = pango_itemize(context, text, 0, length, attribs, NULL); + gchar *filename; /* Accès à une image 1x1 */ + cairo_font_slant_t s; /* Boucle de parcours #1 */ + cairo_font_weight_t w; /* Boucle de parcours #2 */ + cairo_t **cr; /* Contexte à créer */ + cairo_surface_t *surface; /* Surface pour dessin Cairo */ - /* - if (!(item_list != NULL && item_list->next == NULL)) - printf("ouich\n"); - */ + /* Contextes pour les mesures initiales */ - item = (PangoItem *)item_list->data; - pango_shape(text, length, &item->analysis, glyphs); + filename = find_pixmap_file("nil.png"); + if (filename == NULL) abort(); - font = item->analysis.font; - - next: - - desc = pango_font_describe(font); - segment->desc = pango_font_description_copy(desc); - - pango_glyph_string_extents(glyphs, font, NULL, &segment->logical); - - //pango_shape(text, length, &item->analysis, glyphs); + for (s = CAIRO_FONT_SLANT_NORMAL; s < CAIRO_FONT_SLANT_COUNT; s++) + for (w = CAIRO_FONT_WEIGHT_NORMAL; w < CAIRO_FONT_WEIGHT_COUNT; w++) + { + cr = &class->font_ctxts[CAIRO_FONT_INDEX(s, w)]; + surface = cairo_image_surface_create_from_png(filename); + *cr = cairo_create(surface); + cairo_surface_destroy(surface); - //pango_glyph_string_extents(glyphs, class->ascii_font, NULL, &segment->logical); + cairo_select_font_face(*cr, "mono", s, w); + cairo_set_font_size(*cr, 13); - segment->logical.y /= PANGO_SCALE; - segment->logical.width /= PANGO_SCALE; - segment->logical.height /= PANGO_SCALE; + } - segment->glyphs = glyphs; + g_free(filename); + + /* Propriétés d'impression */ + +#define GET_RESET_PATTERN(tp) \ + ({ \ + rendering_pattern_t *__p; \ + __p = &class->patterns[RTT_ ## tp]; \ + memset(__p, 0, sizeof(rendering_pattern_t)); \ + __p; \ + }) + +#define DEFINE_SIMPLE_PATTERN(rtt) \ + do \ + { \ + rendering_pattern_t *__ptn; \ + __ptn = GET_RESET_PATTERN(rtt); \ + __ptn->slant = CAIRO_FONT_SLANT_NORMAL; \ + __ptn->weight = CAIRO_FONT_WEIGHT_NORMAL; \ + __ptn->foreground.pixel = COLOR_NOT_SET; \ + } \ + while (0) + +#define DEFINE_PATTERN(rtt, s, w, r, g, b) \ + do \ + { \ + rendering_pattern_t *__ptn; \ + __ptn = GET_RESET_PATTERN(rtt); \ + __ptn->slant = CAIRO_FONT_SLANT_ ## s; \ + __ptn->weight = CAIRO_FONT_WEIGHT_ ## w; \ + __ptn->foreground.red = r; \ + __ptn->foreground.green = g; \ + __ptn->foreground.blue = b; \ + __ptn->foreground.pixel = COLOR_SET; \ + } \ + while (0) + + DEFINE_PATTERN(RAW, NORMAL, NORMAL, 0, 0, 0); + DEFINE_PATTERN(COMMENT, NORMAL, NORMAL, 14335, 45311, 23551); + DEFINE_PATTERN(INDICATION, ITALIC, NORMAL, 33410, 33410, 33410); + DEFINE_PATTERN(RAW_CODE, NORMAL, NORMAL, 48895, 48895, 48895); + DEFINE_PATTERN(INSTRUCTION, NORMAL, NORMAL, 0, 0, 0); + DEFINE_PATTERN(IMMEDIATE, NORMAL, NORMAL, 41215, 8447, 61695); + DEFINE_PATTERN(REGISTER, NORMAL, NORMAL, 16895, 16895, 53759); + DEFINE_PATTERN(PUNCT, NORMAL, BOLD, 0, 0, 0); + DEFINE_PATTERN(HOOK, NORMAL, BOLD, 0, 0, 0); + DEFINE_PATTERN(SIGNS, NORMAL, BOLD, 0, 0, 0); + DEFINE_SIMPLE_PATTERN(LTGT); + DEFINE_PATTERN(SECTION, NORMAL, NORMAL, 51200, 2560, 2560); + DEFINE_SIMPLE_PATTERN(SEGMENT); + DEFINE_PATTERN(STRING, NORMAL, NORMAL, 52224, 32256, 0); + DEFINE_PATTERN(VAR_NAME, NORMAL, NORMAL, 0, 0, 0); + DEFINE_PATTERN(KEY_WORD, NORMAL, NORMAL, 0, 0, 0); + DEFINE_PATTERN(ERROR, NORMAL, BOLD, 65535, 0, 0); } - - - - - - - - - - - - -/* Détermine le type du fragment de caractères aux propriétés communes. */ -G_DEFINE_TYPE(GBufferSegment, g_buffer_segment, G_TYPE_OBJECT); - - - /****************************************************************************** * * -* Paramètres : class = classe de composant GTK à initialiser. * +* Paramètres : segment = composant GTK à initialiser. * * * -* Description : Procède à l'initialisation d'une classe de fragment de texte.* +* Description : Procède à l'initialisation d'un fragment de texte. * * * * Retour : - * * * @@ -352,7 +212,7 @@ G_DEFINE_TYPE(GBufferSegment, g_buffer_segment, G_TYPE_OBJECT); * * ******************************************************************************/ -static void g_buffer_segment_class_init(GBufferSegmentClass *class) +static void g_buffer_segment_init(GBufferSegment *segment) { } @@ -360,54 +220,77 @@ static void g_buffer_segment_class_init(GBufferSegmentClass *class) /****************************************************************************** * * -* Paramètres : segment = composant GTK à initialiser. * +* Paramètres : type = propriétés de la zone de texte. * +* text = chaîne de caractères à traiter. * +* length = quantité de ces caractères. * * * -* Description : Procède à l'initialisation d'un fragment de texte. * +* Description : Crée un nouveau fragment de texte avec des propriétés. * * * -* Retour : - * +* Retour : Composant GTK créé. * * * * Remarques : - * * * ******************************************************************************/ -static void g_buffer_segment_init(GBufferSegment *segment) +GBufferSegment *g_buffer_segment_new(RenderingTagType type, const char *text, size_t length) { + GBufferSegment *result; /* Composant à retourner */ + GBufferSegmentClass *class; /* Stockage de styles préparés */ + + result = g_object_new(G_TYPE_BUFFER_SEGMENT, NULL); + + result->text = strdup(text); + result->hash = fnv_64a_hash(text); + + class = G_BUFFER_SEGMENT_GET_CLASS(result); + result->pattern = &class->patterns[type]; + + g_buffer_segment_prepare(result, text); + + g_buffer_segment_set_style(result, SRS_CLASSIC); + + return result; } /****************************************************************************** * * -* Paramètres : attribs = propriétés de la zone de texte. * +* Paramètres : segment = instance de segment à affiner. * * text = chaîne de caractères à traiter. * -* length = quantité de ces caractères. * * * -* Description : Crée un nouveau fragment de texte avec des propriétés. * +* Description : Définit les dernières propriétés de rendu restantes. * * * -* Retour : Composant GTK créé. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -GBufferSegment *g_buffer_segment_new(PangoAttrList *attribs, const char *text, size_t length) +static void g_buffer_segment_prepare(GBufferSegment *segment, const char *text) { - GBufferSegment *result; /* Composant à retourner */ + GBufferSegmentClass *class; /* Classe associée à l'instance*/ + cairo_font_slant_t slant; /* Style d'impression */ + cairo_font_weight_t weight; /* Poids de la police */ + cairo_t *cr; /* Contexte de rendu */ - result = g_object_new(G_TYPE_BUFFER_SEGMENT, NULL); + /* Taille */ - result->text = strdup(text); - result->hash = fnv_64a_hash(text); + class = G_BUFFER_SEGMENT_GET_CLASS(segment); - result->attribs = pango_attr_list_ref(attribs); + slant = segment->pattern->slant; + weight = segment->pattern->weight; - g_buffer_segment_prepare(result, get_global_pango_context(), attribs, text, length); + cr = class->font_ctxts[CAIRO_FONT_INDEX(slant, weight)]; - g_buffer_segment_cache_colors(result); + cairo_text_extents(cr, text, &segment->extents); - g_buffer_segment_set_style(result, SRS_CLASSIC); + /* Couleurs */ - return result; + segment->alt_fg.red = 65535 - segment->pattern->foreground.red; + segment->alt_fg.green = 65535 - segment->pattern->foreground.green; + segment->alt_fg.blue = 65535 - segment->pattern->foreground.blue; + segment->alt_fg.pixel = segment->pattern->foreground.pixel; } @@ -471,7 +354,7 @@ const char *g_buffer_segment_get_text(const GBufferSegment *segment) gint g_buffer_segment_get_width(const GBufferSegment *segment) { - return segment->logical.width; + return segment->extents.x_advance; } @@ -497,8 +380,6 @@ gint g_buffer_segment_get_caret_position(const GBufferSegment *segment, gint x) width = g_buffer_segment_get_width(segment); - printf("(seg) x=%d width=%d\n", x, width); - if (x <= 0) result = 0; @@ -507,14 +388,7 @@ gint g_buffer_segment_get_caret_position(const GBufferSegment *segment, gint x) else { - if (strlen(segment->text) != segment->glyphs->num_glyphs) - { - - printf("STOP ::: %d vs %d\n", strlen(segment->text), segment->glyphs->num_glyphs); - exit(0); - } - - char_width = width / segment->glyphs->num_glyphs; + char_width = width / strlen(segment->text); result = (x / char_width) * char_width; if ((x % char_width) > (char_width / 2)) @@ -530,46 +404,6 @@ gint g_buffer_segment_get_caret_position(const GBufferSegment *segment, gint x) /****************************************************************************** * * * Paramètres : segment = fragment de texte à manipuler. * -* * -* Description : (Re)charge les couleurs à partir de la liste d'attributs. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_segment_cache_colors(GBufferSegment *segment) -{ - PangoAttrIterator *iterator; /* Guide de parcours */ - PangoAttribute *attrib; /* Attribut générique */ - PangoAttrColor *color_attrib; /* Propriété de couleur */ - - iterator = pango_attr_list_get_iterator(segment->attribs); - - /* Couleur d'impression */ - - attrib = pango_attr_iterator_get(iterator, PANGO_ATTR_FOREGROUND); - segment->cache_fg.pixel = (attrib != NULL ? COLOR_SET : COLOR_NOT_SET); - - if (segment->cache_fg.pixel == COLOR_SET) - { - color_attrib = (PangoAttrColor *)attrib; - - segment->cache_fg.red = color_attrib->color.red; - segment->cache_fg.green = color_attrib->color.green; - segment->cache_fg.blue = color_attrib->color.blue; - - } - - pango_attr_iterator_destroy(iterator); - -} - - -/****************************************************************************** -* * -* Paramètres : segment = fragment de texte à manipuler. * * style = style de rendu pour le segment. * * * * Description : Module l'apparence finale du composant. * @@ -588,7 +422,7 @@ void g_buffer_segment_set_style(GBufferSegment *segment, SegRenderingStyle style { default: case SRS_CLASSIC: - segment->cache_used_fg = &segment->cache_fg; + segment->used_fg = &segment->pattern->foreground; break; case SRS_HIGHLIGHT_SAME: @@ -597,11 +431,7 @@ void g_buffer_segment_set_style(GBufferSegment *segment, SegRenderingStyle style segment->cache_bg.green = 32768; segment->cache_bg.blue = 32768; - segment->cache_alt_fg.red = 65535 - segment->cache_fg.red; - segment->cache_alt_fg.green = 65535 - segment->cache_fg.green; - segment->cache_alt_fg.blue = 65535 - segment->cache_fg.blue; - - segment->cache_used_fg = &segment->cache_alt_fg; + segment->used_fg = &segment->alt_fg; break; @@ -614,7 +444,6 @@ void g_buffer_segment_set_style(GBufferSegment *segment, SegRenderingStyle style * * * Paramètres : segment = fragment de texte à manipuler. * * cairo = contexte graphique à utiliser pour les pinceaux. * -* fcache = gestionnaire des polices pour l'impression. * * x = abscisse du point d'impression (à maj). [OUT] * * y = ordonnée du point d'impression. * * * @@ -626,23 +455,23 @@ void g_buffer_segment_set_style(GBufferSegment *segment, SegRenderingStyle style * * ******************************************************************************/ -void g_buffer_segment_draw(GBufferSegment *segment, cairo_t *cairo, GFontCache *fcache, gint *x, gint y) +void g_buffer_segment_draw(GBufferSegment *segment, cairo_t *cairo, gint *x, gint y) { - PangoFont *font; /* Police d'impression */ - /* FIXME */ - g_buffer_segment_prepare(segment, get_global_pango_context(), - segment->attribs, segment->text, strlen(segment->text)); + cairo_font_extents_t extents; + + /* Fond du texte */ - if (segment->style != SRS_CLASSIC) + if (segment->style != SRS_CLASSIC || 1) { cairo_set_source_rgb(cairo, segment->cache_bg.red / 65535.0, segment->cache_bg.green / 65535.0, segment->cache_bg.blue / 65535.0); - cairo_rectangle(cairo, *x, y, segment->logical.width, segment->logical.height); + cairo_rectangle(cairo, *x, y, segment->extents.x_advance, 17); + cairo_set_operator(cairo, CAIRO_OPERATOR_DIFFERENCE); cairo_fill(cairo); cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); @@ -651,19 +480,34 @@ void g_buffer_segment_draw(GBufferSegment *segment, cairo_t *cairo, GFontCache * /* Couleur d'impression */ - if (segment->cache_fg.pixel == COLOR_SET) + if (segment->used_fg->pixel == COLOR_SET) cairo_set_source_rgb(cairo, - segment->cache_used_fg->red / 65535.0, - segment->cache_used_fg->green / 65535.0, - segment->cache_used_fg->blue / 65535.0); + segment->used_fg->red / 65535.0, + segment->used_fg->green / 65535.0, + segment->used_fg->blue / 65535.0); /* Impression du texte */ - cairo_move_to(cairo, *x, y - segment->logical.y); + cairo_select_font_face(cairo, "mono", segment->pattern->slant, segment->pattern->weight); + cairo_set_font_size(cairo, 13); + + + + + cairo_move_to(cairo, *x, y + 17 - 3); + + + + + cairo_font_extents(cairo, &extents); + + if (extents.descent != 3) + printf("FONT : %g, %g\n", extents.ascent, extents.descent); + + cairo_show_text(cairo, segment->text); - font = g_font_cache_lookup(fcache, segment->desc); - pango_cairo_show_glyph_string(cairo, font, segment->glyphs); + //printf(">> %s >> %f %f\n", segment->text, segment->extents.width, segment->extents.x_advance); - *x += segment->logical.width; + *x += segment->extents.x_advance; } |