/* Chrysalide - Outil d'analyse de fichiers binaires * gbuffersegment.c - concentration d'un fragment de caractères aux propriétés communes * * Copyright (C) 2010-2014 Cyrille Bagard * * This file is part of Chrysalide. * * OpenIDA is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * OpenIDA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar. If not, see . */ #include "gbuffersegment.h" #include #include #include #include "../common/fnv1a.h" #include "../gtkext/gtkblockview.h" #include "../gtkext/support.h" /* Utilisation du champ pixel des couleurs cachées */ #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 { GObject parent; /* A laisser en premier */ char *text; /* Texte brut conservé */ fnv64_t hash; /* Empreinte pour comparaisons */ rendering_pattern_t *pattern; /* Propriétés du rendu */ SegRenderingStyle style; /* Apparence du segment */ GdkColor cache_bg; /* Fond d'impression */ GdkColor alt_fg; /* Couleur d'impression bis */ GdkColor *used_fg; /* Couleur d'impression utile */ cairo_text_extents_t extents; /* Dimensions du texte */ }; /* Fragment de caractères aux propriétés communes (classe) */ struct _GBufferSegmentClass { GObjectClass parent; /* A laisser en premier */ cairo_t *font_ctxts[CAIRO_FONTS_COUNT]; /* Contextes de police */ rendering_pattern_t patterns[RTT_COUNT];/* Modèles d'impression */ }; /* Procède à l'initialisation d'une classe de fragment de texte. */ 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 *); /* 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. * * * * Description : Procède à l'initialisation d'une classe de fragment de texte.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_segment_class_init(GBufferSegmentClass *class) { 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 */ /* Contextes pour les mesures initiales */ filename = find_pixmap_file("nil.png"); if (filename == NULL) abort(); 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); cairo_select_font_face(*cr, "mono", s, w); cairo_set_font_size(*cr, 13); } 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); } /****************************************************************************** * * * Paramètres : segment = composant GTK à initialiser. * * * * Description : Procède à l'initialisation d'un fragment de texte. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_segment_init(GBufferSegment *segment) { } /****************************************************************************** * * * 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 : Crée un nouveau fragment de texte avec des propriétés. * * * * Retour : Composant GTK créé. * * * * Remarques : - * * * ******************************************************************************/ 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 : segment = instance de segment à affiner. * * text = chaîne de caractères à traiter. * * * * Description : Définit les dernières propriétés de rendu restantes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_segment_prepare(GBufferSegment *segment, const char *text) { 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 */ /* Taille */ class = G_BUFFER_SEGMENT_GET_CLASS(segment); slant = segment->pattern->slant; weight = segment->pattern->weight; cr = class->font_ctxts[CAIRO_FONT_INDEX(slant, weight)]; cairo_text_extents(cr, text, &segment->extents); /* Couleurs */ 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; } /****************************************************************************** * * * Paramètres : segment = fragment de texte à consulter. * * ref = segment de référence servant à la comparaison. * * * * Description : Indique si les textes de deux segments sont identiques. * * * * Retour : Bilan de la comparaison. * * * * Remarques : - * * * ******************************************************************************/ bool g_buffer_segment_compare(const GBufferSegment *segment, const GBufferSegment *ref) { bool result; /* Bilan à retourner */ result = cmp_fnv_64a(segment->hash, ref->hash); result &= (strcmp(segment->text, ref->text) == 0); return result; } /****************************************************************************** * * * Paramètres : segment = fragment de texte à consulter. * * * * Description : Fournit le texte brut conservé dans le segment. * * * * Retour : Texte conservé en interne. * * * * Remarques : - * * * ******************************************************************************/ const char *g_buffer_segment_get_text(const GBufferSegment *segment) { return segment->text; } /****************************************************************************** * * * Paramètres : segment = fragment de texte à consulter. * * * * Description : Fournit la quantité de pixels requise pour l'impression. * * * * Retour : Largeur requise par la colonne, en pixel. * * * * Remarques : - * * * ******************************************************************************/ gint g_buffer_segment_get_width(const GBufferSegment *segment) { return segment->extents.x_advance; } /****************************************************************************** * * * Paramètres : segment = fragment de texte à consulter. * * x = position horizontale au niveau du segment. * * * * Description : Fournit la position idéale pour un marqueur. * * * * Retour : Position dans le segment donné. * * * * Remarques : - * * * ******************************************************************************/ gint g_buffer_segment_get_caret_position(const GBufferSegment *segment, gint x) { gint result; /* Position à retourner */ gint width; /* Largeur du segment */ gint char_width; /* Largeur de police fixe */ width = g_buffer_segment_get_width(segment); if (x <= 0) result = 0; else if (x >= width) result = width; else { char_width = width / strlen(segment->text); result = (x / char_width) * char_width; if ((x % char_width) > (char_width / 2)) result += char_width; } return result; } /****************************************************************************** * * * Paramètres : segment = fragment de texte à manipuler. * * style = style de rendu pour le segment. * * * * Description : Module l'apparence finale du composant. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_segment_set_style(GBufferSegment *segment, SegRenderingStyle style) { segment->style = style; switch (style) { default: case SRS_CLASSIC: segment->used_fg = &segment->pattern->foreground; break; case SRS_HIGHLIGHT_SAME: segment->cache_bg.red = 32768; segment->cache_bg.green = 32768; segment->cache_bg.blue = 32768; segment->used_fg = &segment->alt_fg; break; } } /****************************************************************************** * * * Paramètres : segment = fragment de texte à manipuler. * * cairo = contexte graphique à utiliser pour les pinceaux. * * x = abscisse du point d'impression (à maj). [OUT] * * y = ordonnée du point d'impression. * * * * Description : Imprime le fragment de texte représenté. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_segment_draw(GBufferSegment *segment, cairo_t *cairo, gint *x, gint y) { cairo_font_extents_t extents; /* Fond du texte */ 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->extents.x_advance, 17); cairo_set_operator(cairo, CAIRO_OPERATOR_DIFFERENCE); cairo_fill(cairo); cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); } /* Couleur d'impression */ if (segment->used_fg->pixel == COLOR_SET) cairo_set_source_rgb(cairo, segment->used_fg->red / 65535.0, segment->used_fg->green / 65535.0, segment->used_fg->blue / 65535.0); /* Impression du texte */ 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); //printf(">> %s >> %f %f\n", segment->text, segment->extents.width, segment->extents.x_advance); *x += segment->extents.x_advance; }