mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-28 06:21:14 +00:00
1844 lines
72 KiB
C
1844 lines
72 KiB
C
/* Pango/Font Explorer
|
|
*
|
|
* This example demonstrates support for OpenType font features with
|
|
* Pango attributes. The attributes can be used manually or via Pango
|
|
* markup.
|
|
*
|
|
* It can also be used to explore available features in OpenType fonts
|
|
* and their effect.
|
|
*
|
|
* If the selected font supports OpenType font variations, then the
|
|
* axes are also offered for customization.
|
|
*/
|
|
|
|
#include <gtk/gtk.h>
|
|
#include <pango/pangofc-font.h>
|
|
#include <hb.h>
|
|
#include <hb-ot.h>
|
|
#include <hb-ft.h>
|
|
#include <freetype/ftmm.h>
|
|
#include <freetype/ftsnames.h>
|
|
#include <freetype/ttnameid.h>
|
|
#include <glib/gi18n.h>
|
|
|
|
#include "open-type-layout.h"
|
|
#include "fontplane.h"
|
|
#include "script-names.h"
|
|
#include "language-names.h"
|
|
|
|
|
|
#define MAKE_TAG(a,b,c,d) (unsigned int)(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
|
|
|
|
static GtkWidget *label;
|
|
static GtkWidget *settings;
|
|
static GtkWidget *description;
|
|
static GtkWidget *font;
|
|
static GtkWidget *script_lang;
|
|
static GtkWidget *resetbutton;
|
|
static GtkWidget *stack;
|
|
static GtkWidget *entry;
|
|
static GtkWidget *variations_heading;
|
|
static GtkWidget *variations_grid;
|
|
static GtkWidget *instance_combo;
|
|
static GtkWidget *edit_toggle;
|
|
|
|
typedef struct {
|
|
unsigned int tag;
|
|
const char *name;
|
|
GtkWidget *icon;
|
|
GtkWidget *dflt;
|
|
GtkWidget *feat;
|
|
} FeatureItem;
|
|
|
|
static GList *feature_items;
|
|
|
|
typedef struct {
|
|
unsigned int start;
|
|
unsigned int end;
|
|
PangoFontDescription *desc;
|
|
char *features;
|
|
PangoLanguage *language;
|
|
} Range;
|
|
|
|
static GList *ranges;
|
|
|
|
static void add_font_variations (GString *s);
|
|
|
|
static void
|
|
free_range (gpointer data)
|
|
{
|
|
Range *range = data;
|
|
|
|
if (range->desc)
|
|
pango_font_description_free (range->desc);
|
|
g_free (range->features);
|
|
g_free (range);
|
|
}
|
|
|
|
static int
|
|
compare_range (gconstpointer a, gconstpointer b)
|
|
{
|
|
const Range *ra = a;
|
|
const Range *rb = b;
|
|
|
|
if (ra->start < rb->start)
|
|
return -1;
|
|
else if (ra->start > rb->start)
|
|
return 1;
|
|
else if (ra->end < rb->end)
|
|
return 1;
|
|
else if (ra->end > rb->end)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
ensure_range (unsigned int start,
|
|
unsigned int end,
|
|
PangoFontDescription *desc,
|
|
const char *features,
|
|
PangoLanguage *language)
|
|
{
|
|
GList *l;
|
|
Range *range;
|
|
|
|
for (l = ranges; l; l = l->next)
|
|
{
|
|
Range *r = l->data;
|
|
|
|
if (r->start == start && r->end == end)
|
|
{
|
|
range = r;
|
|
goto set;
|
|
}
|
|
}
|
|
|
|
range = g_new0 (Range, 1);
|
|
range->start = start;
|
|
range->end = end;
|
|
|
|
ranges = g_list_insert_sorted (ranges, range, compare_range);
|
|
|
|
set:
|
|
if (range->desc)
|
|
pango_font_description_free (range->desc);
|
|
if (desc)
|
|
range->desc = pango_font_description_copy (desc);
|
|
g_free (range->features);
|
|
range->features = g_strdup (features);
|
|
range->language = language;
|
|
}
|
|
|
|
static const char *
|
|
get_feature_display_name (unsigned int tag)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (open_type_layout_features); i++)
|
|
{
|
|
if (tag == open_type_layout_features[i].tag)
|
|
return g_dpgettext2 (NULL, "OpenType layout", open_type_layout_features[i].name);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void update_display (void);
|
|
|
|
static void
|
|
set_inconsistent (GtkCheckButton *button,
|
|
gboolean inconsistent)
|
|
{
|
|
gtk_check_button_set_inconsistent (GTK_CHECK_BUTTON (button), inconsistent);
|
|
gtk_widget_set_opacity (gtk_widget_get_first_child (GTK_WIDGET (button)), inconsistent ? 0.0 : 1.0);
|
|
}
|
|
|
|
static void
|
|
feat_clicked (GtkWidget *feat,
|
|
gpointer data)
|
|
{
|
|
g_signal_handlers_block_by_func (feat, feat_clicked, NULL);
|
|
|
|
if (gtk_check_button_get_inconsistent (GTK_CHECK_BUTTON (feat)))
|
|
{
|
|
set_inconsistent (GTK_CHECK_BUTTON (feat), FALSE);
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (feat), TRUE);
|
|
}
|
|
else if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (feat)))
|
|
{
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (feat), FALSE);
|
|
}
|
|
else
|
|
{
|
|
set_inconsistent (GTK_CHECK_BUTTON (feat), TRUE);
|
|
}
|
|
|
|
g_signal_handlers_unblock_by_func (feat, feat_clicked, NULL);
|
|
}
|
|
|
|
static void
|
|
add_check_group (GtkWidget *box,
|
|
const char *title,
|
|
const char **tags)
|
|
{
|
|
GtkWidget *label;
|
|
GtkWidget *group;
|
|
PangoAttrList *attrs;
|
|
int i;
|
|
|
|
group = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
|
gtk_widget_set_halign (group, GTK_ALIGN_START);
|
|
|
|
label = gtk_label_new (title);
|
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
|
gtk_widget_set_halign (label, GTK_ALIGN_START);
|
|
g_object_set (label, "margin-top", 10, "margin-bottom", 10, NULL);
|
|
attrs = pango_attr_list_new ();
|
|
pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
|
|
gtk_label_set_attributes (GTK_LABEL (label), attrs);
|
|
pango_attr_list_unref (attrs);
|
|
gtk_container_add (GTK_CONTAINER (group), label);
|
|
|
|
for (i = 0; tags[i]; i++)
|
|
{
|
|
unsigned int tag;
|
|
GtkWidget *feat;
|
|
FeatureItem *item;
|
|
|
|
tag = hb_tag_from_string (tags[i], -1);
|
|
|
|
feat = gtk_check_button_new_with_label (get_feature_display_name (tag));
|
|
set_inconsistent (GTK_CHECK_BUTTON (feat), TRUE);
|
|
|
|
g_signal_connect (feat, "notify::active", G_CALLBACK (update_display), NULL);
|
|
g_signal_connect (feat, "notify::inconsistent", G_CALLBACK (update_display), NULL);
|
|
g_signal_connect (feat, "clicked", G_CALLBACK (feat_clicked), NULL);
|
|
|
|
gtk_container_add (GTK_CONTAINER (group), feat);
|
|
|
|
item = g_new (FeatureItem, 1);
|
|
item->name = tags[i];
|
|
item->tag = tag;
|
|
item->icon = NULL;
|
|
item->dflt = NULL;
|
|
item->feat = feat;
|
|
|
|
feature_items = g_list_prepend (feature_items, item);
|
|
}
|
|
|
|
gtk_container_add (GTK_CONTAINER (box), group);
|
|
}
|
|
|
|
static void
|
|
add_radio_group (GtkWidget *box,
|
|
const char *title,
|
|
const char **tags)
|
|
{
|
|
GtkWidget *label;
|
|
GtkWidget *group;
|
|
int i;
|
|
GtkWidget *group_button = NULL;
|
|
PangoAttrList *attrs;
|
|
|
|
group = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
|
gtk_widget_set_halign (group, GTK_ALIGN_START);
|
|
|
|
label = gtk_label_new (title);
|
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
|
gtk_widget_set_halign (label, GTK_ALIGN_START);
|
|
g_object_set (label, "margin-top", 10, "margin-bottom", 10, NULL);
|
|
attrs = pango_attr_list_new ();
|
|
pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
|
|
gtk_label_set_attributes (GTK_LABEL (label), attrs);
|
|
pango_attr_list_unref (attrs);
|
|
gtk_container_add (GTK_CONTAINER (group), label);
|
|
|
|
for (i = 0; tags[i]; i++)
|
|
{
|
|
unsigned int tag;
|
|
GtkWidget *feat;
|
|
FeatureItem *item;
|
|
const char *name;
|
|
|
|
tag = hb_tag_from_string (tags[i], -1);
|
|
name = get_feature_display_name (tag);
|
|
|
|
feat = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (group_button),
|
|
name ? name : _("Default"));
|
|
if (group_button == NULL)
|
|
group_button = feat;
|
|
|
|
g_signal_connect (feat, "notify::active", G_CALLBACK (update_display), NULL);
|
|
g_object_set_data (G_OBJECT (feat), "default", group_button);
|
|
|
|
gtk_container_add (GTK_CONTAINER (group), feat);
|
|
|
|
item = g_new (FeatureItem, 1);
|
|
item->name = tags[i];
|
|
item->tag = tag;
|
|
item->icon = NULL;
|
|
item->dflt = NULL;
|
|
item->feat = feat;
|
|
|
|
feature_items = g_list_prepend (feature_items, item);
|
|
}
|
|
|
|
gtk_container_add (GTK_CONTAINER (box), group);
|
|
}
|
|
|
|
static void
|
|
update_display (void)
|
|
{
|
|
GString *s;
|
|
const char *text;
|
|
gboolean has_feature;
|
|
GtkTreeIter iter;
|
|
GtkTreeModel *model;
|
|
PangoFontDescription *desc;
|
|
GList *l;
|
|
PangoAttrList *attrs;
|
|
PangoAttribute *attr;
|
|
gint ins, bound;
|
|
guint start, end;
|
|
PangoLanguage *lang;
|
|
char *font_desc;
|
|
char *features;
|
|
|
|
text = gtk_editable_get_text (GTK_EDITABLE (entry));
|
|
|
|
if (gtk_label_get_selection_bounds (GTK_LABEL (label), &ins, &bound))
|
|
{
|
|
start = g_utf8_offset_to_pointer (text, ins) - text;
|
|
end = g_utf8_offset_to_pointer (text, bound) - text;
|
|
}
|
|
else
|
|
{
|
|
start = PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING;
|
|
end = PANGO_ATTR_INDEX_TO_TEXT_END;
|
|
}
|
|
|
|
desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (font));
|
|
|
|
s = g_string_new ("");
|
|
add_font_variations (s);
|
|
if (s->len > 0)
|
|
{
|
|
pango_font_description_set_variations (desc, s->str);
|
|
g_string_free (s, TRUE);
|
|
}
|
|
|
|
font_desc = pango_font_description_to_string (desc);
|
|
|
|
s = g_string_new ("");
|
|
|
|
has_feature = FALSE;
|
|
for (l = feature_items; l; l = l->next)
|
|
{
|
|
FeatureItem *item = l->data;
|
|
|
|
if (!gtk_widget_is_sensitive (item->feat))
|
|
continue;
|
|
|
|
if (GTK_IS_RADIO_BUTTON (item->feat))
|
|
{
|
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (item->feat)) &&
|
|
strcmp (item->name, "xxxx") != 0)
|
|
{
|
|
if (has_feature)
|
|
g_string_append (s, ", ");
|
|
g_string_append (s, item->name);
|
|
g_string_append (s, " 1");
|
|
has_feature = TRUE;
|
|
}
|
|
}
|
|
else if (GTK_IS_CHECK_BUTTON (item->feat))
|
|
{
|
|
if (gtk_check_button_get_inconsistent (GTK_CHECK_BUTTON (item->feat)))
|
|
continue;
|
|
|
|
if (has_feature)
|
|
g_string_append (s, ", ");
|
|
g_string_append (s, item->name);
|
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (item->feat)))
|
|
g_string_append (s, " 1");
|
|
else
|
|
g_string_append (s, " 0");
|
|
has_feature = TRUE;
|
|
}
|
|
}
|
|
|
|
features = g_string_free (s, FALSE);
|
|
|
|
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (script_lang), &iter))
|
|
{
|
|
hb_tag_t lang_tag;
|
|
|
|
model = gtk_combo_box_get_model (GTK_COMBO_BOX (script_lang));
|
|
gtk_tree_model_get (model, &iter,
|
|
3, &lang_tag,
|
|
-1);
|
|
|
|
lang = pango_language_from_string (hb_language_to_string (hb_ot_tag_to_language (lang_tag)));
|
|
}
|
|
else
|
|
lang = NULL;
|
|
|
|
ensure_range (start, end, desc, features, lang);
|
|
|
|
attrs = pango_attr_list_new ();
|
|
|
|
for (l = ranges; l; l = l->next)
|
|
{
|
|
Range *range = l->data;
|
|
|
|
attr = pango_attr_font_desc_new (range->desc);
|
|
attr->start_index = range->start;
|
|
attr->end_index = range->end;
|
|
pango_attr_list_insert (attrs, attr);
|
|
|
|
attr = pango_attr_font_features_new (range->features);
|
|
attr->start_index = range->start;
|
|
attr->end_index = range->end;
|
|
pango_attr_list_insert (attrs, attr);
|
|
|
|
if (range->language)
|
|
{
|
|
attr = pango_attr_language_new (range->language);
|
|
attr->start_index = range->start;
|
|
attr->end_index = range->end;
|
|
pango_attr_list_insert (attrs, attr);
|
|
}
|
|
}
|
|
|
|
gtk_label_set_text (GTK_LABEL (description), font_desc);
|
|
gtk_label_set_text (GTK_LABEL (settings), features);
|
|
gtk_label_set_text (GTK_LABEL (label), text);
|
|
gtk_label_set_attributes (GTK_LABEL (label), attrs);
|
|
|
|
g_free (font_desc);
|
|
pango_font_description_free (desc);
|
|
g_free (features);
|
|
pango_attr_list_unref (attrs);
|
|
}
|
|
|
|
static PangoFont *
|
|
get_pango_font (void)
|
|
{
|
|
PangoFontDescription *desc;
|
|
PangoContext *context;
|
|
|
|
desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (font));
|
|
context = gtk_widget_get_pango_context (font);
|
|
|
|
return pango_context_load_font (context, desc);
|
|
}
|
|
|
|
typedef struct {
|
|
hb_tag_t script_tag;
|
|
hb_tag_t lang_tag;
|
|
unsigned int script_index;
|
|
unsigned int lang_index;
|
|
} TagPair;
|
|
|
|
static guint
|
|
tag_pair_hash (gconstpointer data)
|
|
{
|
|
const TagPair *pair = data;
|
|
|
|
return pair->script_tag + pair->lang_tag;
|
|
}
|
|
|
|
static gboolean
|
|
tag_pair_equal (gconstpointer a, gconstpointer b)
|
|
{
|
|
const TagPair *pair_a = a;
|
|
const TagPair *pair_b = b;
|
|
|
|
return pair_a->script_tag == pair_b->script_tag && pair_a->lang_tag == pair_b->lang_tag;
|
|
}
|
|
|
|
static int
|
|
script_sort_func (GtkTreeModel *model,
|
|
GtkTreeIter *a,
|
|
GtkTreeIter *b,
|
|
gpointer user_data)
|
|
{
|
|
char *sa, *sb;
|
|
int ret;
|
|
|
|
gtk_tree_model_get (model, a, 0, &sa, -1);
|
|
gtk_tree_model_get (model, b, 0, &sb, -1);
|
|
|
|
ret = strcmp (sa, sb);
|
|
|
|
g_free (sa);
|
|
g_free (sb);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
update_script_combo (void)
|
|
{
|
|
GtkListStore *store;
|
|
hb_font_t *hb_font;
|
|
gint i, j, k;
|
|
FT_Face ft_face;
|
|
PangoFont *pango_font;
|
|
GHashTable *tags;
|
|
GHashTableIter iter;
|
|
TagPair *pair;
|
|
char *lang;
|
|
hb_tag_t active;
|
|
GtkTreeIter active_iter;
|
|
gboolean have_active = FALSE;
|
|
|
|
lang = gtk_font_chooser_get_language (GTK_FONT_CHOOSER (font));
|
|
|
|
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
|
active = hb_ot_tag_from_language (hb_language_from_string (lang, -1));
|
|
G_GNUC_END_IGNORE_DEPRECATIONS
|
|
|
|
g_free (lang);
|
|
|
|
store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
|
|
|
|
pango_font = get_pango_font ();
|
|
ft_face = pango_fc_font_lock_face (PANGO_FC_FONT (pango_font)),
|
|
hb_font = hb_ft_font_create (ft_face, NULL);
|
|
|
|
tags = g_hash_table_new_full (tag_pair_hash, tag_pair_equal, g_free, NULL);
|
|
|
|
pair = g_new (TagPair, 1);
|
|
pair->script_tag = HB_OT_TAG_DEFAULT_SCRIPT;
|
|
pair->lang_tag = HB_OT_TAG_DEFAULT_LANGUAGE;
|
|
g_hash_table_add (tags, pair);
|
|
|
|
if (hb_font)
|
|
{
|
|
hb_tag_t tables[2] = { HB_OT_TAG_GSUB, HB_OT_TAG_GPOS };
|
|
hb_face_t *hb_face;
|
|
|
|
hb_face = hb_font_get_face (hb_font);
|
|
|
|
for (i= 0; i < 2; i++)
|
|
{
|
|
hb_tag_t scripts[80];
|
|
unsigned int script_count = G_N_ELEMENTS (scripts);
|
|
|
|
hb_ot_layout_table_get_script_tags (hb_face, tables[i], 0, &script_count, scripts);
|
|
for (j = 0; j < script_count; j++)
|
|
{
|
|
hb_tag_t languages[80];
|
|
unsigned int language_count = G_N_ELEMENTS (languages);
|
|
|
|
hb_ot_layout_script_get_language_tags (hb_face, tables[i], j, 0, &language_count, languages);
|
|
for (k = 0; k < language_count; k++)
|
|
{
|
|
pair = g_new (TagPair, 1);
|
|
pair->script_tag = scripts[j];
|
|
pair->lang_tag = languages[k];
|
|
pair->script_index = j;
|
|
pair->lang_index = k;
|
|
g_hash_table_add (tags, pair);
|
|
}
|
|
}
|
|
}
|
|
|
|
hb_face_destroy (hb_face);
|
|
}
|
|
|
|
pango_fc_font_unlock_face (PANGO_FC_FONT (pango_font));
|
|
g_object_unref (pango_font);
|
|
|
|
g_hash_table_iter_init (&iter, tags);
|
|
while (g_hash_table_iter_next (&iter, (gpointer *)&pair, NULL))
|
|
{
|
|
const char *langname;
|
|
char langbuf[5];
|
|
GtkTreeIter iter;
|
|
|
|
if (pair->lang_tag == HB_OT_TAG_DEFAULT_LANGUAGE)
|
|
langname = NC_("Language", "Default");
|
|
else
|
|
{
|
|
langname = get_language_name_for_tag (pair->lang_tag);
|
|
if (!langname)
|
|
{
|
|
hb_tag_to_string (pair->lang_tag, langbuf);
|
|
langbuf[4] = 0;
|
|
langname = langbuf;
|
|
}
|
|
}
|
|
|
|
gtk_list_store_insert_with_values (store, &iter, -1,
|
|
0, langname,
|
|
1, pair->script_index,
|
|
2, pair->lang_index,
|
|
3, pair->lang_tag,
|
|
-1);
|
|
if (pair->lang_tag == active)
|
|
{
|
|
have_active = TRUE;
|
|
active_iter = iter;
|
|
}
|
|
}
|
|
|
|
g_hash_table_destroy (tags);
|
|
|
|
gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (store),
|
|
script_sort_func, NULL, NULL);
|
|
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
|
|
GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
|
|
GTK_SORT_ASCENDING);
|
|
gtk_combo_box_set_model (GTK_COMBO_BOX (script_lang), GTK_TREE_MODEL (store));
|
|
if (have_active)
|
|
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (script_lang), &active_iter);
|
|
else
|
|
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (script_lang), 0);
|
|
}
|
|
|
|
static void
|
|
update_features (void)
|
|
{
|
|
gint i, j;
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
guint script_index, lang_index;
|
|
PangoFont *pango_font;
|
|
FT_Face ft_face;
|
|
hb_font_t *hb_font;
|
|
GList *l;
|
|
|
|
for (l = feature_items; l; l = l->next)
|
|
{
|
|
FeatureItem *item = l->data;
|
|
gtk_widget_hide (item->feat);
|
|
gtk_widget_hide (gtk_widget_get_parent (item->feat));
|
|
if (strcmp (item->name, "xxxx") == 0)
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item->feat), TRUE);
|
|
}
|
|
|
|
/* set feature presence checks from the font features */
|
|
|
|
if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (script_lang), &iter))
|
|
return;
|
|
|
|
model = gtk_combo_box_get_model (GTK_COMBO_BOX (script_lang));
|
|
gtk_tree_model_get (model, &iter,
|
|
1, &script_index,
|
|
2, &lang_index,
|
|
-1);
|
|
|
|
pango_font = get_pango_font ();
|
|
ft_face = pango_fc_font_lock_face (PANGO_FC_FONT (pango_font)),
|
|
hb_font = hb_ft_font_create (ft_face, NULL);
|
|
|
|
if (hb_font)
|
|
{
|
|
hb_tag_t tables[2] = { HB_OT_TAG_GSUB, HB_OT_TAG_GPOS };
|
|
hb_face_t *hb_face;
|
|
char *feat;
|
|
|
|
hb_face = hb_font_get_face (hb_font);
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
hb_tag_t features[80];
|
|
unsigned int count = G_N_ELEMENTS(features);
|
|
|
|
hb_ot_layout_language_get_feature_tags (hb_face,
|
|
tables[i],
|
|
script_index,
|
|
lang_index,
|
|
0,
|
|
&count,
|
|
features);
|
|
|
|
for (j = 0; j < count; j++)
|
|
{
|
|
#if 0
|
|
char buf[5];
|
|
hb_tag_to_string (features[j], buf);
|
|
buf[4] = 0;
|
|
g_print ("%s present in %s\n", buf, i == 0 ? "GSUB" : "GPOS");
|
|
#endif
|
|
for (l = feature_items; l; l = l->next)
|
|
{
|
|
FeatureItem *item = l->data;
|
|
|
|
if (item->tag == features[j])
|
|
{
|
|
gtk_widget_show (item->feat);
|
|
gtk_widget_show (gtk_widget_get_parent (item->feat));
|
|
if (GTK_IS_RADIO_BUTTON (item->feat))
|
|
{
|
|
GtkWidget *def = GTK_WIDGET (g_object_get_data (G_OBJECT (item->feat), "default"));
|
|
gtk_widget_show (def);
|
|
}
|
|
else if (GTK_IS_CHECK_BUTTON (item->feat))
|
|
{
|
|
set_inconsistent (GTK_CHECK_BUTTON (item->feat), TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
feat = gtk_font_chooser_get_font_features (GTK_FONT_CHOOSER (font));
|
|
if (feat)
|
|
{
|
|
for (l = feature_items; l; l = l->next)
|
|
{
|
|
FeatureItem *item = l->data;
|
|
char buf[5];
|
|
char *p;
|
|
|
|
hb_tag_to_string (item->tag, buf);
|
|
buf[4] = 0;
|
|
|
|
p = strstr (feat, buf);
|
|
if (p)
|
|
{
|
|
if (GTK_IS_RADIO_BUTTON (item->feat))
|
|
{
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item->feat), p[6] == '1');
|
|
}
|
|
else if (GTK_IS_CHECK_BUTTON (item->feat))
|
|
{
|
|
set_inconsistent (GTK_CHECK_BUTTON (item->feat), FALSE);
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item->feat), p[6] == '1');
|
|
}
|
|
}
|
|
}
|
|
|
|
g_free (feat);
|
|
}
|
|
|
|
hb_face_destroy (hb_face);
|
|
}
|
|
|
|
pango_fc_font_unlock_face (PANGO_FC_FONT (pango_font));
|
|
g_object_unref (pango_font);
|
|
}
|
|
|
|
#define FixedToFloat(f) (((float)(f))/65536.0)
|
|
|
|
static void
|
|
adjustment_changed (GtkAdjustment *adjustment,
|
|
GtkEntry *entry)
|
|
{
|
|
char *str;
|
|
|
|
str = g_strdup_printf ("%g", gtk_adjustment_get_value (adjustment));
|
|
gtk_editable_set_text (GTK_EDITABLE (entry), str);
|
|
g_free (str);
|
|
|
|
update_display ();
|
|
}
|
|
|
|
static void
|
|
entry_activated (GtkEntry *entry,
|
|
GtkAdjustment *adjustment)
|
|
{
|
|
gdouble value;
|
|
gchar *err = NULL;
|
|
|
|
value = g_strtod (gtk_editable_get_text (GTK_EDITABLE (entry)), &err);
|
|
if (err != NULL)
|
|
gtk_adjustment_set_value (adjustment, value);
|
|
}
|
|
|
|
static void unset_instance (GtkAdjustment *adjustment);
|
|
|
|
typedef struct {
|
|
guint32 tag;
|
|
GtkAdjustment *adjustment;
|
|
} Axis;
|
|
|
|
static GHashTable *axes;
|
|
|
|
static void
|
|
add_font_variations (GString *s)
|
|
{
|
|
GHashTableIter iter;
|
|
Axis *axis;
|
|
char buf[G_ASCII_DTOSTR_BUF_SIZE];
|
|
char *sep = "";
|
|
|
|
g_hash_table_iter_init (&iter, axes);
|
|
while (g_hash_table_iter_next (&iter, (gpointer *)NULL, (gpointer *)&axis))
|
|
{
|
|
char tag[5];
|
|
double value;
|
|
|
|
hb_tag_to_string (axis->tag, tag);
|
|
tag[4] = '\0';
|
|
value = gtk_adjustment_get_value (axis->adjustment);
|
|
|
|
g_string_append_printf (s, "%s%s=%s", sep, tag, g_ascii_dtostr (buf, sizeof (buf), value));
|
|
sep = ",";
|
|
}
|
|
}
|
|
|
|
static guint
|
|
axes_hash (gconstpointer v)
|
|
{
|
|
const Axis *p = v;
|
|
|
|
return p->tag;
|
|
}
|
|
|
|
static gboolean
|
|
axes_equal (gconstpointer v1, gconstpointer v2)
|
|
{
|
|
const Axis *p1 = v1;
|
|
const Axis *p2 = v2;
|
|
|
|
return p1->tag == p2->tag;
|
|
}
|
|
|
|
static void
|
|
add_axis (FT_Var_Axis *ax, FT_Fixed value, int i)
|
|
{
|
|
GtkWidget *axis_label;
|
|
GtkWidget *axis_entry;
|
|
GtkWidget *axis_scale;
|
|
GtkAdjustment *adjustment;
|
|
Axis *axis;
|
|
|
|
axis_label = gtk_label_new (ax->name);
|
|
gtk_widget_set_halign (axis_label, GTK_ALIGN_START);
|
|
gtk_widget_set_valign (axis_label, GTK_ALIGN_BASELINE);
|
|
gtk_grid_attach (GTK_GRID (variations_grid), axis_label, 0, i, 1, 1);
|
|
adjustment = gtk_adjustment_new ((double)FixedToFloat(value),
|
|
(double)FixedToFloat(ax->minimum),
|
|
(double)FixedToFloat(ax->maximum),
|
|
1.0, 10.0, 0.0);
|
|
axis_scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, adjustment);
|
|
gtk_scale_add_mark (GTK_SCALE (axis_scale), (double)FixedToFloat(ax->def), GTK_POS_TOP, NULL);
|
|
gtk_widget_set_valign (axis_scale, GTK_ALIGN_BASELINE);
|
|
gtk_widget_set_hexpand (axis_scale, TRUE);
|
|
gtk_widget_set_size_request (axis_scale, 100, -1);
|
|
gtk_scale_set_draw_value (GTK_SCALE (axis_scale), FALSE);
|
|
gtk_grid_attach (GTK_GRID (variations_grid), axis_scale, 1, i, 1, 1);
|
|
axis_entry = gtk_entry_new ();
|
|
gtk_widget_set_valign (axis_entry, GTK_ALIGN_BASELINE);
|
|
gtk_editable_set_width_chars (GTK_EDITABLE (axis_entry), 4);
|
|
gtk_grid_attach (GTK_GRID (variations_grid), axis_entry, 2, i, 1, 1);
|
|
|
|
axis = g_new (Axis, 1);
|
|
axis->tag = ax->tag;
|
|
axis->adjustment = adjustment;
|
|
g_hash_table_add (axes, axis);
|
|
|
|
adjustment_changed (adjustment, GTK_ENTRY (axis_entry));
|
|
|
|
g_signal_connect (adjustment, "value-changed", G_CALLBACK (adjustment_changed), axis_entry);
|
|
g_signal_connect (adjustment, "value-changed", G_CALLBACK (unset_instance), NULL);
|
|
g_signal_connect (axis_entry, "activate", G_CALLBACK (entry_activated), adjustment);
|
|
}
|
|
|
|
typedef struct {
|
|
char *name;
|
|
int n_axes;
|
|
guint32 *axes;
|
|
float *coords;
|
|
} Instance;
|
|
|
|
static guint
|
|
instance_hash (gconstpointer v)
|
|
{
|
|
const Instance *p = v;
|
|
|
|
return g_str_hash (p->name);
|
|
}
|
|
|
|
static gboolean
|
|
instance_equal (gconstpointer v1, gconstpointer v2)
|
|
{
|
|
const Instance *p1 = v1;
|
|
const Instance *p2 = v2;
|
|
|
|
return g_str_equal (p1->name, p2->name);
|
|
}
|
|
|
|
static void
|
|
free_instance (gpointer data)
|
|
{
|
|
Instance *instance = data;
|
|
|
|
g_free (instance->name);
|
|
g_free (instance->axes);
|
|
g_free (instance->coords);
|
|
g_free (instance);
|
|
}
|
|
|
|
static GHashTable *instances;
|
|
|
|
typedef struct {
|
|
const FT_UShort platform_id;
|
|
const FT_UShort encoding_id;
|
|
const char fromcode[12];
|
|
} FtEncoding;
|
|
|
|
#define TT_ENCODING_DONT_CARE 0xffff
|
|
|
|
static const FtEncoding ftEncoding[] = {
|
|
{ TT_PLATFORM_APPLE_UNICODE, TT_ENCODING_DONT_CARE, "UTF-16BE" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, "MACINTOSH" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_ID_JAPANESE, "SJIS" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, "UTF-16BE" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, "UTF-16BE" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, "SJIS-WIN" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, "GB2312" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, "BIG-5" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, "Wansung" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, "Johab" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, "UTF-16BE" },
|
|
{ TT_PLATFORM_ISO, TT_ISO_ID_7BIT_ASCII, "ASCII" },
|
|
{ TT_PLATFORM_ISO, TT_ISO_ID_10646, "UTF-16BE" },
|
|
{ TT_PLATFORM_ISO, TT_ISO_ID_8859_1, "ISO-8859-1" },
|
|
};
|
|
|
|
typedef struct {
|
|
const FT_UShort platform_id;
|
|
const FT_UShort language_id;
|
|
const char lang[8];
|
|
} FtLanguage;
|
|
|
|
#define TT_LANGUAGE_DONT_CARE 0xffff
|
|
|
|
static const FtLanguage ftLanguage[] = {
|
|
{ TT_PLATFORM_APPLE_UNICODE, TT_LANGUAGE_DONT_CARE, "" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ENGLISH, "en" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FRENCH, "fr" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GERMAN, "de" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ITALIAN, "it" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DUTCH, "nl" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SWEDISH, "sv" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SPANISH, "es" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DANISH, "da" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PORTUGUESE, "pt" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_NORWEGIAN, "no" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HEBREW, "he" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_JAPANESE, "ja" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ARABIC, "ar" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FINNISH, "fi" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREEK, "el" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ICELANDIC, "is" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALTESE, "mt" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TURKISH, "tr" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CROATIAN, "hr" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHINESE_TRADITIONAL, "zh-tw" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_URDU, "ur" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HINDI, "hi" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_THAI, "th" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KOREAN, "ko" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LITHUANIAN, "lt" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_POLISH, "pl" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HUNGARIAN, "hu" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ESTONIAN, "et" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LETTISH, "lv" },
|
|
/* { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SAAMISK, ??? */
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FAEROESE, "fo" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FARSI, "fa" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUSSIAN, "ru" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHINESE_SIMPLIFIED, "zh-cn" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FLEMISH, "nl" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH, "ga" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ALBANIAN, "sq" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ROMANIAN, "ro" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CZECH, "cs" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SLOVAK, "sk" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SLOVENIAN, "sl" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_YIDDISH, "yi" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SERBIAN, "sr" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MACEDONIAN, "mk" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BULGARIAN, "bg" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UKRAINIAN, "uk" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BYELORUSSIAN, "be" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UZBEK, "uz" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KAZAKH, "kk" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI, "az" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT, "az" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT, "ar" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ARMENIAN, "hy" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GEORGIAN, "ka" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MOLDAVIAN, "mo" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KIRGHIZ, "ky" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAJIKI, "tg" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TURKMEN, "tk" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN, "mo" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT,"mo" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT, "mo" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PASHTO, "ps" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KURDISH, "ku" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KASHMIRI, "ks" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SINDHI, "sd" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TIBETAN, "bo" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_NEPALI, "ne" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SANSKRIT, "sa" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MARATHI, "mr" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BENGALI, "bn" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ASSAMESE, "as" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GUJARATI, "gu" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PUNJABI, "pa" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ORIYA, "or" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAYALAM, "ml" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KANNADA, "kn" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAMIL, "ta" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TELUGU, "te" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SINHALESE, "si" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BURMESE, "my" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KHMER, "km" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LAO, "lo" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_VIETNAMESE, "vi" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_INDONESIAN, "id" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAGALOG, "tl" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAY_ROMAN_SCRIPT, "ms" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAY_ARABIC_SCRIPT, "ms" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AMHARIC, "am" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TIGRINYA, "ti" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GALLA, "om" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SOMALI, "so" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SWAHILI, "sw" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUANDA, "rw" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUNDI, "rn" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHEWA, "ny" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAGASY, "mg" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ESPERANTO, "eo" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_WELSH, "cy" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BASQUE, "eu" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CATALAN, "ca" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LATIN, "la" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_QUECHUA, "qu" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GUARANI, "gn" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AYMARA, "ay" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TATAR, "tt" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UIGHUR, "ug" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DZONGKHA, "dz" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_JAVANESE, "jw" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SUNDANESE, "su" },
|
|
|
|
#if 0 /* these seem to be errors that have been dropped */
|
|
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SCOTTISH_GAELIC },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH_GAELIC },
|
|
|
|
#endif
|
|
|
|
/* The following codes are new as of 2000-03-10 */
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GALICIAN, "gl" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AFRIKAANS, "af" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BRETON, "br" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_INUKTITUT, "iu" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SCOTTISH_GAELIC, "gd" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MANX_GAELIC, "gv" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH_GAELIC, "ga" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TONGAN, "to" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREEK_POLYTONIC, "el" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREELANDIC, "ik" },
|
|
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT,"az" },
|
|
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_SAUDI_ARABIA, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_IRAQ, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_EGYPT, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_LIBYA, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_ALGERIA, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_MOROCCO, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_TUNISIA, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_OMAN, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_YEMEN, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_SYRIA, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_JORDAN, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_LEBANON, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_KUWAIT, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_UAE, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_BAHRAIN, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_QATAR, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BULGARIAN_BULGARIA, "bg" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CATALAN_SPAIN, "ca" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_TAIWAN, "zh-tw" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_PRC, "zh-cn" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_HONG_KONG, "zh-hk" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_SINGAPORE, "zh-sg" },
|
|
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_MACAU, "zh-mo" },
|
|
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CZECH_CZECH_REPUBLIC, "cs" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DANISH_DENMARK, "da" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_GERMANY, "de" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_SWITZERLAND, "de" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_AUSTRIA, "de" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_LUXEMBOURG, "de" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_LIECHTENSTEI, "de" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GREEK_GREECE, "el" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_UNITED_STATES, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_UNITED_KINGDOM, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_AUSTRALIA, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_CANADA, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_NEW_ZEALAND, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_IRELAND, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_SOUTH_AFRICA, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_JAMAICA, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_CARIBBEAN, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_BELIZE, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_TRINIDAD, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_ZIMBABWE, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_PHILIPPINES, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT,"es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_MEXICO, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT,"es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_GUATEMALA, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_COSTA_RICA, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PANAMA, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC,"es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_VENEZUELA, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_COLOMBIA, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PERU, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_ARGENTINA, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_ECUADOR, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_CHILE, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_URUGUAY, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PARAGUAY, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_BOLIVIA, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_EL_SALVADOR, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_HONDURAS, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_NICARAGUA, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PUERTO_RICO, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FINNISH_FINLAND, "fi" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_FRANCE, "fr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_BELGIUM, "fr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CANADA, "fr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_SWITZERLAND, "fr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_LUXEMBOURG, "fr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MONACO, "fr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HEBREW_ISRAEL, "he" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HUNGARIAN_HUNGARY, "hu" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ICELANDIC_ICELAND, "is" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ITALIAN_ITALY, "it" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ITALIAN_SWITZERLAND, "it" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_JAPANESE_JAPAN, "ja" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA,"ko" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KOREAN_JOHAB_KOREA, "ko" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DUTCH_NETHERLANDS, "nl" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DUTCH_BELGIUM, "nl" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL, "no" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK, "nn" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_POLISH_POLAND, "pl" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PORTUGUESE_BRAZIL, "pt" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PORTUGUESE_PORTUGAL, "pt" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND,"rm" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ROMANIAN_ROMANIA, "ro" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MOLDAVIAN_MOLDAVIA, "mo" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RUSSIAN_RUSSIA, "ru" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RUSSIAN_MOLDAVIA, "ru" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CROATIAN_CROATIA, "hr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SERBIAN_SERBIA_LATIN, "sr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC, "sr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SLOVAK_SLOVAKIA, "sk" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ALBANIAN_ALBANIA, "sq" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWEDISH_SWEDEN, "sv" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWEDISH_FINLAND, "sv" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_THAI_THAILAND, "th" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TURKISH_TURKEY, "tr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_URDU_PAKISTAN, "ur" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_INDONESIAN_INDONESIA, "id" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UKRAINIAN_UKRAINE, "uk" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BELARUSIAN_BELARUS, "be" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SLOVENE_SLOVENIA, "sl" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ESTONIAN_ESTONIA, "et" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATVIAN_LATVIA, "lv" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LITHUANIAN_LITHUANIA, "lt" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA,"lt" },
|
|
|
|
#ifdef TT_MS_LANGID_MAORI_NEW_ZELAND
|
|
/* this seems to be an error that have been dropped */
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MAORI_NEW_ZEALAND, "mi" },
|
|
#endif
|
|
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FARSI_IRAN, "fa" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VIETNAMESE_VIET_NAM, "vi" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARMENIAN_ARMENIA, "hy" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN, "az" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC, "az" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BASQUE_SPAIN, "eu" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SORBIAN_GERMANY, "wen" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MACEDONIAN_MACEDONIA, "mk" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SUTU_SOUTH_AFRICA, "st" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TSONGA_SOUTH_AFRICA, "ts" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TSWANA_SOUTH_AFRICA, "tn" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VENDA_SOUTH_AFRICA, "ven" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_XHOSA_SOUTH_AFRICA, "xh" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ZULU_SOUTH_AFRICA, "zu" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA, "af" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GEORGIAN_GEORGIA, "ka" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS, "fo" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HINDI_INDIA, "hi" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALTESE_MALTA, "mt" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SAAMI_LAPONIA, "se" },
|
|
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM,"gd" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IRISH_GAELIC_IRELAND, "ga" },
|
|
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAY_MALAYSIA, "ms" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM, "ms" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KAZAK_KAZAKSTAN, "kk" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWAHILI_KENYA, "sw" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN, "uz" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC, "uz" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TATAR_TATARSTAN, "tt" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BENGALI_INDIA, "bn" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PUNJABI_INDIA, "pa" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GUJARATI_INDIA, "gu" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ORIYA_INDIA, "or" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMIL_INDIA, "ta" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TELUGU_INDIA, "te" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KANNADA_INDIA, "kn" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAYALAM_INDIA, "ml" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ASSAMESE_INDIA, "as" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MARATHI_INDIA, "mr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SANSKRIT_INDIA, "sa" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KONKANI_INDIA, "kok" },
|
|
|
|
/* new as of 2001-01-01 */
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_GENERAL, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_GENERAL, "zh" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_GENERAL, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_WEST_INDIES, "fr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_REUNION, "fr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CONGO, "fr" },
|
|
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_SENEGAL, "fr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CAMEROON, "fr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_COTE_D_IVOIRE, "fr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MALI, "fr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA,"bs" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_URDU_INDIA, "ur" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAJIK_TAJIKISTAN, "tg" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YIDDISH_GERMANY, "yi" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN, "ky" },
|
|
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TURKMEN_TURKMENISTAN, "tk" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MONGOLIAN_MONGOLIA, "mn" },
|
|
|
|
/* the following seems to be inconsistent;
|
|
here is the current "official" way: */
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIBETAN_BHUTAN, "bo" },
|
|
/* and here is what is used by Passport SDK */
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIBETAN_CHINA, "bo" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DZONGHKA_BHUTAN, "dz" },
|
|
/* end of inconsistency */
|
|
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_WELSH_WALES, "cy" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KHMER_CAMBODIA, "km" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LAO_LAOS, "lo" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BURMESE_MYANMAR, "my" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GALICIAN_SPAIN, "gl" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MANIPURI_INDIA, "mni" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SINDHI_INDIA, "sd" },
|
|
/* the following one is only encountered in Microsoft RTF specification */
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KASHMIRI_PAKISTAN, "ks" },
|
|
/* the following one is not in the Passport list, looks like an omission */
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KASHMIRI_INDIA, "ks" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NEPALI_NEPAL, "ne" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NEPALI_INDIA, "ne" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRISIAN_NETHERLANDS, "fy" },
|
|
|
|
/* new as of 2001-03-01 (from Office Xp) */
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_HONG_KONG, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_INDIA, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_MALAYSIA, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_SINGAPORE, "en" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SYRIAC_SYRIA, "syr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SINHALESE_SRI_LANKA, "si" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHEROKEE_UNITED_STATES, "chr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_INUKTITUT_CANADA, "iu" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AMHARIC_ETHIOPIA, "am" },
|
|
#if 0
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMAZIGHT_MOROCCO },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN },
|
|
#endif
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PASHTO_AFGHANISTAN, "ps" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FILIPINO_PHILIPPINES, "phi" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DHIVEHI_MALDIVES, "div" },
|
|
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_OROMO_ETHIOPIA, "om" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIGRIGNA_ETHIOPIA, "ti" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIGRIGNA_ERYTHREA, "ti" },
|
|
|
|
/* New additions from Windows Xp/Passport SDK 2001-11-10. */
|
|
|
|
/* don't ask what this one means... It is commented out currently. */
|
|
#if 0
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GREEK_GREECE2 },
|
|
#endif
|
|
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_UNITED_STATES, "es" },
|
|
/* The following two IDs blatantly violate MS specs by using a */
|
|
/* sublanguage >,. */
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_LATIN_AMERICA, "es" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_NORTH_AFRICA, "fr" },
|
|
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MOROCCO, "fr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_HAITI, "fr" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BENGALI_BANGLADESH, "bn" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN, "ar" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN,"mn" },
|
|
#if 0
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_EDO_NIGERIA },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FULFULDE_NIGERIA },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IBIBIO_NIGERIA },
|
|
#endif
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HAUSA_NIGERIA, "ha" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YORUBA_NIGERIA, "yo" },
|
|
/* language codes from, to, are (still) unknown. */
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IGBO_NIGERIA, "ibo" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KANURI_NIGERIA, "kau" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GUARANI_PARAGUAY, "gn" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HAWAIIAN_UNITED_STATES, "haw" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATIN, "la" },
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SOMALI_SOMALIA, "so" },
|
|
#if 0
|
|
/* Note: Yi does not have a (proper) ISO 639-2 code, since it is mostly */
|
|
/* not written (but OTOH the peculiar writing system is worth */
|
|
/* studying). */
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YI_CHINA },
|
|
#endif
|
|
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES,"pap" },
|
|
};
|
|
|
|
static const char *
|
|
FcSfntNameLanguage (FT_SfntName *sname)
|
|
{
|
|
int i;
|
|
FT_UShort platform_id = sname->platform_id;
|
|
FT_UShort language_id = sname->language_id;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (ftLanguage); i++)
|
|
if (ftLanguage[i].platform_id == platform_id &&
|
|
(ftLanguage[i].language_id == TT_LANGUAGE_DONT_CARE ||
|
|
ftLanguage[i].language_id == language_id))
|
|
{
|
|
if (ftLanguage[i].lang[0] == '\0')
|
|
return NULL;
|
|
else
|
|
return ftLanguage[i].lang;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static char *
|
|
FcSfntNameTranscode (FT_SfntName *name)
|
|
{
|
|
int i;
|
|
const char *fromcode;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (ftEncoding); i++)
|
|
if (ftEncoding[i].platform_id == name->platform_id &&
|
|
(ftEncoding[i].encoding_id == TT_ENCODING_DONT_CARE ||
|
|
ftEncoding[i].encoding_id == name->encoding_id))
|
|
break;
|
|
if (i == G_N_ELEMENTS (ftEncoding))
|
|
return NULL;
|
|
fromcode = ftEncoding[i].fromcode;
|
|
|
|
return g_convert ((const char *)name->string, name->string_len, "UTF-8", fromcode, NULL, NULL, NULL);
|
|
}
|
|
|
|
static char *
|
|
get_sfnt_name (FT_Face ft_face,
|
|
guint nameid)
|
|
{
|
|
guint count;
|
|
guint i, j;
|
|
const char * const *langs = g_get_language_names ();
|
|
char *res = NULL;
|
|
guint pos = G_MAXUINT;
|
|
|
|
count = FT_Get_Sfnt_Name_Count (ft_face);
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
FT_SfntName name;
|
|
const char *lang;
|
|
|
|
if (FT_Get_Sfnt_Name (ft_face, i, &name) != 0)
|
|
continue;
|
|
|
|
if (name.name_id != nameid)
|
|
continue;
|
|
|
|
lang = FcSfntNameLanguage (&name);
|
|
for (j = 0; j < pos && langs[j]; j++)
|
|
{
|
|
if (strcmp (lang, langs[j]) == 0)
|
|
{
|
|
pos = j;
|
|
g_free (res);
|
|
res = FcSfntNameTranscode (&name);
|
|
}
|
|
}
|
|
|
|
if (pos == 0)
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static gboolean
|
|
is_valid_subfamily_id (guint id)
|
|
{
|
|
return id == 2 || id == 17 || (255 < id && id < 32768);
|
|
}
|
|
|
|
static void
|
|
add_instance (FT_Face ft_face,
|
|
FT_MM_Var *ft_mm_var,
|
|
FT_Var_Named_Style *ns,
|
|
GtkWidget *combo,
|
|
int pos)
|
|
{
|
|
Instance *instance;
|
|
int i;
|
|
|
|
instance = g_new0 (Instance, 1);
|
|
|
|
if (is_valid_subfamily_id (ns->strid))
|
|
instance->name = get_sfnt_name (ft_face, ns->strid);
|
|
if (!instance->name)
|
|
instance->name = g_strdup_printf ("Instance %d", pos);
|
|
|
|
g_hash_table_add (instances, instance);
|
|
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), instance->name);
|
|
|
|
instance->n_axes = ft_mm_var->num_axis;
|
|
instance->axes = g_new (guint32, ft_mm_var->num_axis);
|
|
instance->coords = g_new (float, ft_mm_var->num_axis);
|
|
|
|
for (i = 0; i < ft_mm_var->num_axis; i++)
|
|
{
|
|
instance->axes[i] = ft_mm_var->axis[i].tag;
|
|
instance->coords[i] = FixedToFloat(ns->coords[i]);
|
|
}
|
|
}
|
|
|
|
static void
|
|
unset_instance (GtkAdjustment *adjustment)
|
|
{
|
|
if (instance_combo)
|
|
gtk_combo_box_set_active (GTK_COMBO_BOX (instance_combo), 0);
|
|
}
|
|
|
|
static void
|
|
instance_changed (GtkComboBox *combo)
|
|
{
|
|
char *text;
|
|
Instance *instance;
|
|
Instance ikey;
|
|
int i;
|
|
|
|
text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (combo));
|
|
if (text[0] == '\0')
|
|
goto out;
|
|
|
|
ikey.name = text;
|
|
instance = g_hash_table_lookup (instances, &ikey);
|
|
if (!instance)
|
|
{
|
|
g_print ("did not find instance %s\n", text);
|
|
goto out;
|
|
}
|
|
|
|
for (i = 0; i < instance->n_axes; i++)
|
|
{
|
|
Axis *axis;
|
|
Axis akey;
|
|
guint32 tag;
|
|
gdouble value;
|
|
|
|
tag = instance->axes[i];
|
|
value = instance->coords[i];
|
|
|
|
akey.tag = tag;
|
|
axis = g_hash_table_lookup (axes, &akey);
|
|
if (axis)
|
|
{
|
|
g_signal_handlers_block_by_func (axis->adjustment, unset_instance, NULL);
|
|
gtk_adjustment_set_value (axis->adjustment, value);
|
|
g_signal_handlers_unblock_by_func (axis->adjustment, unset_instance, NULL);
|
|
}
|
|
}
|
|
|
|
out:
|
|
g_free (text);
|
|
}
|
|
|
|
static gboolean
|
|
matches_instance (FT_Var_Named_Style *instance,
|
|
FT_Fixed *coords,
|
|
FT_UInt num_coords)
|
|
{
|
|
FT_UInt i;
|
|
|
|
for (i = 0; i < num_coords; i++)
|
|
if (coords[i] != instance->coords[i])
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
add_font_plane (int i)
|
|
{
|
|
GtkWidget *plane;
|
|
Axis *weight_axis;
|
|
Axis *width_axis;
|
|
|
|
Axis key;
|
|
|
|
key.tag = MAKE_TAG('w','g','h','t');
|
|
weight_axis = g_hash_table_lookup (axes, &key);
|
|
key.tag = MAKE_TAG('w','d','t','h');
|
|
width_axis = g_hash_table_lookup (axes, &key);
|
|
|
|
if (weight_axis && width_axis)
|
|
{
|
|
plane = gtk_font_plane_new (weight_axis->adjustment,
|
|
width_axis->adjustment);
|
|
|
|
gtk_widget_set_size_request (plane, 300, 300);
|
|
gtk_widget_set_halign (plane, GTK_ALIGN_CENTER);
|
|
gtk_grid_attach (GTK_GRID (variations_grid), plane, 0, i, 3, 1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
update_font_variations (void)
|
|
{
|
|
GtkWidget *child, *next;
|
|
PangoFont *pango_font;
|
|
FT_Face ft_face;
|
|
FT_MM_Var *ft_mm_var;
|
|
FT_Error ret;
|
|
|
|
child = gtk_widget_get_first_child (variations_grid);
|
|
while (child != NULL)
|
|
{
|
|
next = gtk_widget_get_next_sibling (child);
|
|
gtk_widget_destroy (child);
|
|
child = next;
|
|
}
|
|
|
|
instance_combo = NULL;
|
|
|
|
g_hash_table_remove_all (axes);
|
|
g_hash_table_remove_all (instances);
|
|
|
|
pango_font = get_pango_font ();
|
|
ft_face = pango_fc_font_lock_face (PANGO_FC_FONT (pango_font)),
|
|
|
|
ret = FT_Get_MM_Var (ft_face, &ft_mm_var);
|
|
if (ret == 0)
|
|
{
|
|
unsigned int i;
|
|
FT_Fixed *coords;
|
|
|
|
coords = g_new (FT_Fixed, ft_mm_var->num_axis);
|
|
ret = FT_Get_Var_Design_Coordinates (ft_face, ft_mm_var->num_axis, coords);
|
|
|
|
if (ft_mm_var->num_namedstyles > 0)
|
|
{
|
|
GtkWidget *label;
|
|
GtkWidget *combo;
|
|
|
|
label = gtk_label_new ("Instance");
|
|
gtk_label_set_xalign (GTK_LABEL (label), 0);
|
|
gtk_widget_set_halign (label, GTK_ALIGN_START);
|
|
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
|
|
gtk_grid_attach (GTK_GRID (variations_grid), label, 0, -1, 2, 1);
|
|
|
|
combo = gtk_combo_box_text_new ();
|
|
gtk_widget_set_valign (combo, GTK_ALIGN_BASELINE);
|
|
g_signal_connect (combo, "changed", G_CALLBACK (instance_changed), NULL);
|
|
gtk_grid_attach (GTK_GRID (variations_grid), combo, 1, -1, 2, 1);
|
|
|
|
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "");
|
|
|
|
for (i = 0; i < ft_mm_var->num_namedstyles; i++)
|
|
add_instance (ft_face, ft_mm_var, &ft_mm_var->namedstyle[i], combo, i);
|
|
for (i = 0; i < ft_mm_var->num_namedstyles; i++)
|
|
{
|
|
if (matches_instance (&ft_mm_var->namedstyle[i], coords, ft_mm_var->num_axis))
|
|
{
|
|
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), i + 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
instance_combo = combo;
|
|
}
|
|
|
|
if (ret == 0)
|
|
{
|
|
for (i = 0; i < ft_mm_var->num_axis; i++)
|
|
add_axis (&ft_mm_var->axis[i], coords[i], i);
|
|
|
|
add_font_plane (ft_mm_var->num_axis);
|
|
}
|
|
g_free (coords);
|
|
free (ft_mm_var);
|
|
}
|
|
|
|
pango_fc_font_unlock_face (PANGO_FC_FONT (pango_font));
|
|
g_object_unref (pango_font);
|
|
}
|
|
|
|
static void
|
|
font_changed (void)
|
|
{
|
|
update_script_combo ();
|
|
update_features ();
|
|
update_font_variations ();
|
|
}
|
|
|
|
static void
|
|
script_changed (void)
|
|
{
|
|
update_features ();
|
|
update_display ();
|
|
}
|
|
|
|
static void
|
|
reset_features (void)
|
|
{
|
|
GList *l;
|
|
|
|
gtk_label_select_region (GTK_LABEL (label), 0, 0);
|
|
|
|
g_list_free_full (ranges, free_range);
|
|
ranges = NULL;
|
|
|
|
for (l = feature_items; l; l = l->next)
|
|
{
|
|
FeatureItem *item = l->data;
|
|
|
|
if (GTK_IS_RADIO_BUTTON (item->feat))
|
|
{
|
|
if (strcmp (item->name, "xxxx") == 0)
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item->feat), TRUE);
|
|
}
|
|
else if (GTK_IS_CHECK_BUTTON (item->feat))
|
|
{
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item->feat), FALSE);
|
|
set_inconsistent (GTK_CHECK_BUTTON (item->feat), TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
static char *text;
|
|
|
|
static void
|
|
switch_to_entry (void)
|
|
{
|
|
text = g_strdup (gtk_editable_get_text (GTK_EDITABLE (entry)));
|
|
gtk_stack_set_visible_child_name (GTK_STACK (stack), "entry");
|
|
gtk_widget_grab_focus (entry);
|
|
}
|
|
|
|
static void
|
|
switch_to_label (void)
|
|
{
|
|
g_free (text);
|
|
text = NULL;
|
|
gtk_stack_set_visible_child_name (GTK_STACK (stack), "label");
|
|
update_display ();
|
|
}
|
|
|
|
static void
|
|
toggle_edit (void)
|
|
{
|
|
if (strcmp (gtk_stack_get_visible_child_name (GTK_STACK (stack)), "label") == 0)
|
|
switch_to_entry ();
|
|
else
|
|
switch_to_label ();
|
|
}
|
|
|
|
static void
|
|
stop_edit (void)
|
|
{
|
|
g_signal_emit_by_name (edit_toggle, "clicked");
|
|
}
|
|
|
|
static gboolean
|
|
entry_key_press (GtkEventController *controller,
|
|
guint keyval,
|
|
guint keycode,
|
|
GdkModifierType modifiers,
|
|
GtkEntry *entry)
|
|
{
|
|
if (keyval == GDK_KEY_Escape)
|
|
{
|
|
gtk_editable_set_text (GTK_EDITABLE (entry), text);
|
|
stop_edit ();
|
|
return GDK_EVENT_STOP;
|
|
}
|
|
|
|
return GDK_EVENT_PROPAGATE;
|
|
}
|
|
|
|
GtkWidget *
|
|
do_font_features (GtkWidget *do_widget)
|
|
{
|
|
static GtkWidget *window = NULL;
|
|
|
|
if (!window)
|
|
{
|
|
GtkBuilder *builder;
|
|
GtkWidget *feature_list;
|
|
GtkEventController *controller;
|
|
|
|
builder = gtk_builder_new_from_resource ("/font_features/font-features.ui");
|
|
|
|
gtk_builder_add_callback_symbol (builder, "update_display", update_display);
|
|
gtk_builder_add_callback_symbol (builder, "font_changed", font_changed);
|
|
gtk_builder_add_callback_symbol (builder, "script_changed", script_changed);
|
|
gtk_builder_add_callback_symbol (builder, "reset", reset_features);
|
|
gtk_builder_add_callback_symbol (builder, "stop_edit", G_CALLBACK (stop_edit));
|
|
gtk_builder_add_callback_symbol (builder, "toggle_edit", G_CALLBACK (toggle_edit));
|
|
gtk_builder_connect_signals (builder, NULL);
|
|
|
|
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
|
|
feature_list = GTK_WIDGET (gtk_builder_get_object (builder, "feature_list"));
|
|
label = GTK_WIDGET (gtk_builder_get_object (builder, "label"));
|
|
settings = GTK_WIDGET (gtk_builder_get_object (builder, "settings"));
|
|
description = GTK_WIDGET (gtk_builder_get_object (builder, "description"));
|
|
resetbutton = GTK_WIDGET (gtk_builder_get_object (builder, "reset"));
|
|
font = GTK_WIDGET (gtk_builder_get_object (builder, "font"));
|
|
script_lang = GTK_WIDGET (gtk_builder_get_object (builder, "script_lang"));
|
|
stack = GTK_WIDGET (gtk_builder_get_object (builder, "stack"));
|
|
entry = GTK_WIDGET (gtk_builder_get_object (builder, "entry"));
|
|
edit_toggle = GTK_WIDGET (gtk_builder_get_object (builder, "edit_toggle"));
|
|
|
|
controller = gtk_event_controller_key_new ();
|
|
g_object_set_data_full (G_OBJECT (entry), "controller", controller, g_object_unref);
|
|
g_signal_connect (controller, "key-pressed", G_CALLBACK (entry_key_press), entry);
|
|
gtk_widget_add_controller (entry, controller);
|
|
|
|
add_check_group (feature_list, _("Kerning"), (const char *[]){ "kern", NULL });
|
|
add_check_group (feature_list, _("Ligatures"), (const char *[]){ "liga",
|
|
"dlig",
|
|
"hlig",
|
|
"clig",
|
|
"rlig", NULL });
|
|
add_check_group (feature_list, _("Letter Case"), (const char *[]){ "smcp",
|
|
"c2sc",
|
|
"pcap",
|
|
"c2pc",
|
|
"unic",
|
|
"cpsp",
|
|
"case",NULL });
|
|
add_radio_group (feature_list, _("Number Case"), (const char *[]){ "xxxx",
|
|
"lnum",
|
|
"onum", NULL });
|
|
add_radio_group (feature_list, _("Number Spacing"), (const char *[]){ "xxxx",
|
|
"pnum",
|
|
"tnum", NULL });
|
|
add_radio_group (feature_list, _("Fractions"), (const char *[]){ "xxxx",
|
|
"frac",
|
|
"afrc", NULL });
|
|
add_check_group (feature_list, _("Numeric Extras"), (const char *[]){ "zero",
|
|
"nalt",
|
|
"sinf", NULL });
|
|
add_check_group (feature_list, _("Character Alternatives"), (const char *[]){ "swsh",
|
|
"cswh",
|
|
"locl",
|
|
"calt",
|
|
"falt",
|
|
"hist",
|
|
"salt",
|
|
"jalt",
|
|
"titl",
|
|
"rand",
|
|
"subs",
|
|
"sups",
|
|
"ordn",
|
|
"ltra",
|
|
"ltrm",
|
|
"rtla",
|
|
"rtlm",
|
|
"rclt", NULL });
|
|
add_check_group (feature_list, _("Positional Alternatives"), (const char *[]){ "init",
|
|
"medi",
|
|
"med2",
|
|
"fina",
|
|
"fin2",
|
|
"fin3",
|
|
"isol", NULL });
|
|
add_check_group (feature_list, _("Width Variants"), (const char *[]){ "fwid",
|
|
"hwid",
|
|
"halt",
|
|
"pwid",
|
|
"palt",
|
|
"twid",
|
|
"qwid", NULL });
|
|
add_check_group (feature_list, _("Alternative Stylistic Sets"), (const char *[]){ "ss00",
|
|
"ss01",
|
|
"ss02",
|
|
"ss03",
|
|
"ss04",
|
|
"ss05",
|
|
"ss06",
|
|
"ss07",
|
|
"ss08",
|
|
"ss09",
|
|
"ss10",
|
|
"ss11",
|
|
"ss12",
|
|
"ss13",
|
|
"ss14",
|
|
"ss15",
|
|
"ss16",
|
|
"ss17",
|
|
"ss18",
|
|
"ss19",
|
|
"ss20", NULL });
|
|
add_check_group (feature_list, _("Mathematical"), (const char *[]){ "dtls",
|
|
"flac",
|
|
"mgrk",
|
|
"ssty", NULL });
|
|
add_check_group (feature_list, _("Optical Bounds"), (const char *[]){ "opbd",
|
|
"lfbd",
|
|
"rtbd", NULL });
|
|
feature_items = g_list_reverse (feature_items);
|
|
|
|
variations_heading = GTK_WIDGET (gtk_builder_get_object (builder, "variations_heading"));
|
|
variations_grid = GTK_WIDGET (gtk_builder_get_object (builder, "variations_grid"));
|
|
if (instances == NULL)
|
|
instances = g_hash_table_new_full (instance_hash, instance_equal, NULL, free_instance);
|
|
else
|
|
g_hash_table_remove_all (instances);
|
|
|
|
if (axes == NULL)
|
|
axes = g_hash_table_new_full (axes_hash, axes_equal, NULL, g_free);
|
|
else
|
|
g_hash_table_remove_all (axes);
|
|
|
|
font_changed ();
|
|
|
|
g_signal_connect (window, "destroy",
|
|
G_CALLBACK (gtk_widget_destroyed), &window);
|
|
|
|
g_object_unref (builder);
|
|
}
|
|
|
|
if (!gtk_widget_get_visible (window))
|
|
gtk_window_present (GTK_WINDOW (window));
|
|
else
|
|
gtk_widget_destroy (window);
|
|
|
|
return window;
|
|
}
|