/* Chrysalide - Outil d'analyse de fichiers binaires
 * tokenstyle.c - centralisation des paramètres de rendu de bribes textuelles
 *
 * Copyright (C) 2018-2024 Cyrille Bagard
 *
 *  This file is part of Chrysalide.
 *
 *  Chrysalide 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.
 *
 *  Chrysalide 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 this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


#include "tokenstyle.h"


#include <math.h>
#include <string.h>


#include "tokenstyle-int.h"
#include "../core/logs.h"
#include "../common/extstr.h"



/* -------------------------- DEFINITION D'UN NOUVEL OBJET -------------------------- */


/* Procède à l'initialisation des gestionnaires de paramètres. */
static void g_token_style_class_init(GTokenStyleClass *);

/* Procède à l'initialisation d'un gestionnaire de paramètres. */
static void g_token_style_init(GTokenStyle *);

/* Supprime toutes les références externes. */
static void g_token_style_dispose(GTokenStyle *);

/* Procède à la libération totale de la mémoire. */
static void g_token_style_finalize(GTokenStyle *);



/* ------------------------ RECEPTACLES DE SIGNAUX CONNECTES ------------------------ */


/* Nom des éléments CSS */

#define SEGMENT_NAME(s) "token-" s

static const char *_token_names[TRT_COUNT] = {

    [TRT_NONE]              = SEGMENT_NAME("none"),
    [TRT_RAW_PRINTABLE]     = SEGMENT_NAME("raw-printable"),
    [TRT_RAW_NOT_PRINTABLE] = SEGMENT_NAME("raw-not-printable"),
    [TRT_RAW_FULL]          = SEGMENT_NAME("raw-full"),
    [TRT_RAW_NULL]          = SEGMENT_NAME("raw-null"),
    [TRT_CHR_PRINTABLE]     = SEGMENT_NAME("chr-printable"),
    [TRT_CHR_NOT_PRINTABLE] = SEGMENT_NAME("chr-not-printable"),
    [TRT_COMMENT]           = SEGMENT_NAME("comment"),
    [TRT_INDICATION]        = SEGMENT_NAME("indication"),
    [TRT_PHYS_ADDR_PAD]     = SEGMENT_NAME("phys-addr-padding"),
    [TRT_PHYS_ADDR]         = SEGMENT_NAME("phys-addr"),
    [TRT_VIRT_ADDR_PAD]     = SEGMENT_NAME("virt-addr-padding"),
    [TRT_VIRT_ADDR]         = SEGMENT_NAME("virt-addr"),
    [TRT_RAW_CODE]          = SEGMENT_NAME("raw-code"),
    [TRT_RAW_CODE_NULL]     = SEGMENT_NAME("raw-code-null"),
    [TRT_LABEL]             = SEGMENT_NAME("label"),
    [TRT_INSTRUCTION]       = SEGMENT_NAME("instruction"),
    [TRT_IMMEDIATE]         = SEGMENT_NAME("immediate"),
    [TRT_REGISTER]          = SEGMENT_NAME("register"),
    [TRT_PUNCT]             = SEGMENT_NAME("punct"),
    [TRT_HOOK]              = SEGMENT_NAME("hooks"),
    [TRT_SIGNS]             = SEGMENT_NAME("signs"),
    [TRT_LTGT]              = SEGMENT_NAME("ltgt"),
    [TRT_SECTION]           = SEGMENT_NAME("section"),
    [TRT_SEGMENT]           = SEGMENT_NAME("segment"),
    [TRT_STRING]            = SEGMENT_NAME("string"),
    [TRT_VAR_NAME]          = SEGMENT_NAME("var-name"),
    [TRT_KEY_WORD]          = SEGMENT_NAME("keyword"),
    [TRT_ERROR]             = SEGMENT_NAME("error"),

};


/* Réagit à un changement de racine pour le composant suivi. */
static void on_root_change(GtkWidget *, GParamSpec *, GTokenStyle *);

/* Charge toutes les indications liées aux polices. */
static bool g_token_style_retrieve_font(GTokenStyle *);

/* Détermine les tailles d'impression possibles pour les rendus. */
static bool g_token_style_retrieve_advances(GTokenStyle *);

