blob: 79245b5ab93fb8eb81d08194d9117b3a788f1914 [file] [log] [blame]
/* Pango
* pango-ot-ruleset.c: Shaping using OpenType features
*
* Copyright (C) 2000 Red Hat Software
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <freetype/internal/ftmemory.h>
#include <pango/pango-ot.h>
#include "pango-ot-private.h"
typedef struct _PangoOTRule PangoOTRule;
struct _PangoOTRule
{
gulong property_bit;
FT_UShort feature_index;
guint table_type : 1;
};
static void pango_ot_ruleset_class_init (GObjectClass *object_class);
static void pango_ot_ruleset_init (PangoOTRuleset *ruleset);
static void pango_ot_ruleset_finalize (GObject *object);
static GObjectClass *parent_class;
GType
pango_ot_ruleset_get_type (void)
{
static GType object_type = 0;
if (!object_type)
{
static const GTypeInfo object_info =
{
sizeof (PangoOTRulesetClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc)pango_ot_ruleset_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (PangoOTRuleset),
0, /* n_preallocs */
(GInstanceInitFunc)pango_ot_ruleset_init,
};
object_type = g_type_register_static (G_TYPE_OBJECT,
"PangoOTRuleset",
&object_info, 0);
}
return object_type;
}
static void
pango_ot_ruleset_class_init (GObjectClass *object_class)
{
parent_class = g_type_class_peek_parent (object_class);
object_class->finalize = pango_ot_ruleset_finalize;
}
static void
pango_ot_ruleset_init (PangoOTRuleset *ruleset)
{
ruleset->rules = g_array_new (FALSE, FALSE, sizeof (PangoOTRule));
}
static void
pango_ot_ruleset_finalize (GObject *object)
{
PangoOTRuleset *ruleset = PANGO_OT_RULESET (object);
g_array_free (ruleset->rules, TRUE);
g_object_unref (G_OBJECT (ruleset->info));
}
PangoOTRuleset *
pango_ot_ruleset_new (PangoOTInfo *info)
{
PangoOTRuleset *ruleset;
ruleset = g_object_new (PANGO_TYPE_OT_RULESET, NULL);
ruleset->info = g_object_ref (G_OBJECT (info));
return ruleset;
}
void
pango_ot_ruleset_add_feature (PangoOTRuleset *ruleset,
PangoOTTableType table_type,
guint feature_index,
gulong property_bit)
{
PangoOTRule tmp_rule;
g_return_if_fail (PANGO_OT_IS_RULESET (ruleset));
tmp_rule.table_type = table_type;
tmp_rule.feature_index = feature_index;
tmp_rule.property_bit = property_bit;
g_array_append_val (ruleset->rules, tmp_rule);
}
void
pango_ot_ruleset_shape (PangoOTRuleset *ruleset,
PangoGlyphString *glyphs,
gulong *properties)
{
int i;
int last_cluster;
TTO_GSUB gsub = NULL;
TTO_GPOS gpos = NULL;
TTO_GSUB_String *in_string = NULL;
TTO_GSUB_String *out_string = NULL;
TTO_GSUB_String *result_string = NULL;
TTO_GPOS_Data *pos_data;
gboolean need_gsub = FALSE;
gboolean need_gpos = FALSE;
g_return_if_fail (PANGO_OT_IS_RULESET (ruleset));
for (i = 0; i < ruleset->rules->len; i++)
{
PangoOTRule *rule = &g_array_index (ruleset->rules, PangoOTRule, i);
if (rule->table_type == PANGO_OT_TABLE_GSUB)
need_gsub = TRUE;
else
need_gpos = TRUE;
}
if (need_gsub)
{
gsub = pango_ot_info_get_gsub (ruleset->info);
if (gsub)
TT_GSUB_Clear_Features (gsub);
}
if (need_gpos)
{
gpos = pango_ot_info_get_gpos (ruleset->info);
if (gpos)
TT_GPOS_Clear_Features (gpos);
}
for (i = 0; i < ruleset->rules->len; i++)
{
PangoOTRule *rule = &g_array_index (ruleset->rules, PangoOTRule, i);
if (rule->table_type == PANGO_OT_TABLE_GSUB)
{
if (gsub)
TT_GSUB_Add_Feature (gsub, rule->feature_index, rule->property_bit);
}
else
{
if (gpos)
TT_GPOS_Add_Feature (gpos, rule->feature_index, rule->property_bit);
}
}
if (!gsub && !gpos)
return;
g_assert (TT_GSUB_String_New (ruleset->info->face->memory,
&in_string) == FT_Err_Ok);
g_assert (TT_GSUB_String_Set_Length (in_string, glyphs->num_glyphs) == FT_Err_Ok);
for (i = 0; i < glyphs->num_glyphs; i++)
{
in_string->string[i] = glyphs->glyphs[i].glyph;
in_string->properties[i] = properties[i];
in_string->logClusters[i] = glyphs->log_clusters[i];
}
in_string->max_ligID = i;
if (gsub)
{
g_assert (TT_GSUB_String_New (ruleset->info->face->memory,
&out_string) == FT_Err_Ok);
result_string = out_string;
TT_GSUB_Apply_String (gsub, in_string, out_string);
}
else
result_string = in_string;
pango_glyph_string_set_size (glyphs, result_string->length);
last_cluster = -1;
for (i = 0; i < result_string->length; i++)
{
glyphs->glyphs[i].glyph = result_string->string[i];
glyphs->glyphs[i].glyph = result_string->string[i];
glyphs->log_clusters[i] = result_string->logClusters[i];
if (glyphs->log_clusters[i] != last_cluster)
glyphs->glyphs[i].attr.is_cluster_start = 1;
else
glyphs->glyphs[i].attr.is_cluster_start = 0;
last_cluster = glyphs->log_clusters[i];
}
if (in_string)
TT_GSUB_String_Done (in_string);
if (out_string)
TT_GSUB_String_Done (out_string);
}