blob: 002393924063f5dbf49e63c98ea2592d3e6de3b6 [file] [log] [blame]
/***************************************************************************/
/* */
/* gxdemo.c */
/* */
/* Demo program for AAT/TrueTypeGX font driver implementation (body). */
/* */
/* Copyright 2003 by */
/* Masatake YAMATO and Redhat K.K. */
/* */
/* This file may only be used, */
/* modified, and distributed under the terms of the FreeType project */
/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
/* this file you indicate that you have read the license and */
/* understand and accept it fully. */
/* */
/***************************************************************************/
/***************************************************************************/
/* Development of the code in this file is support of */
/* Information-technology Promotion Agency, Japan. */
/***************************************************************************/
#define _XOPEN_SOURCE
#include <stdlib.h>
#include <ft2build.h>
#include FT_GXLAYOUT_H
#include FT_BBOX_H
#include FT_OUTLINE_H
#include FT_INTERNAL_DEBUG_H
#include <stdio.h>
#include <popt.h>
#include <glib.h>
#include <glib/gslist.h>
#include <glib-object.h>
#include <gtk/gtk.h>
#include <errno.h>
#include <libgnomecanvas/libgnomecanvas.h>
#include "gxdump.h"
#include "gxfeatreg.h"
#include "gxtypes.h"
#include "gxload.h"
#include "gxaccess.h"
#define DEFAULT_UNIT 1024
#define BUFFER_LENGTH 1024
static char buffer[BUFFER_LENGTH];
static GHashTable * setting_buttons = NULL;
static gulong dump_flags = GX_DUMP_mort|GX_DUMP_morx|GX_DUMP_feat|GX_DUMP_kern;
static gboolean dump_glyph_metrics = FALSE;
static GtkAdjustment * gid_spinner_adj;
static GtkWidget *glyph_canvas;
static GnomeCanvasItem *root_rect_item = NULL;
static GnomeCanvasItem *bbox_item = NULL;
static GnomeCanvasItem *h_advance_item = NULL;
static GnomeCanvasItem *v_advance_item = NULL;
static GnomeCanvasItem *pixbuf_item = NULL;
static GSList *div_items = NULL;
static int default_gid = 19;
void create_window ( GX_Face face );
void destroy_window ( GtkObject * unused, GXL_FeaturesRequest request );
void radio_toggled( GtkToggleButton * toggle, gpointer setting );
void check_toggled( GtkToggleButton * toggle, gpointer setting);
void run_layout_engine ( GtkButton * button, gpointer request );
void reset_feature_request( GtkButton * button, gpointer request );
void check_table ( GtkToggleButton * toggle_button, gpointer flag);
void dump_feature_request( GtkButton * button, gpointer request );
void dump_feature_registry( GtkButton * button, gpointer request );
void dump_language_id ( GtkButton * button, gpointer face );
void horizontal_radio_toggled( GtkToggleButton * toggle, gpointer request );
void vertical_radio_toggled( GtkToggleButton * toggle, gpointer request );
void dump_file(FT_Library library, const char * file, gint verbose);
void dump_face(FT_Face face, const char* file, gint verbose);
void dump_glyph(FT_Face face, FT_UShort gid, FTL_Direction direction);
void activate_chain_trace( void );
void set_dump_glyph_metrics ( GtkWidget * check_button, gpointer data );
void render_glyph ( GtkWidget * button, gpointer request );
void set_trace_level( GtkAdjustment * adj, gpointer trace );
#define DUMP_DESC "Supported tables are mort,morx,feat,prop,trak,kern,just,lcar,opbd,bsln,fmtx,fdsc"
static const GDebugKey dump_keys[] = {
{"mort", GX_DUMP_mort},
{"morx", GX_DUMP_morx},
{"feat", GX_DUMP_feat},
{"prop", GX_DUMP_prop},
{"trak", GX_DUMP_trak},
{"kern", GX_DUMP_kern},
{"just", GX_DUMP_just},
{"lcar", GX_DUMP_lcar},
{"opbd", GX_DUMP_opbd},
{"bsln", GX_DUMP_bsln},
{"fmtx", GX_DUMP_fmtx},
{"fdsc", GX_DUMP_fdsc},
};
int
main(int argc, char ** argv)
{
FT_Library library;
FT_Face face;
poptContext optCon;
int rc;
const char * file;
static char* arg_debug = NULL;
static int arg_batch = 0;
static int arg_memprof = 0;
static int arg_verbose = 0;
static int arg_trace_chain = 0;
const int ndump_keys = sizeof(dump_keys)/sizeof(GDebugKey);
struct poptOption optTable [] = {
{ "trace-chain", '\0', POPT_ARG_NONE, &arg_trace_chain, 0, "Dump chains selection", ""},
{ "default-gid", '\0', POPT_ARG_INT, &default_gid, 0, "Default GID", ""},
{ "batch", 'b', POPT_ARG_NONE, &arg_batch, 0, "batch mode", ""},
{ "table", 't', POPT_ARG_STRING, &arg_debug, 0, DUMP_DESC, "tableName"},
{ "memprof", 'm', POPT_ARG_NONE, &arg_memprof, 0, "Enter to infinite loop to run under memprof", ""},
{ "verbose", 'v', POPT_ARG_NONE, &arg_verbose, 0, "Print extra infomation to stdout", ""},
POPT_AUTOHELP
POPT_TABLEEND
};
FTL_EngineType engine_type;
gtk_init(&argc, &argv);
optCon = poptGetContext(argv[0], argc, (const char **)argv, optTable, 0);
poptSetOtherOptionHelp(optCon, "[options] gxfont\n");
rc = poptReadDefaultConfig (optCon, 0);
if (rc < 0)
{
fprintf(stderr, "Fail to read .popt config file: %s\n",
poptStrerror(rc));
exit (1);
}
while ((rc = poptGetNextOpt(optCon)) > 0)
if (rc != -1)
{
fprintf(stderr, "Bad argument %s: %s\n",
poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
poptStrerror(rc));
exit (1);
}
if (arg_trace_chain)
activate_chain_trace();
if (FT_Init_FreeType (&library))
{
fprintf(stderr, "Error in %s\n", "FT_Init_FreeType");
exit (1);
}
if (arg_debug)
dump_flags = g_parse_debug_string (arg_debug,
(GDebugKey *) dump_keys,
ndump_keys);
file = poptGetArg(optCon);
if (!file)
{
poptPrintHelp(optCon, stderr, 0);
exit(1);
}
if ( arg_batch )
{
fprintf(stdout, "<meta>\n");
do {
dump_file( library, file, arg_verbose );
file = poptGetArg(optCon);
} while (file);
fprintf(stdout, "</meta>\n");
goto Exit;
}
if ( FT_New_Face (library, file, 0, &face) )
{
fprintf(stderr, "Error in %s: %s\n", "FT_New_Face", file);
exit (1);
}
#if 0
if ( FT_HAS_VERTICAL(face) )
fprintf(stdout, "Face has vertical infomation\n");
else
fprintf(stdout, "Face does not have vertical infomation\n");
#endif /* 0 */
if (( FTL_Query_EngineType( face, &engine_type ) )
|| ( engine_type != FTL_TRUETYPEGX_ENGINE ))
{
fprintf(stderr, "No GX table is existed: %s\n", file);
exit ( 1 );
}
setting_buttons = g_hash_table_new(NULL, NULL);
create_window( (GX_Face)face );
if ( FT_Done_Face ( face ) )
fprintf(stderr, "Error in %s: %s\n", "FT_Done_Face", file);
Exit:
if ( FT_Done_FreeType (library) )
{
fprintf(stderr, "Error in %s\n", "FT_Done_FreeType");
exit(1);
}
if ( arg_memprof || getenv("_MEMPROF_SOCKET") )
{
fprintf(stderr, "Enter infinite loop for memprof\n");
while (1);
}
return 0;
}
GtkWidget * create_gx_window( GX_Face face );
GtkWidget * create_feat_area( GXL_FeaturesRequest request );
GtkWidget * create_dump_area( GX_Face face,
GXL_FeaturesRequest request );
GtkWidget * create_trace_area(void);
void
create_window (GX_Face face)
{
GtkWidget * window;
window = create_gx_window ( face );
gtk_widget_show(window);
gtk_window_resize( GTK_WINDOW(window), 1, 400);
gtk_window_set_title (GTK_WINDOW( window ), ((FT_Face)face)->family_name);
gtk_main();
}
GtkWidget *
create_gx_window( GX_Face face )
{
GtkWidget * window;
GtkWidget * feat;
GtkWidget * dump;
GtkWidget * trace;
GtkWidget * vbox;
GtkWidget * hbox;
GtkWidget * button;
GtkWidget * notebook;
GtkWidget * label;
GXL_FeaturesRequest request;
GtkWidget *gid_spinner;
FTL_New_FeaturesRequest ( (FT_Face)face,
(FTL_FeaturesRequest*)&request );
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK ( destroy_window ), request);
gtk_container_set_border_width (GTK_CONTAINER (window), 4);
notebook = gtk_notebook_new ();
gtk_widget_show( notebook );
gtk_container_add ( GTK_CONTAINER( window ),
notebook );
/* Features */
vbox = gtk_vbox_new ( FALSE, 8 );
label = gtk_label_new("Features");
gtk_notebook_append_page ( GTK_NOTEBOOK(notebook),
vbox,
label );
gtk_widget_show( vbox );
feat = create_feat_area ( request );
gtk_box_pack_start ( GTK_BOX ( vbox ),
feat,
TRUE,
TRUE,
4 );
hbox = gtk_hbox_new ( TRUE, 4 );
gtk_box_pack_start ( GTK_BOX ( vbox ),
hbox,
FALSE,
TRUE,
4 );
gtk_widget_show( hbox );
button = gtk_button_new_with_label ("Reset");
gtk_widget_show ( button );
g_signal_connect ( G_OBJECT( button ), "clicked",
G_CALLBACK ( reset_feature_request ), request );
gtk_box_pack_start ( GTK_BOX ( hbox ),
button,
TRUE,
TRUE,
4 );
button = gtk_button_new_with_label ("Run");
gtk_widget_show ( button );
g_signal_connect ( G_OBJECT( button ), "clicked",
G_CALLBACK ( run_layout_engine ), request );
gtk_box_pack_start ( GTK_BOX ( hbox ),
button,
TRUE,
TRUE,
4 );
/* Glyph */
vbox = gtk_vbox_new ( FALSE, 8 );
label = gtk_label_new("Glyph");
gtk_notebook_append_page ( GTK_NOTEBOOK(notebook),
vbox,
label );
gtk_widget_show ( vbox );
hbox = gtk_hbox_new ( TRUE, 4 );
gtk_box_pack_start ( GTK_BOX ( vbox ),
hbox,
FALSE,
TRUE,
0 );
gtk_widget_show ( hbox );
gid_spinner_adj = (GtkAdjustment *) gtk_adjustment_new ((gdouble)default_gid, 0.0, (gdouble)0xFFFF,
1.0, 5.0, 5.0);
gid_spinner = gtk_spin_button_new (gid_spinner_adj, 1.0, 0);
gtk_box_pack_start ( GTK_BOX ( hbox ),
gid_spinner,
FALSE,
TRUE,
0 );
gtk_widget_show(gid_spinner);
button = gtk_button_new_with_label("Render");
gtk_box_pack_start ( GTK_BOX ( hbox ),
button,
FALSE,
TRUE,
0 );
g_signal_connect( button,
"clicked",
G_CALLBACK( render_glyph ),
request );
gtk_widget_push_visual (gdk_rgb_get_visual ());
gtk_widget_push_colormap (gdk_rgb_get_cmap ());
glyph_canvas = gnome_canvas_new_aa ();
gtk_widget_pop_colormap ();
gtk_widget_pop_visual ();
gtk_box_pack_start ( GTK_BOX ( vbox ),
glyph_canvas,
TRUE,
TRUE,
4 );
gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(glyph_canvas),0.2);
gnome_canvas_set_scroll_region(GNOME_CANVAS(glyph_canvas),0.0,0.0,
(double)DEFAULT_UNIT,
(double)-DEFAULT_UNIT );
gtk_widget_show( glyph_canvas );
gtk_widget_show ( button );
/* Styles */
vbox = gtk_vbox_new ( FALSE, 8 );
label = gtk_label_new("Styles");
gtk_notebook_append_page ( GTK_NOTEBOOK(notebook),
vbox,
label );
gtk_widget_show ( vbox );
/* Variations */
vbox = gtk_vbox_new ( FALSE, 8 );
label = gtk_label_new("Variations");
gtk_notebook_append_page ( GTK_NOTEBOOK(notebook),
vbox,
label );
/* gtk_widget_show ( vbox ); */
/* Dump */
dump = create_dump_area( face, request );
label = gtk_label_new("Dump");
gtk_notebook_append_page ( GTK_NOTEBOOK(notebook),
dump,
label );
gtk_widget_show ( dump );
/* Trace */
trace = create_trace_area();
label = gtk_label_new("Trace");
gtk_notebook_append_page ( GTK_NOTEBOOK(notebook),
trace,
label );
gtk_widget_show ( trace );
return window;
}
GtkWidget *
create_feat_area( GXL_FeaturesRequest request )
{
GtkWidget * features_vbox;
GtkWidget * feature_frame;
GtkWidget * settings_vbox;
GtkWidget * setting_toggle;
GtkWidget * setting_radio;
GtkWidget * scrolled;
GtkWidget * sep;
gint i_feat, j_string, k_setting;
gint nFeatures = GXL_FeaturesRequest_Get_Feature_Count ( request );
GXL_Feature feature;
FT_SfntName feature_name;
gint nSettings;
GXL_Setting setting;
FT_SfntName setting_name;
char * c_string;
static GSList * group = NULL;
scrolled = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled),
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC );
features_vbox = gtk_vbox_new( FALSE, 4 );
gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( scrolled ),
features_vbox );
feature_frame = gtk_frame_new ( "Direction" );
gtk_box_pack_start( GTK_BOX( features_vbox ),
feature_frame,
FALSE,
FALSE,
2 );
settings_vbox = gtk_vbox_new( FALSE, 4 );
gtk_container_add( GTK_CONTAINER( feature_frame ),
settings_vbox );
setting_radio = gtk_radio_button_new_with_label( group, "Horizontal" );
gtk_box_pack_start( GTK_BOX(settings_vbox),
setting_radio,
FALSE,
FALSE,
0 );
g_signal_connect ( setting_radio,
"toggled",
G_CALLBACK(horizontal_radio_toggled),
request );
group = gtk_radio_button_get_group( GTK_RADIO_BUTTON (setting_radio) );
setting_radio = gtk_radio_button_new_with_label( group, "Vertical" );
gtk_box_pack_start( GTK_BOX(settings_vbox),
setting_radio,
FALSE,
FALSE,
0 );
g_signal_connect ( setting_radio,
"toggled",
G_CALLBACK(vertical_radio_toggled),
request );
sep = gtk_hseparator_new();
gtk_box_pack_start( GTK_BOX(features_vbox),
sep,
FALSE,
FALSE,
0 );
for ( i_feat = 0; i_feat < nFeatures; i_feat++ )
{
group = NULL;
feature = GXL_FeaturesRequest_Get_Feature ( request, i_feat );
if ( GXL_Feature_Get_Name ( feature, 0, 0, 0, &feature_name ) )
{
fprintf(stderr, "Cannot find name\n");
exit (1);
}
c_string = g_new(char, feature_name.string_len + 1 );
c_string[feature_name.string_len] = '\0';
for (j_string = 0; j_string < feature_name.string_len; j_string++)
c_string[j_string] = feature_name.string[j_string];
feature_frame = gtk_frame_new ( c_string );
g_free(c_string);
gtk_box_pack_start( GTK_BOX( features_vbox ),
feature_frame,
FALSE,
FALSE,
2 );
settings_vbox = gtk_vbox_new( FALSE, 4 );
gtk_container_add( GTK_CONTAINER( feature_frame ),
settings_vbox );
nSettings = GXL_Feature_Get_Setting_Count( feature );
for ( k_setting = 0; k_setting < nSettings; k_setting++ )
{
setting = GXL_Feature_Get_Setting( feature, k_setting );
if ( GXL_Setting_Get_Name ( setting, 0, 0, 0, &setting_name ) )
{
fprintf (stderr, "Cannot find setting name\n");
exit (1);
}
c_string = g_new(char, setting_name.string_len + 1 );
c_string[setting_name.string_len] = '\0';
for (j_string = 0; j_string < setting_name.string_len; j_string++)
c_string[j_string] = setting_name.string[j_string];
if ( GXL_Feature_Is_Setting_Exclusive (feature) )
{
setting_radio = gtk_radio_button_new_with_label(group, c_string);
group = gtk_radio_button_get_group( GTK_RADIO_BUTTON (setting_radio) );
g_free(c_string);
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(setting_radio),
GXL_Setting_Get_State (setting) );
g_signal_connect ( setting_radio,
"toggled",
G_CALLBACK(radio_toggled),
setting );
gtk_box_pack_start( GTK_BOX(settings_vbox),
setting_radio,
FALSE,
FALSE,
0 );
gtk_container_set_border_width (GTK_CONTAINER (setting_radio), 2);
g_hash_table_insert ( setting_buttons, setting_radio, setting );
}
else
{
setting_toggle = gtk_check_button_new_with_label(c_string);
g_free(c_string);
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(setting_toggle),
GXL_Setting_Get_State (setting) );
g_signal_connect ( setting_toggle,
"toggled",
G_CALLBACK(check_toggled),
setting );
gtk_box_pack_start( GTK_BOX(settings_vbox),
setting_toggle,
FALSE,
FALSE,
0 );
gtk_container_set_border_width (GTK_CONTAINER (setting_toggle), 2);
g_hash_table_insert ( setting_buttons, setting_toggle, setting );
}
}
group = NULL;
}
gtk_widget_show_all(scrolled);
return scrolled;
}
void dump_face_cb( GtkButton * button, gpointer face );
GtkWidget *
create_dump_area( GX_Face face,
GXL_FeaturesRequest request )
{
GtkWidget * vbox = gtk_vbox_new ( FALSE, 0 );
GtkWidget * button;
GtkWidget * frame;
GtkWidget * dump_face_vbox;
GtkWidget * dump_tables_vbox;
GtkWidget * check_button;
/* Language ID */
button = gtk_button_new_with_label("Dump Language ID");
gtk_box_pack_start ( GTK_BOX ( vbox ),
button,
FALSE,
TRUE,
0 );
g_signal_connect ( G_OBJECT( button ), "clicked",
G_CALLBACK ( dump_language_id ), face );
gtk_widget_show ( button );
/* Feature Request */
button = gtk_button_new_with_label("Dump Feature Request");
gtk_box_pack_start ( GTK_BOX ( vbox ),
button,
FALSE,
TRUE,
0 );
g_signal_connect ( G_OBJECT( button ), "clicked",
G_CALLBACK ( dump_feature_request ), request );
gtk_widget_show ( button );
/* Feature Registry */
button = gtk_button_new_with_label("Dump Feature Registry");
gtk_box_pack_start ( GTK_BOX ( vbox ),
button,
FALSE,
TRUE,
0 );
g_signal_connect ( G_OBJECT( button ), "clicked",
G_CALLBACK ( dump_feature_registry ), NULL );
gtk_widget_show ( button );
/* Dump Glyph Metrics */
button = gtk_check_button_new_with_label ("Enable to Dump Glyph Metrics");
gtk_box_pack_start ( GTK_BOX ( vbox ),
button,
FALSE,
TRUE,
0 );
g_signal_connect ( G_OBJECT( button ), "toggled",
G_CALLBACK ( set_dump_glyph_metrics ), &dump_glyph_metrics );
gtk_widget_show ( button );
/* Dump tables */
frame = gtk_frame_new ( "Dump Tables" );
gtk_box_pack_start( GTK_BOX( vbox ), frame, FALSE, FALSE, 2 );
dump_face_vbox = gtk_vbox_new ( FALSE, 0 );
gtk_container_add( GTK_CONTAINER( frame ), dump_face_vbox );
dump_tables_vbox = gtk_vbox_new ( FALSE, 0 );
gtk_container_add( GTK_CONTAINER( dump_face_vbox ), dump_tables_vbox );
#define MAKE_CHECK_BUTTON(tag) \
check_button = gtk_check_button_new_with_label(#tag); \
gtk_container_add( GTK_CONTAINER( dump_tables_vbox ), check_button ); \
gtk_widget_show(check_button); \
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(check_button), \
( dump_flags & GX_DUMP_##tag )? TRUE: FALSE ); \
g_signal_connect ( G_OBJECT( check_button ), \
"toggled", \
G_CALLBACK(check_table), \
GINT_TO_POINTER(GX_DUMP_##tag) )
MAKE_CHECK_BUTTON(mort);
MAKE_CHECK_BUTTON(morx);
MAKE_CHECK_BUTTON(feat);
MAKE_CHECK_BUTTON(prop);
MAKE_CHECK_BUTTON(trak);
MAKE_CHECK_BUTTON(kern);
MAKE_CHECK_BUTTON(just);
MAKE_CHECK_BUTTON(lcar);
MAKE_CHECK_BUTTON(opbd);
MAKE_CHECK_BUTTON(bsln);
MAKE_CHECK_BUTTON(fmtx);
MAKE_CHECK_BUTTON(fdsc);
button = gtk_button_new_with_label("Dump Font Tables");
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK ( dump_face_cb ), face);
gtk_container_add( GTK_CONTAINER( dump_face_vbox ), button );
gtk_widget_show ( button );
gtk_widget_show ( dump_tables_vbox );
gtk_widget_show ( dump_face_vbox );
gtk_widget_show ( frame );
return vbox;
}
GtkWidget*
create_trace_area(void)
{
int count = FT_Trace_Get_Count();
int i;
GtkWidget * vbox, *hbox;
GtkWidget * label;
GtkWidget * scrolled;
const char * label_string;
GtkObject * adj;
GtkWidget * spinner;
int level;
scrolled = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled),
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC );
vbox = gtk_vbox_new ( TRUE, 1 );
for ( i = 0; i < count; i++ )
{
hbox = gtk_hbox_new( TRUE, 2 );
label_string = FT_Trace_Get_Name( i );
label = gtk_label_new( label_string );
gtk_container_add(GTK_CONTAINER(hbox), label);
gtk_widget_show(label);
#ifdef FT_DEBUG_LEVEL_TRACE
level = (gdouble)ft_trace_levels[i];
#else
level = 0;
#endif /* FT_DEBUG_LEVEL_TRACE */
adj = gtk_adjustment_new(level,
0.0, (gdouble)7, 1.0, 1.0, 1.0);
spinner = gtk_spin_button_new( GTK_ADJUSTMENT(adj), 1.0, 0 );
gtk_spin_button_set_range(GTK_SPIN_BUTTON(spinner), 0.0, 7.0);
gtk_box_pack_end( GTK_BOX(hbox), spinner, FALSE, TRUE, 0 );
gtk_widget_show(spinner);
g_signal_connect( G_OBJECT(adj),
"value_changed",
G_CALLBACK(set_trace_level),
GINT_TO_POINTER(i));
gtk_container_add( GTK_CONTAINER(vbox), hbox);
gtk_widget_show(hbox);
}
gtk_widget_show(vbox);
gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( scrolled ),
vbox );
return scrolled;
}
void
dump_face_cb( GtkButton * button, gpointer face )
{
dump_face( face, ((FT_Face)face)->family_name, 1);
}
void
check_table ( GtkToggleButton * toggle_button, gpointer flag)
{
if ( gtk_toggle_button_get_active( toggle_button ) )
dump_flags |= GPOINTER_TO_INT(flag);
else
dump_flags &= (~(GPOINTER_TO_INT(flag)));
}
void
destroy_window ( GtkObject * unused, GXL_FeaturesRequest request )
{
FTL_Done_FeaturesRequest ( (FTL_FeaturesRequest)request );
gtk_main_quit();
}
void
radio_toggled( GtkToggleButton * toggle, gpointer setting )
{
gboolean state = gtk_toggle_button_get_active(toggle);
GXL_Setting_Set_State( setting, state );
}
void
check_toggled( GtkToggleButton * toggle, gpointer setting )
{
gboolean state = gtk_toggle_button_get_active(toggle);
GXL_Setting_Set_State( setting, state );
}
void
run_layout_engine ( GtkButton * button, gpointer request )
{
FTL_GlyphArray in, out;
FT_Face face = ((FTL_FeaturesRequest)request)->font->face;
FT_Memory memory = face->driver->root.memory;
char * tmp, *next;
long value, length = 0, i;
printf( "Input: ");
tmp = fgets(buffer, BUFFER_LENGTH, stdin);
if ( !tmp )
{
fprintf(stderr, "Fail to read string\n");
return;
}
FTL_New_Glyphs_Array ( memory, &in );
FTL_New_Glyphs_Array ( memory, &out );
tmp = buffer;
while ( 1 )
{
value = strtol(tmp, &next, 10);
if (( value == 0 ) && ( tmp == next ))
break;
else
{
length++;
tmp = next;
}
}
FTL_Set_Glyphs_Array_Length ( in, length );
tmp = buffer;
for ( i = 0; i < length; i++ )
in->glyphs[i].gid = (FT_UShort)strtol(tmp, &tmp, 10);
FTL_Activate_FeaturesRequest( request );
FTL_Substitute_Glyphs ( face, in, out );
fprintf(stdout, "Substituted: ");
for ( i = 0; i < length; i++ )
fprintf(stdout, "%u%s ", out->glyphs[i].gid,
(out->glyphs[i].gid == 0xFFFF)? "<empty>": "");
fprintf(stdout, "\n");
if ( dump_glyph_metrics )
{
fprintf(stdout, "\nGlyph Metrics\n");
fprintf(stdout, "---------------\n");
for ( i = 0; i < length; i++ )
dump_glyph(face,
out->glyphs[i].gid,
FTL_Get_FeaturesRequest_Direction((FTL_FeaturesRequest)request));
}
FTL_Done_Glyphs_Array ( in );
FTL_Done_Glyphs_Array ( out );
}
void
reflect_request ( gpointer key, gpointer value, gpointer user_data );
void
reset_feature_request( GtkButton * button, gpointer request )
{
FTL_Reset_FeaturesRequest( request );
g_hash_table_foreach(setting_buttons, reflect_request, NULL);
}
void
reflect_request ( gpointer key, gpointer value, gpointer user_data )
{
GtkWidget * button = GTK_WIDGET(key);
GXL_Setting setting = value;
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(button),
GXL_Setting_Get_State (setting) );
}
void
dump_feature_request( GtkButton * button, gpointer request )
{
gxl_features_request_dump(request, stdout);
}
void
dump_feature_registry( GtkButton * button, gpointer request )
{
fprintf(stdout, "Contents of registry data base\n");
fprintf(stdout, "------------------------------\n");
gx_feature_registory_dump(stdout);
}
void
horizontal_radio_toggled( GtkToggleButton * toggle,
gpointer request )
{
if ( gtk_toggle_button_get_active( toggle ) )
FTL_Set_FeaturesRequest_Direction ( request,
FTL_HORIZONTAL );
}
void
vertical_radio_toggled( GtkToggleButton * toggle,
gpointer request )
{
if ( gtk_toggle_button_get_active( toggle ) )
FTL_Set_FeaturesRequest_Direction ( request,
FTL_VERTICAL );
}
void
dump_face( FT_Face face, const char * file, gint verbose)
{
FT_Bool gx_p;
FTL_EngineType engine_type;
gx_p = !((FTL_Query_EngineType (face, &engine_type))
|| (engine_type != FTL_TRUETYPEGX_ENGINE));
if ( verbose )
{
if ( gx_p )
fprintf(stderr, "ok\n");
else if (((TT_Face)face)->extra.data)
fprintf(stderr, "failed(no gx, cff)\n");
else
fprintf(stderr, "failed(no gx)\n");
}
if ( gx_p )
gx_face_dump(face, dump_flags, file);
fflush ( stdout );
}
void
dump_file( FT_Library library, const char * file, gint verbose)
{
FT_Face face;
if ( FT_New_Face (library, file, 0, &face) )
{
fprintf(stderr, "Error in %s: %s\n", "FT_New_Face", file);
return;
}
if ( verbose )
fprintf(stderr, "loading %s...", file);
/* dump_language_id( NULL, face ); */
dump_face( face, file, verbose );
if ( FT_Done_Face ( face ) )
fprintf(stderr, "Error in %s: %s\n", "FT_Done_Face", file);
}
void
dump_language_id ( GtkButton * unused, gpointer face )
{
/* See ttnameid.h */
FT_CharMap * charmaps = ((FT_Face)face)->charmaps;
FT_Int i, num_charmaps = ((FT_Face)face)->num_charmaps;
FT_ULong langid;
fprintf(stdout, "Laguage ID for the charmaps in the face(see ttnameid.h)\n");
fprintf(stdout, "---------------------------------------\n");
for ( i = 0; i < num_charmaps; i++ )
{
langid = FT_Get_CMap_Language_ID ( charmaps[i] );
switch ( i )
{
case 0:
fprintf(stdout, "Laguage ID for the 1st charmap: %lu\n", langid );
break;
case 1:
fprintf(stdout, "Laguage ID for the 2nd charmap: %lu\n", langid );
break;
case 2:
fprintf(stdout, "Laguage ID for the 3rd charmap: %lu\n", langid );
break;
default:
fprintf(stdout, "Laguage ID for the %dth charmap: %lu\n", i, langid );
}
}
}
void
activate_chain_trace( void )
{
char * tmp = getenv("FT2_DEBUG");
if ( !tmp )
tmp = g_strdup("FT2_DEBUG=gxchain:6");
else
tmp = g_strconcat (tmp, " gxchain:6", NULL);
putenv(tmp);
}
void
dump_glyph(FT_Face face, FT_UShort gid, FTL_Direction dir)
{
FT_Int32 vmask;
FT_BBox bbox;
FT_UShort i, ligcount, div, new_div;
fprintf(stdout, "gid: %u\n", gid);
if ( gid == 0xFFFF )
{
fprintf(stdout, "\t<null glyph>\n");
return ;
}
ligcount = FTL_Get_LigatureCaret_Count ( face, gid );
vmask = (dir == FTL_VERTICAL)? FT_LOAD_VERTICAL_LAYOUT: 0;
FT_Load_Glyph (face, gid,
vmask | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP);
FT_Outline_Get_CBox (&face->glyph->outline, &bbox);
if ( ligcount == 0 )
{
fprintf(stdout, "\twidth: %g\n\theight: %g\n",
(double)bbox.xMax - (double)bbox.xMin,
(double)bbox.yMax - (double)bbox.yMin );
fprintf(stdout, "\tbbox: [xmin: %g ymin: %g xmax: %g ymax: %g]\n",
(double)bbox.xMin, (double)bbox.yMin, (double)bbox.xMax, (double)bbox.yMax);
}
else
{
div = bbox.xMin;
for ( i = 0; i < ligcount; i++ )
{
new_div = FTL_Get_LigatureCaret_Division( face, gid, i );
fprintf(stdout, "\twidth[%d]: %u\n\theight[%d]: %g\n",
i, new_div - div,
i, (double)bbox.yMax - (double)bbox.yMin );
fprintf(stdout, "\tbbox[%d]: [xmin: %g ymin: %g xmax: %g ymax: %g]\n",
i, (double)div, (double)bbox.yMin, (double)new_div, (double)bbox.yMax);
div = new_div;
fprintf(stdout, "\t----------------\n");
}
fprintf(stdout, "\twidth[%d]: %g\n\theight[%d]: %g\n",
i, (double)bbox.xMax - (double)div,
i, (double)bbox.yMax - (double)bbox.yMin );
fprintf(stdout, "\tbbox[%d]: [xmin: %g ymin: %g xmax: %g ymax: %g]\n",
i, (double)div, (double)bbox.yMin, (double)bbox.xMax, (double)bbox.yMax);
}
}
void
set_dump_glyph_metrics ( GtkWidget * check_button, gpointer data )
{
*(gboolean*)data = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(check_button) );
}
void
render_glyph ( GtkWidget * button, gpointer request )
{
FT_Error error;
GnomeCanvasGroup *root = gnome_canvas_root(GNOME_CANVAS(glyph_canvas));
GnomeCanvasItem *div_item;
GdkPixbuf *pixbuf;
FT_Face face = ((FTL_FeaturesRequest)request)->font->face;
FTL_Direction dir = FTL_Get_FeaturesRequest_Direction((FTL_FeaturesRequest)request);
FT_UShort gid = (FT_UShort)gtk_adjustment_get_value(gid_spinner_adj);
FT_Int32 vmask;
FT_BBox bbox;
FT_UShort i, ligcount, div;
double affine[6] = {1.0, 0.0, 0.0, -1.0, 0.0, 0.0};
double affine_with_bearing[6] = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
double factor = (double)DEFAULT_UNIT/(double)face->units_per_EM;
if ( dump_glyph_metrics )
dump_glyph ( face, gid, dir );
if ( pixbuf_item )
{
gtk_object_destroy( GTK_OBJECT(pixbuf_item) );
pixbuf_item = NULL;
}
if ( root_rect_item )
gtk_object_destroy( GTK_OBJECT(root_rect_item) );
if ( bbox_item )
gtk_object_destroy( GTK_OBJECT(bbox_item) );
if ( h_advance_item )
gtk_object_destroy( GTK_OBJECT(h_advance_item) );
if ( v_advance_item )
gtk_object_destroy( GTK_OBJECT(v_advance_item) );
if ( div_items )
{
GSList * tmp;
for ( tmp = div_items; tmp; tmp = tmp->next )
gtk_object_destroy( tmp->data );
g_slist_free ( div_items );
div_items = NULL;
}
error = FT_Set_Pixel_Sizes(face, 0, DEFAULT_UNIT );
if ( error )
{
fprintf(stderr, "Fail in FT_Set_Pixel_Sizes\n");
return ;
}
vmask = (dir == FTL_VERTICAL)? FT_LOAD_VERTICAL_LAYOUT: 0;
error = FT_Load_Glyph (face, gid,
vmask | FT_LOAD_NO_BITMAP);
if ( error )
{
fprintf(stderr, "Fail in FT_Load_Glyph[0]\n");
return ;
}
error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL );
if ( error )
{
fprintf(stderr, "Fail in FT_Render_Glyph\n");
return ;
}
#if 0
fprintf(stdout, "gid: %d row: %d, width: %d, pitch: %d\n",
gid,
face->glyph->bitmap.rows, face->glyph->bitmap.width,
face->glyph->bitmap.pitch);
#endif /* 0 */
if ( face->glyph->bitmap.width == 0 )
goto IGNORE_PIXBUF;
pixbuf = gdk_pixbuf_new( GDK_COLORSPACE_RGB,
TRUE,
8,
face->glyph->bitmap.width,
face->glyph->bitmap.rows );
{
int x, y;
unsigned char src;
unsigned char* src_buffer;
guchar *dist_buffer = gdk_pixbuf_get_pixels (pixbuf);
guchar * dist;
int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
for ( y = 0; y < face->glyph->bitmap.rows; y++ )
{
src_buffer = &(face->glyph->bitmap.buffer[y*face->glyph->bitmap.pitch]);
for (x = 0; x < face->glyph->bitmap.width; x++ )
{
src = src_buffer[x];
dist = dist_buffer + y * rowstride + x * 4;
dist[0] = dist[1] = dist[2] = 255 - src;
if (255 - src)
dist[3] = 0;
else
dist[3] = 255;
}
}
}
pixbuf_item = gnome_canvas_item_new(root,
GNOME_TYPE_CANVAS_PIXBUF,
"pixbuf", pixbuf,
NULL);
g_object_unref(pixbuf);
IGNORE_PIXBUF:
error = FT_Load_Glyph (face, gid,
vmask | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP);
if ( error )
{
fprintf(stderr, "Fail in FT_Load_Glyph[1]\n");
return ;
}
FT_Outline_Get_CBox (&face->glyph->outline, &bbox);
if ( error )
{
fprintf(stderr, "Fail in FT_Outline_Get_CBox\n");
return ;
}
root_rect_item = gnome_canvas_item_new(root,
GNOME_TYPE_CANVAS_RECT,
"x1", (double)0,
"y1", (double)0,
"x2", (double)DEFAULT_UNIT,
"y2", (double)DEFAULT_UNIT,
"outline_color", "black",
NULL);
gnome_canvas_item_affine_relative( root_rect_item, affine );
affine[0] *= factor;
affine[3] *= factor;
h_advance_item = gnome_canvas_item_new( root,
GNOME_TYPE_CANVAS_RECT,
"x1", (double)0,
"y1", (double)0,
"x2", (double)face->glyph->metrics.horiAdvance,
"y2", (double)0,
"outline_color", "red",
NULL);
gnome_canvas_item_affine_relative( h_advance_item, affine );
{
/* Next line is workaround against libart(?)'s bug */
double vertAdvance = ((face->glyph->metrics.vertAdvance)/2)*2.0;
v_advance_item = gnome_canvas_item_new( root,
GNOME_TYPE_CANVAS_RECT,
"x1", (double)0,
"y1", (double)0,
"x2", (double)0,
"y2", (double)vertAdvance,
"outline_color", "red",
NULL);
}
gnome_canvas_item_affine_relative( v_advance_item, affine );
bbox_item = gnome_canvas_item_new(root,
GNOME_TYPE_CANVAS_RECT,
"x1", (double)bbox.xMin,
"y1", (double)bbox.yMin,
"x2", (double)bbox.xMax,
"y2", (double)bbox.yMax,
"outline_color", "blue",
NULL);
gnome_canvas_item_affine_relative( bbox_item, affine );
ligcount = FTL_Get_LigatureCaret_Count ( face, gid );
for ( i = 0; i < ligcount; i++ )
{
/* Here, we will ignore the direction. */
div = FTL_Get_LigatureCaret_Division( face, gid, i );
div_item = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(glyph_canvas)),
GNOME_TYPE_CANVAS_RECT,
"x1", (double)div,
"y1", (double)0,
"x2", (double)div,
"y2", (double)DEFAULT_UNIT,
"outline_color", "red",
NULL);
gnome_canvas_item_affine_relative( div_item, affine );
div_items = g_slist_append ( div_items, div_item );
}
if ( pixbuf_item )
{
affine_with_bearing[4] = (double)bbox.xMin * factor;
affine_with_bearing[5] = -(double)bbox.yMax * factor;
gnome_canvas_item_affine_relative( pixbuf_item, affine_with_bearing );
}
}
void
set_trace_level( GtkAdjustment * adj, gpointer trace )
{
#ifdef FT_DEBUG_LEVEL_TRACE
gint index = GPOINTER_TO_INT(trace);
gint level = (gint)gtk_adjustment_get_value(adj);
ft_trace_levels[index] = level;
#endif /* FT_DEBUG_LEVEL_TRACE */
}
/* END */