/* Charge les définitions complémentaires spécifiques. */
static bool g_token_style_retrieve_rendering_properties(GTokenStyle *, TokenRenderingTag );



/* ---------------------------------------------------------------------------------- */
/*                            DEFINITION D'UN NOUVEL OBJET                            */
/* ---------------------------------------------------------------------------------- */


/* Détermine le type du composant d'affichage générique. */
G_DEFINE_TYPE(GTokenStyle, g_token_style, G_TYPE_OBJECT);


/******************************************************************************
*                                                                             *
*  Paramètres  : class = classe des objets à initialiser.                     *
*                                                                             *
*  Description : Procède à l'initialisation des gestionnaires de paramètres.  *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void g_token_style_class_init(GTokenStyleClass *class)
{
    GObjectClass *object;                   /* Plus haut niveau équivalent */

    object = G_OBJECT_CLASS(class);

    object->dispose = (GObjectFinalizeFunc/* ! */)g_token_style_dispose;
    object->finalize = (GObjectFinalizeFunc)g_token_style_finalize;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : style = centralisation de paramètres de rendu à initialiser. *
*                                                                             *
*  Description : Procède à l'initialisation d'un gestionnaire de paramètres.  *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void g_token_style_init(GTokenStyle *style)
{
    style->target = NULL;

    style->loaded = false;

    style->font_family = NULL;
    style->font_size = 0;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : style = instance d'objet GLib à traiter.                     *
*                                                                             *
*  Description : Supprime toutes les références externes.                     *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void g_token_style_dispose(GTokenStyle *style)
{
    g_clear_object(&style->target);

    G_OBJECT_CLASS(g_token_style_parent_class)->dispose(G_OBJECT(style));

}


/******************************************************************************
*                                                                             *
*  Paramètres  : style = instance d'objet GLib à traiter.                     *
*                                                                             *
*  Description : Procède à la libération totale de la mémoire.                *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void g_token_style_finalize(GTokenStyle *style)
{
    if (style->font_family != NULL)
        free(style->font_family);

    G_OBJECT_CLASS(g_token_style_parent_class)->finalize(G_OBJECT(style));

}


/******************************************************************************
*                                                                             *
*  Paramètres  : target = composant GTK à dédier au futur gestionnaire.       *
*                                                                             *
*  Description : Crée un gestionnaire de style pour le rendu des lignes.      *
*                                                                             *
*  Retour      : Centralisateur mis en place pour un composant GTK donné.     *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

GTokenStyle *g_token_style_new(GtkWidget *target)
{
    GTokenStyle *result;                    /* Nouvelle instance à renvoyer*/

    result = g_object_new(G_TYPE_TOKEN_STYLE, NULL);

    if (!g_token_style_create(result, target))
        g_clear_object(&result);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : style  = gestionnaire à initialiser.                         *
*                target = composant GTK à dédier au gestionnaire préparé.     *
*                                                                             *
*  Description : Met en place un nouveau gestionnaire de rendu des lignes.    *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool g_token_style_create(GTokenStyle *style, GtkWidget *target)
{
    bool result;                            /* Bilan à retourner           */

    result = true;

    style->target = target;
    ref_object(target);

    /**
     * Si le composant est déjà affiché, l'actualisation des paramètres est
     * forcée ! Dans le cas contraire, la surveillance des changements
     * déclenchera l'opération.
     */
    if (gtk_widget_get_root(target) != NULL)
        on_root_change(target, NULL, style);

    g_signal_connect(target, "notify::root", G_CALLBACK(on_root_change), style);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : style  = gestionnaire de paramètres de rendu à consulter.    *
*                                                                             *
*  Description : Fournit la quantité de pixels requise pour une ligne.        *
*                                                                             *
*  Retour      : Hauteur de chaque ligne de rendu, en pixels.                 *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

int g_token_style_get_line_height(const GTokenStyle *style)
{
    int result;                             /* Hauteur à retourner         */

    result = style->font_extents.height;

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : style  = gestionnaire de paramètres de rendu à consulter.    *
*                tag    = type de rendu sollicité.                            *
*                length = nombre de caractères à mesurer.                     *
*                                                                             *
*  Description : Fournit la quantité de pixels requise pour l'impression.     *
*                                                                             *
*  Retour      : Largeur requise par la colonne, en pixels.                   *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

int g_token_style_measure_width(const GTokenStyle *style, TokenRenderingTag tag, size_t length)
{
    int result;                             /* Largeur à retourner         */
    const rendering_property_t *prop;       /* Motif de rendu visé         */
    size_t index;                           /* Indice de config. adaptée   */

    prop = &style->properties[tag];

    index = CAIRO_FONT_INDEX(prop->slant, prop->weight);

    result = style->x_advances[index] * length;

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : style  = gestionnaire de paramètres de rendu à consulter.    *
*                tag    = type de rendu sollicité.                            *
*                cr     = contexte graphique à utiliser pour les pinceaux.    *
*                x      = abscisse du point d'impression (à maj). [OUT]       *
*                y      = ordonnée du point d'impression.                     *
*                text   = texte UTF-8 à faire appraître.                      *
*                length = taille de ce texte à imprimer.                      *
*                                                                             *
*  Description : Imprime le fragment de texte transmis.                       *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void g_token_style_draw_text(const GTokenStyle *style, TokenRenderingTag tag, cairo_t *cr, int *x, int y, const char *text, size_t length)
{
    bool selected;                          /* Marquer une sélection ?     */
    gint width;                             /* Largeur du segment          */
    cairo_operator_t old;                   /* Sauvegarde avant changement */
    const rendering_property_t *prop;       /* Motif de rendu visé         */

    /* Cas particulier d'une tabulation */
    if (length == 1 && (text[0] == '\t' || text[0] == ' '))
    {
        width = g_token_style_measure_width(style, tag, text[0] == '\t' ? TAB_SIZE : 1);
        goto small_sep;
    }

    selected = false;//selection_list_has_segment_content(list, segment);

    width = g_token_style_measure_width(style, tag, length);

    /* Fond du texte */
    if (selected)
    {
#if 0

        cairo_set_source_rgba(cr,
                              _seg_params.selection_bg.color.red,
                              _seg_params.selection_bg.color.green,
                              _seg_params.selection_bg.color.blue,
                              _seg_params.selection_bg.color.alpha);

        cairo_rectangle(cr, *x, y, width, 17);

        old = cairo_get_operator(cr);
        cairo_set_operator(cr, CAIRO_OPERATOR_DIFFERENCE);
        cairo_fill(cr);
        cairo_set_operator(cr, old);

#endif

    }

    /* Couleur d'impression */

    prop = &style->properties[tag];

    if (selected)
        cairo_set_source_rgba(cr,
                              prop->inverted.red,
                              prop->inverted.green,
                              prop->inverted.blue,
                              prop->inverted.alpha);

    else
        cairo_set_source_rgba(cr,
                              prop->foreground.red,
                              prop->foreground.green,
                              prop->foreground.blue,
                              prop->foreground.alpha);

    /* Impression du texte */

    cairo_select_font_face(cr, style->font_family, prop->slant, prop->weight);
    cairo_set_font_size(cr, style->font_size);

    cairo_move_to(cr, *x, y + style->font_extents.ascent);

    cairo_show_text(cr, text);

 small_sep:

    *x += width;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : style = gestionnaire de paramètres de rendu à consulter.     *
*                tag   = type de rendu sollicité.                             *
*                text  = texte à encadrer par des balises Pango.              *
*                                                                             *
*  Description : Enjolive du texte selon les paramètres d'un élément de thème.*
*                                                                             *
*  Retour      : Chaîne de caractère à libérer après usage.                   *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

char *g_token_style_build_markup(const GTokenStyle *style, TokenRenderingTag tag, const char *text)
{
    char *result;                           /* Construction à retourner    */
    const rendering_property_t *prop;       /* Motif de rendu visé         */
    char color[10];                         /* Définition hexa de couleur  */

    result = strdup(text);

    prop = &style->properties[tag];

    snprintf(color, sizeof(color), "#%02hhx%02hhx%02hhx%02hhx",
             (unsigned char)(255 * prop->foreground.red),
             (unsigned char)(255 * prop->foreground.green),
             (unsigned char)(255 * prop->foreground.blue),
             (unsigned char)(255 * prop->foreground.alpha));

    result = strprep(result, "\">");
    result = strprep(result, color);
    result = strprep(result, "<span color=\"");

    result = stradd(result, "</span>");

    if (prop->slant == CAIRO_FONT_SLANT_ITALIC || prop->slant == CAIRO_FONT_SLANT_OBLIQUE)
    {
        result = strprep(result, "<i>");
        result = stradd(result, "</i>");
    }

    if (prop->weight == CAIRO_FONT_WEIGHT_BOLD)
    {
        result = strprep(result, "<b>");
        result = stradd(result, "</b>");
    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : style = gestionnaire de paramètres de rendu à consulter.     *
*                base  = base de texte à compléter.                           *
*                tag   = type de rendu sollicité.                             *
*                text  = texte à encadrer par des balises Pango.              *
*                                                                             *
*  Description : Ajoute du texte enjolivé selon un élément de thème.          *
*                                                                             *
*  Retour      : Chaîne de caractère à libérer après usage.                   *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

char *g_token_style_append_markup(const GTokenStyle *style, char *base, TokenRenderingTag tag, const char *text)
{
    char *result;                           /* Construction à retourner    */
    char *tmp;                              /* Stockage temporaire         */

    tmp = g_token_style_build_markup(style, tag, text);

    result = stradd(base, tmp);

    free(tmp);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : style = gestionnaire de paramètres de rendu à consulter.     *
*                max   = valeur maximale atteignable.                         *
*                virt  = indique une position virtuelle et non physique.      *
*                                                                             *
*  Description : Détermine une taille de localisation, physique ou virtuelle. *
*                                                                             *
*  Retour      : Largeur minimale à observer en pixels.                       *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

int g_token_style_compute_location_width(const GTokenStyle *style, uint64_t max, bool virt)
{
    int result;                             /* Taille à retourner          */
    double n;                               /* Nombre de chiffres hexa     */
    double c;                               /* Valeur ajustée              */
    TokenRenderingTag tag;                  /* Type de représentation      */

    /**
     * Les situations suivantes ont été évaluées :
     *
     *          max        |     n    |  c
     *   -----------------------------------
     *                   0 |  0       |  0
     *                   1 |  0,25    |  1
     *                   f |  1       |  1
     *                  10 |  1,02187 |  2
     *                  11 |  1,04248 |  2
     *                  ff |  2       |  2
     *                 100 |  2,00141 |  3
     *            ffffffff |  8       |  8
     *    ffffffffffffffff | 16       | 16
     */

    n = log1p(max) / log(16);

    c = ceil(n);

    tag = virt ? TRT_VIRT_ADDR : TRT_PHYS_ADDR;

    result = g_token_style_measure_width(style, tag, c);

    return result;

}



/* ---------------------------------------------------------------------------------- */
/*                          RECEPTACLES DE SIGNAUX CONNECTES                          */
/* ---------------------------------------------------------------------------------- */


/******************************************************************************
*                                                                             *
*  Paramètres  : widget = composant graphique de GTK changeant d'affichage.   *
*                pspec  = détails de la propriété ayant évolué.               *
*                style  = concentration de paramètres de rendu à actualiser.  *
*                                                                             *
*  Description : Réagit à un changement de racine pour le composant suivi.    *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void on_root_change(GtkWidget *widget, GParamSpec *pspec, GTokenStyle *style)
{
    GtkCssProvider *css;                    /* Feuille de style maison     */
    GdkDisplay *display;                    /* Zone d'affichage courante   */
    TokenRenderingTag i;                    /* Boucle de parcours          */

    /**
     * Si on fermeture n'est pas en court...
     */
    if (gtk_widget_get_root(widget) != NULL)
    {
        /* Chargement des définitions dédiées */

        css = gtk_css_provider_new();

        gtk_css_provider_load_from_resource(css, "/re/chrysalide/framework/glibext/tokenstyle.css");

        display = gtk_widget_get_display(widget);

        gtk_style_context_add_provider_for_display(display, GTK_STYLE_PROVIDER(css),
                                                   GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);

        /* Relecture des paramètres */

        gtk_widget_add_css_class(widget, "token-generic");

        style->loaded = g_token_style_retrieve_font(style);

        if (style->loaded)
            style->loaded = g_token_style_retrieve_advances(style);

        for (i = 0; i < TRT_COUNT && style->loaded; i++)
        {
            gtk_widget_add_css_class(widget, _token_names[i]);

            style->loaded = g_token_style_retrieve_rendering_properties(style, i);

            gtk_widget_remove_css_class(widget, _token_names[i]);

        }

        gtk_widget_remove_css_class(widget, "token-generic");

        /* Déchargement des définitions prises en compte */

        gtk_style_context_remove_provider_for_display(display, GTK_STYLE_PROVIDER(css));

        unref_object(css);

    }

}


/******************************************************************************
*                                                                             *
*  Paramètres  : style = gestionnaire de paramètres de rendu à actualiser.    *
*                                                                             *
*  Description : Charge toutes les indications liées aux polices.             *
*                                                                             *
*  Retour      : Bilan de l'opération : true pour un chargement sans encombre.*
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool g_token_style_retrieve_font(GTokenStyle *style)
{
    bool result;                            /* Bilan à faire remonter      */
    PangoContext *context;                  /* Contexte Pango du composant */
    PangoFontDescription *desc;             /* Détails de la police liée   */
    const char *family;                     /* Eventuelle désignation      */
    bool is_mono;                           /* Propriété attendue de chasse*/
    PangoFontFamily **pango_families;       /* Liste des familles connues  */
    int pango_families_count;               /* Taille de cette liste       */
    int k;                                  /* Boucle de parcours          */
    const char *other;                      /* Autre nom à comparer        */

    result = true;

    /* Réinitialisation */

    if (style->font_family != NULL)
    {
        free(style->font_family);
        style->font_family = NULL;
    }

    style->font_size = 0;

    /* Chargement */

    context = gtk_widget_create_pango_context(style->target);

    desc = pango_context_get_font_description(context);

    if (desc != NULL)
    {
        family = pango_font_description_get_family(desc);

        if (family != NULL)
        {
            is_mono = false;

            pango_context_list_families(context, &pango_families, &pango_families_count);

            for (k = 0; k < pango_families_count && !is_mono; k++)
            {
                if (!pango_font_family_is_monospace(pango_families[k]))
                    continue;

                other = pango_font_family_get_name(pango_families[k]);

                is_mono = (strcmp(family, other) == 0);

            }

            g_free(pango_families);

            if (is_mono)
                style->font_family = strdup(family);
            else
                log_variadic_message(LMT_WARNING,
                                     _("Selected font '%s' does not seem to be a monospace font; skipping it..."),
                                     family);

        }

        style->font_size = pango_font_description_get_size(desc);

        if (pango_font_description_get_size_is_absolute(desc))
            style->font_size /= PANGO_SCALE;

    }

    /* Application de valeurs par défaut au besoin */

    if (style->font_family == NULL)
    {
        style->font_family = strdup(DEFAULT_FONT_FAMILY);

        log_variadic_message(LMT_WARNING,
                             _("No font family defined; switching to '%s' as default"),
                             DEFAULT_FONT_FAMILY);

    }

    if (style->font_size == 0)
    {
        style->font_size = DEFAULT_FONT_SIZE;

        log_variadic_message(LMT_WARNING,
                             _("No font size defined; switching to '%s' as default"),
                             DEFAULT_FONT_SIZE);

    }

    log_variadic_message(LMT_INFO,
                         _("Using '%s' as font family for buffer rendering (size: %d)"),
                         style->font_family, style->font_size);

    unref_object(context);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : style = gestionnaire de paramètres de rendu à actualiser.    *
*                                                                             *
*  Description : Détermine les tailles d'impression possibles pour les rendus.*
*                                                                             *
*  Retour      : Bilan de l'opération : true pour un chargement sans encombre.*
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool g_token_style_retrieve_advances(GTokenStyle *style)
{
    bool result;                            /* Bilan à faire remonter      */
    cairo_font_slant_t s;                   /* Boucle de parcours #1       */
    cairo_font_weight_t w;                  /* Boucle de parcours #2       */
    cairo_t *cr;                            /* Contexte à usage unique     */
    cairo_surface_t *surface;               /* Surface pour dessin Cairo   */
    cairo_text_extents_t extents;           /* Couverture des caractères   */

    result = true;

    for (s = CAIRO_FONT_SLANT_NORMAL; s < CAIRO_FONT_SLANT_COUNT; s++)
        for (w = CAIRO_FONT_WEIGHT_NORMAL; w < CAIRO_FONT_WEIGHT_COUNT; w++)
        {
            surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 100, 100);
            cr = cairo_create(surface);

            cairo_select_font_face(cr, style->font_family, s, w);
            cairo_set_font_size(cr, style->font_size);

            if (s == CAIRO_FONT_SLANT_NORMAL && w == CAIRO_FONT_WEIGHT_NORMAL)
            {
                cairo_font_extents(cr, &style->font_extents);
            }

            cairo_text_extents(cr, "A", &extents);
            style->x_advances[CAIRO_FONT_INDEX(s, w)] = extents.x_advance;

            cairo_destroy(cr);
            cairo_surface_destroy(surface);

        }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : style = gestionnaire de paramètres de rendu à actualiser.    *
*                tag   = désignation du style de rendu à traiter.             *
*                                                                             *
*  Description : Charge les définitions complémentaires spécifiques.          *
*                                                                             *
*  Retour      : Bilan de l'opération : true pour un chargement sans encombre.*
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool g_token_style_retrieve_rendering_properties(GTokenStyle *style, TokenRenderingTag tag)
{
    bool result;                            /* Bilan à faire remonter      */
    rendering_property_t *prop;             /* Motif de rendu visé         */
    GtkStyleContext *s_context;             /* Contexte voué à disparaître */
    PangoContext *context;                  /* Contexte Pango du composant */
    PangoFontDescription *desc;             /* Détails de la police liée   */

    result = true;

    prop = &style->properties[tag];

    /* Couleur d'impression */

    /**
     * En attendant la disponibilité de GTK 4.10 et l'appel
     * gtk_widget_get_color(widget, &color);
     */

    s_context = gtk_widget_get_style_context(style->target);

    gtk_style_context_get_color(s_context, &prop->foreground);

    /* Couleur inversée */

    prop->inverted.red = 1.0 - prop->foreground.red;
    prop->inverted.green = 1.0 - prop->foreground.green;
    prop->inverted.blue = 1.0 - prop->foreground.blue;
    prop->inverted.alpha = prop->foreground.alpha;

    /* Style d'impression */

    context = gtk_widget_create_pango_context(style->target);

    desc = pango_context_get_font_description(context);

    if (desc == NULL)
    {
        prop->slant = CAIRO_FONT_SLANT_NORMAL;
        prop->weight = CAIRO_FONT_WEIGHT_NORMAL;
    }

    else
    {
        switch (pango_font_description_get_style(desc))
        {
            case PANGO_STYLE_NORMAL:
                prop->slant = CAIRO_FONT_SLANT_NORMAL;
                break;
            case PANGO_STYLE_ITALIC:
                prop->slant = CAIRO_FONT_SLANT_ITALIC;
                break;
            case PANGO_STYLE_OBLIQUE:
                prop->slant = CAIRO_FONT_SLANT_OBLIQUE;
                break;
        }

        switch (pango_font_description_get_weight(desc))
        {
            case PANGO_WEIGHT_THIN:
            case PANGO_WEIGHT_ULTRALIGHT:
            case PANGO_WEIGHT_LIGHT:
            case PANGO_WEIGHT_SEMILIGHT:
            case PANGO_WEIGHT_BOOK:
            case PANGO_WEIGHT_NORMAL:
            case PANGO_WEIGHT_MEDIUM:
                prop->weight = CAIRO_FONT_WEIGHT_NORMAL;
                break;
            case PANGO_WEIGHT_SEMIBOLD:
            case PANGO_WEIGHT_BOLD:
            case PANGO_WEIGHT_ULTRABOLD:
            case PANGO_WEIGHT_HEAVY:
            case PANGO_WEIGHT_ULTRAHEAVY:
                prop->weight = CAIRO_FONT_WEIGHT_BOLD;
                break;
        }

    }

    unref_object(context);

    return result;

}