/* OpenIDA - Outil d'analyse de fichiers binaires
* gbuffersegment.c - concentration d'un fragment de caractères aux propriétés communes
*
* Copyright (C) 2010 Cyrille Bagard
*
* This file is part of OpenIDA.
*
* 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
/* Fragment de caractères aux propriétés communes (instance) */
struct _GBufferSegment
{
GObject parent; /* A laisser en premier */
PangoGlyphString *glyphs; /* Caractères traités */
PangoFont *font; /* Police utilisée à l'analyse */
PangoRectangle logical; /* Dimension du texte */
};
/* Fragment de caractères aux propriétés communes (classe) */
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 ? */
};
/* 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 *);
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;
}
/******************************************************************************
* *
* 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. *
* *
* Description : Crée un nouveau fragment de texte avec des propriétés. *
* *
* Retour : Composant GTK créé. *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_buffer_segment_prepare(GBufferSegment *segment, PangoContext *context, PangoAttrList *attribs, const char *text, size_t length)
{
PangoGlyphString *glyphs; /* Caractères traités */
GList *item_list;
PangoItem *item;
PangoRectangle logical;
char *max;
char *iter;
GBufferSegmentClass *class;
size_t i;
PangoGlyphInfo *info;
gint *log_clusters;
PangoGlyphInfo *ref;
glyphs = pango_glyph_string_new();
/**
* 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;
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[text[i]];
log_clusters[i] = i;
}
goto next;
not_ascii:
item_list = pango_itemize(context, text, 0, length, attribs, NULL);
/*
if (!(item_list != NULL && item_list->next == NULL))
printf("ouich\n");
*/
item = (PangoItem *)item_list->data;
pango_shape(text, length, &item->analysis, glyphs);
//segment->font = item->analysis.font;/* TODO : ref ! */
next:
//pango_shape(text, length, &item->analysis, glyphs);
pango_glyph_string_extents(glyphs, class->ascii_font, NULL, &segment->logical);
segment->logical.y /= PANGO_SCALE;
segment->logical.width /= PANGO_SCALE;
segment->logical.height /= PANGO_SCALE;
segment->glyphs = glyphs;
}
/* 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)
{
}
/******************************************************************************
* *
* 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 : 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. *
* *
* Description : Crée un nouveau fragment de texte avec des propriétés. *
* *
* Retour : Composant GTK créé. *
* *
* Remarques : - *
* *
******************************************************************************/
GBufferSegment *g_buffer_segment_new(PangoContext *context, PangoAttrList *attribs, const char *text, size_t length)
{
GBufferSegment *result; /* Composant à retourner */
result = g_object_new(G_TYPE_BUFFER_SEGMENT, NULL);
//result = g_new(GBufferSegment, 1);
g_buffer_segment_prepare(result, context, attribs, text, length);
return result;
}
/******************************************************************************
* *
* 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->logical.width;
}
/******************************************************************************
* *
* Paramètres : segment = fragment de texte à manipuler. *
* drawable = surface de rendu où travailler. *
* gc = 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, GdkDrawable *drawable, GdkGC *gc, gint *x, gint y)
{
gdk_draw_glyphs(drawable, gc, G_BUFFER_SEGMENT_GET_CLASS(segment)->ascii_font,
*x, y - segment->logical.y, segment->glyphs);
*x += segment->logical.width;
}