[API] unicode: rework virtual functions for subclassing

Unicode data providers can now be subclassed, including support for
chain-up.  The interface should now be nicely bindable, as well.

Also fix glib unicode funcs that where broken after hb_script_t
changes.  Nicely caught by the test-unicode.c added in this commit.
This commit is contained in:
Ryan Lortie 2011-04-20 00:19:20 -04:00 committed by Behdad Esfahbod
parent f85faee9b3
commit 2fd0c577e3
9 changed files with 610 additions and 164 deletions

View File

@ -35,22 +35,188 @@
HB_BEGIN_DECLS
static hb_codepoint_t hb_glib_get_mirroring (hb_codepoint_t unicode) { g_unichar_get_mirror_char (unicode, &unicode); return unicode; }
static hb_unicode_general_category_t hb_glib_get_general_category (hb_codepoint_t unicode) { return g_unichar_type (unicode); }
static hb_script_t hb_glib_get_script (hb_codepoint_t unicode) { return g_unichar_get_script (unicode); }
static unsigned int hb_glib_get_combining_class (hb_codepoint_t unicode) { return g_unichar_combining_class (unicode); }
static unsigned int hb_glib_get_eastasian_width (hb_codepoint_t unicode) { return g_unichar_iswide (unicode); }
static hb_codepoint_t
hb_glib_get_mirroring (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data)
{
g_unichar_get_mirror_char (unicode, &unicode);
return unicode;
}
static hb_unicode_general_category_t
hb_glib_get_general_category (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data)
{
return g_unichar_type (unicode);
}
static hb_script_t
hb_glib_get_script (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data)
{
GUnicodeScript script = g_unichar_get_script (unicode);
switch (script)
{
#define MATCH_SCRIPT(C) case G_UNICODE_SCRIPT_##C: return HB_SCRIPT_##C
#define MATCH_SCRIPT2(C1, C2) case G_UNICODE_SCRIPT_##C1: return HB_SCRIPT_##C2
MATCH_SCRIPT2(INVALID_CODE, INVALID);
MATCH_SCRIPT (COMMON); /* Zyyy */
MATCH_SCRIPT (INHERITED); /* Qaai */
MATCH_SCRIPT (ARABIC); /* Arab */
MATCH_SCRIPT (ARMENIAN); /* Armn */
MATCH_SCRIPT (BENGALI); /* Beng */
MATCH_SCRIPT (BOPOMOFO); /* Bopo */
MATCH_SCRIPT (CHEROKEE); /* Cher */
MATCH_SCRIPT (COPTIC); /* Qaac */
MATCH_SCRIPT (CYRILLIC); /* Cyrl (Cyrs) */
MATCH_SCRIPT (DESERET); /* Dsrt */
MATCH_SCRIPT (DEVANAGARI); /* Deva */
MATCH_SCRIPT (ETHIOPIC); /* Ethi */
MATCH_SCRIPT (GEORGIAN); /* Geor (Geon); Geoa) */
MATCH_SCRIPT (GOTHIC); /* Goth */
MATCH_SCRIPT (GREEK); /* Grek */
MATCH_SCRIPT (GUJARATI); /* Gujr */
MATCH_SCRIPT (GURMUKHI); /* Guru */
MATCH_SCRIPT (HAN); /* Hani */
MATCH_SCRIPT (HANGUL); /* Hang */
MATCH_SCRIPT (HEBREW); /* Hebr */
MATCH_SCRIPT (HIRAGANA); /* Hira */
MATCH_SCRIPT (KANNADA); /* Knda */
MATCH_SCRIPT (KATAKANA); /* Kana */
MATCH_SCRIPT (KHMER); /* Khmr */
MATCH_SCRIPT (LAO); /* Laoo */
MATCH_SCRIPT (LATIN); /* Latn (Latf); Latg) */
MATCH_SCRIPT (MALAYALAM); /* Mlym */
MATCH_SCRIPT (MONGOLIAN); /* Mong */
MATCH_SCRIPT (MYANMAR); /* Mymr */
MATCH_SCRIPT (OGHAM); /* Ogam */
MATCH_SCRIPT (OLD_ITALIC); /* Ital */
MATCH_SCRIPT (ORIYA); /* Orya */
MATCH_SCRIPT (RUNIC); /* Runr */
MATCH_SCRIPT (SINHALA); /* Sinh */
MATCH_SCRIPT (SYRIAC); /* Syrc (Syrj, Syrn); Syre) */
MATCH_SCRIPT (TAMIL); /* Taml */
MATCH_SCRIPT (TELUGU); /* Telu */
MATCH_SCRIPT (THAANA); /* Thaa */
MATCH_SCRIPT (THAI); /* Thai */
MATCH_SCRIPT (TIBETAN); /* Tibt */
MATCH_SCRIPT (CANADIAN_ABORIGINAL);/* Cans */
MATCH_SCRIPT (YI); /* Yiii */
MATCH_SCRIPT (TAGALOG); /* Tglg */
MATCH_SCRIPT (HANUNOO); /* Hano */
MATCH_SCRIPT (BUHID); /* Buhd */
MATCH_SCRIPT (TAGBANWA); /* Tagb */
/* Unicode-4.0 additions */
MATCH_SCRIPT (BRAILLE); /* Brai */
MATCH_SCRIPT (CYPRIOT); /* Cprt */
MATCH_SCRIPT (LIMBU); /* Limb */
MATCH_SCRIPT (OSMANYA); /* Osma */
MATCH_SCRIPT (SHAVIAN); /* Shaw */
MATCH_SCRIPT (LINEAR_B); /* Linb */
MATCH_SCRIPT (TAI_LE); /* Tale */
MATCH_SCRIPT (UGARITIC); /* Ugar */
/* Unicode-4.1 additions */
MATCH_SCRIPT (NEW_TAI_LUE); /* Talu */
MATCH_SCRIPT (BUGINESE); /* Bugi */
MATCH_SCRIPT (GLAGOLITIC); /* Glag */
MATCH_SCRIPT (TIFINAGH); /* Tfng */
MATCH_SCRIPT (SYLOTI_NAGRI); /* Sylo */
MATCH_SCRIPT (OLD_PERSIAN); /* Xpeo */
MATCH_SCRIPT (KHAROSHTHI); /* Khar */
/* Unicode-5.0 additions */
MATCH_SCRIPT (UNKNOWN); /* Zzzz */
MATCH_SCRIPT (BALINESE); /* Bali */
MATCH_SCRIPT (CUNEIFORM); /* Xsux */
MATCH_SCRIPT (PHOENICIAN); /* Phnx */
MATCH_SCRIPT (PHAGS_PA); /* Phag */
MATCH_SCRIPT (NKO); /* Nkoo */
/* Unicode-5.1 additions */
MATCH_SCRIPT (KAYAH_LI); /* Kali */
MATCH_SCRIPT (LEPCHA); /* Lepc */
MATCH_SCRIPT (REJANG); /* Rjng */
MATCH_SCRIPT (SUNDANESE); /* Sund */
MATCH_SCRIPT (SAURASHTRA); /* Saur */
MATCH_SCRIPT (CHAM); /* Cham */
MATCH_SCRIPT (OL_CHIKI); /* Olck */
MATCH_SCRIPT (VAI); /* Vaii */
MATCH_SCRIPT (CARIAN); /* Cari */
MATCH_SCRIPT (LYCIAN); /* Lyci */
MATCH_SCRIPT (LYDIAN); /* Lydi */
/* Unicode-5.2 additions */
#if GLIB_CHECK_VERSION(2,26,0)
MATCH_SCRIPT (AVESTAN); /* Avst */
MATCH_SCRIPT (BAMUM); /* Bamu */
MATCH_SCRIPT (EGYPTIAN_HIEROGLYPHS); /* Egyp */
MATCH_SCRIPT (IMPERIAL_ARAMAIC); /* Armi */
MATCH_SCRIPT (INSCRIPTIONAL_PAHLAVI); /* Phli */
MATCH_SCRIPT (INSCRIPTIONAL_PARTHIAN); /* Prti */
MATCH_SCRIPT (JAVANESE); /* Java */
MATCH_SCRIPT (KAITHI); /* Kthi */
MATCH_SCRIPT (TAI_THAM); /* Lana */
MATCH_SCRIPT (LISU); /* Lisu */
MATCH_SCRIPT (MEETEI_MAYEK); /* Mtei */
MATCH_SCRIPT (OLD_SOUTH_ARABIAN); /* Sarb */
#if GLIB_CHECK_VERSION(2,28,0)
MATCH_SCRIPT (OLD_TURKIC); /* Orkh */
#else
MATCH_SCRIPT2(OLD_TURKISH, OLD_TURKIC);/* Orkh */
#endif
MATCH_SCRIPT (SAMARITAN); /* Samr */
MATCH_SCRIPT (TAI_VIET); /* Tavt */
#endif
/* Unicode-6.0 additions */
#if GLIB_CHECK_VERSION(2,28,0)
MATCH_SCRIPT (BATAK); /* Batk */
MATCH_SCRIPT (BRAHMI); /* Brah */
MATCH_SCRIPT (MANDAIC); /* Mand */
#endif
#undef MATCH_SCRIPT
#undef MATCH_SCRIPT2
}
return HB_SCRIPT_UNKNOWN;
}
static unsigned int
hb_glib_get_combining_class (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data)
{
return g_unichar_combining_class (unicode);
}
static unsigned int
hb_glib_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data)
{
return g_unichar_iswide (unicode) ? 2 : 1;
}
static hb_unicode_funcs_t glib_ufuncs = {
HB_REFERENCE_COUNT_INVALID, /* ref_count */
NULL,
TRUE, /* immutable */
{
hb_glib_get_general_category,
hb_glib_get_combining_class,
hb_glib_get_mirroring,
hb_glib_get_script,
hb_glib_get_eastasian_width
hb_glib_get_general_category, NULL, NULL,
hb_glib_get_combining_class, NULL, NULL,
hb_glib_get_mirroring, NULL, NULL,
hb_glib_get_script, NULL, NULL,
hb_glib_get_eastasian_width, NULL, NULL
}
};

View File

@ -38,11 +38,27 @@
HB_BEGIN_DECLS
static hb_codepoint_t hb_icu_get_mirroring (hb_codepoint_t unicode) { return u_charMirror(unicode); }
static unsigned int hb_icu_get_combining_class (hb_codepoint_t unicode) { return u_getCombiningClass (unicode); }
static hb_codepoint_t
hb_icu_get_mirroring (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data)
{
return u_charMirror(unicode);
}
static unsigned int
hb_icu_get_eastasian_width (hb_codepoint_t unicode)
hb_icu_get_combining_class (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data)
{
return u_getCombiningClass (unicode);
}
static unsigned int
hb_icu_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data)
{
switch (u_getIntPropertyValue(unicode, UCHAR_EAST_ASIAN_WIDTH))
{
@ -59,7 +75,9 @@ hb_icu_get_eastasian_width (hb_codepoint_t unicode)
}
static hb_unicode_general_category_t
hb_icu_get_general_category (hb_codepoint_t unicode)
hb_icu_get_general_category (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data)
{
switch (u_getIntPropertyValue(unicode, UCHAR_GENERAL_CATEGORY))
{
@ -108,7 +126,9 @@ hb_icu_get_general_category (hb_codepoint_t unicode)
}
static hb_script_t
hb_icu_get_script (hb_codepoint_t unicode)
hb_icu_get_script (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data)
{
UErrorCode status = U_ZERO_ERROR;
UScriptCode scriptCode = uscript_getScript(unicode, &status);
@ -234,19 +254,24 @@ hb_icu_get_script (hb_codepoint_t unicode)
MATCH_SCRIPT (BRAHMI); /* Brah */
MATCH_SCRIPT2(MANDAEAN, MANDAIC); /* Mand */
#undef CHECK_ICU_VERSION
#undef MATCH_SCRIPT
#undef MATCH_SCRIPT2
}
return HB_SCRIPT_UNKNOWN;
}
static hb_unicode_funcs_t icu_ufuncs = {
HB_REFERENCE_COUNT_INVALID, /* ref_count */
NULL,
TRUE, /* immutable */
{
hb_icu_get_general_category,
hb_icu_get_combining_class,
hb_icu_get_mirroring,
hb_icu_get_script,
hb_icu_get_eastasian_width
hb_icu_get_general_category, NULL, NULL,
hb_icu_get_combining_class, NULL, NULL,
hb_icu_get_mirroring, NULL, NULL,
hb_icu_get_script, NULL, NULL,
hb_icu_get_eastasian_width, NULL, NULL
}
};

View File

@ -149,8 +149,10 @@ hb_set_unicode_props (hb_ot_shape_context_t *c)
unsigned int count = c->buffer->len;
for (unsigned int i = 1; i < count; i++) {
info[i].general_category() = get_general_category (info[i].codepoint);
info[i].combining_class() = get_combining_class (info[i].codepoint);
info[i].general_category() = get_general_category (c->buffer->unicode, info[i].codepoint,
c->buffer->unicode->v.get_general_category_data);
info[i].combining_class() = get_combining_class (c->buffer->unicode, info[i].codepoint,
c->buffer->unicode->v.get_combining_class_data);
}
}
@ -200,7 +202,8 @@ hb_mirror_chars (hb_ot_shape_context_t *c)
unsigned int count = c->buffer->len;
for (unsigned int i = 0; i < count; i++) {
hb_codepoint_t codepoint = get_mirroring (c->buffer->info[i].codepoint);
hb_codepoint_t codepoint = get_mirroring (c->buffer->unicode, c->buffer->info[i].codepoint,
c->buffer->unicode->v.get_mirroring_data);
if (likely (codepoint == c->buffer->info[i].codepoint))
c->buffer->info[i].mask |= rtlm_mask; /* XXX this should be moved to before setting user-feature masks */
else

View File

@ -77,7 +77,7 @@ hb_shape (hb_font_t *font,
hb_unicode_get_script_func_t get_script = buffer->unicode->v.get_script;
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++) {
hb_script_t script = get_script (buffer->info[i].codepoint);
hb_script_t script = get_script (buffer->unicode, buffer->info[i].codepoint, buffer->unicode->v.get_script_data);
if (likely (script != HB_SCRIPT_COMMON &&
script != HB_SCRIPT_INHERITED &&
script != HB_SCRIPT_UNKNOWN)) {

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2009 Red Hat, Inc.
* Copyright © 2011 Codethink Limited
*
* This is part of HarfBuzz, a text shaping library.
*
@ -22,6 +23,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Codethink Author(s): Ryan Lortie
*/
#ifndef HB_UNICODE_PRIVATE_H
@ -40,15 +42,30 @@ HB_BEGIN_DECLS
struct _hb_unicode_funcs_t {
hb_reference_count_t ref_count;
hb_unicode_funcs_t *parent;
hb_bool_t immutable;
struct {
hb_unicode_get_general_category_func_t get_general_category;
void *get_general_category_data;
hb_destroy_func_t get_general_category_destroy;
hb_unicode_get_combining_class_func_t get_combining_class;
void *get_combining_class_data;
hb_destroy_func_t get_combining_class_destroy;
hb_unicode_get_mirroring_func_t get_mirroring;
void *get_mirroring_data;
hb_destroy_func_t get_mirroring_destroy;
hb_unicode_get_script_func_t get_script;
void *get_script_data;
hb_destroy_func_t get_script_destroy;
hb_unicode_get_eastasian_width_func_t get_eastasian_width;
void *get_eastasian_width_data;
hb_destroy_func_t get_eastasian_width_destroy;
} v;
};

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2009 Red Hat, Inc.
* Copyright © 2011 Codethink Limited
*
* This is part of HarfBuzz, a text shaping library.
*
@ -22,6 +23,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Codethink Author(s): Ryan Lortie
*/
#include "hb-private.h"
@ -35,33 +37,86 @@ HB_BEGIN_DECLS
* hb_unicode_funcs_t
*/
static hb_codepoint_t hb_unicode_get_mirroring_nil (hb_codepoint_t unicode) { return unicode; }
static hb_unicode_general_category_t hb_unicode_get_general_category_nil (hb_codepoint_t unicode HB_UNUSED) { return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER; }
static hb_script_t hb_unicode_get_script_nil (hb_codepoint_t unicode HB_UNUSED) { return HB_SCRIPT_UNKNOWN; }
static unsigned int hb_unicode_get_combining_class_nil (hb_codepoint_t unicode HB_UNUSED) { return 0; }
static unsigned int hb_unicode_get_eastasian_width_nil (hb_codepoint_t unicode HB_UNUSED) { return 1; }
static hb_codepoint_t
hb_unicode_get_mirroring_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode HB_UNUSED,
void *user_data HB_UNUSED)
{
return unicode;
}
static hb_unicode_general_category_t
hb_unicode_get_general_category_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode HB_UNUSED,
void *user_data HB_UNUSED)
{
return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;
}
static hb_script_t
hb_unicode_get_script_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode HB_UNUSED,
void *user_data HB_UNUSED)
{
return HB_SCRIPT_UNKNOWN;
}
static unsigned int
hb_unicode_get_combining_class_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode HB_UNUSED,
void *user_data HB_UNUSED)
{
return 0;
}
static unsigned int
hb_unicode_get_eastasian_width_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode HB_UNUSED,
void *user_data HB_UNUSED)
{
return 1;
}
hb_unicode_funcs_t _hb_unicode_funcs_nil = {
HB_REFERENCE_COUNT_INVALID, /* ref_count */
NULL, /* parent */
TRUE, /* immutable */
{
hb_unicode_get_general_category_nil,
hb_unicode_get_combining_class_nil,
hb_unicode_get_mirroring_nil,
hb_unicode_get_script_nil,
hb_unicode_get_eastasian_width_nil
hb_unicode_get_general_category_nil, NULL, NULL,
hb_unicode_get_combining_class_nil, NULL, NULL,
hb_unicode_get_mirroring_nil, NULL, NULL,
hb_unicode_get_script_nil, NULL, NULL,
hb_unicode_get_eastasian_width_nil, NULL, NULL
}
};
hb_unicode_funcs_t *
hb_unicode_funcs_create (void)
hb_unicode_funcs_create (hb_unicode_funcs_t *parent)
{
hb_unicode_funcs_t *ufuncs;
if (!HB_OBJECT_DO_CREATE (hb_unicode_funcs_t, ufuncs))
return &_hb_unicode_funcs_nil;
ufuncs->v = _hb_unicode_funcs_nil.v;
if (parent != NULL) {
ufuncs->parent = hb_unicode_funcs_reference (parent);
hb_unicode_funcs_make_immutable (parent);
ufuncs->v = parent->v;
/* Clear out the destroy notifies from our parent.
*
* We don't want to destroy the user_data twice and since we hold a
* reference on our parent then we know that the user_data will
* survive for at least as long as we do anyway.
*/
ufuncs->v.get_general_category_destroy = NULL;
ufuncs->v.get_combining_class_destroy = NULL;
ufuncs->v.get_mirroring_destroy = NULL;
ufuncs->v.get_script_destroy = NULL;
ufuncs->v.get_eastasian_width_destroy = NULL;
} else {
ufuncs->v = _hb_unicode_funcs_nil.v;
}
return ufuncs;
}
@ -83,20 +138,31 @@ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
{
HB_OBJECT_DO_DESTROY (ufuncs);
if (ufuncs->parent != NULL)
hb_unicode_funcs_destroy (ufuncs->parent);
if (ufuncs->v.get_general_category_destroy != NULL)
ufuncs->v.get_general_category_destroy (ufuncs->v.get_general_category_data);
if (ufuncs->v.get_combining_class_destroy != NULL)
ufuncs->v.get_combining_class_destroy (ufuncs->v.get_combining_class_data);
if (ufuncs->v.get_mirroring_destroy != NULL)
ufuncs->v.get_mirroring_destroy (ufuncs->v.get_mirroring_data);
if (ufuncs->v.get_script_destroy != NULL)
ufuncs->v.get_script_destroy (ufuncs->v.get_script_data);
if (ufuncs->v.get_eastasian_width_destroy != NULL)
ufuncs->v.get_eastasian_width_destroy (ufuncs->v.get_eastasian_width_data);
free (ufuncs);
}
hb_unicode_funcs_t *
hb_unicode_funcs_copy (hb_unicode_funcs_t *other_ufuncs)
hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs)
{
hb_unicode_funcs_t *ufuncs;
if (!HB_OBJECT_DO_CREATE (hb_unicode_funcs_t, ufuncs))
return &_hb_unicode_funcs_nil;
ufuncs->v = other_ufuncs->v;
return ufuncs;
return ufuncs->parent;
}
void
@ -115,122 +181,75 @@ hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs)
}
void
hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_get_mirroring_func_t mirroring_func)
{
if (ufuncs->immutable)
return;
ufuncs->v.get_mirroring = mirroring_func ? mirroring_func : hb_unicode_get_mirroring_nil;
#define SETTER(name) \
void \
hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t *ufuncs, \
hb_unicode_get_##name##_func_t func, \
void *user_data, \
hb_destroy_func_t destroy) \
{ \
if (ufuncs->immutable) \
return; \
\
if (func != NULL) { \
ufuncs->v.get_##name = func; \
ufuncs->v.get_##name##_data = user_data; \
ufuncs->v.get_##name##_destroy = destroy; \
} else if (ufuncs->parent != NULL) { \
ufuncs->v.get_##name = ufuncs->parent->v.get_##name; \
ufuncs->v.get_##name##_data = ufuncs->parent->v.get_##name##_data;; \
ufuncs->v.get_##name##_destroy = NULL; \
} else { \
ufuncs->v.get_##name = hb_unicode_get_##name##_nil; \
ufuncs->v.get_##name##_data = NULL; \
ufuncs->v.get_##name##_destroy = NULL; \
} \
}
void
hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_get_general_category_func_t general_category_func)
{
if (ufuncs->immutable)
return;
ufuncs->v.get_general_category = general_category_func ? general_category_func : hb_unicode_get_general_category_nil;
}
void
hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_get_script_func_t script_func)
{
if (ufuncs->immutable)
return;
ufuncs->v.get_script = script_func ? script_func : hb_unicode_get_script_nil;
}
void
hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_get_combining_class_func_t combining_class_func)
{
if (ufuncs->immutable)
return;
ufuncs->v.get_combining_class = combining_class_func ? combining_class_func : hb_unicode_get_combining_class_nil;
}
void
hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_get_eastasian_width_func_t eastasian_width_func)
{
if (ufuncs->immutable)
return;
ufuncs->v.get_eastasian_width = eastasian_width_func ? eastasian_width_func : hb_unicode_get_eastasian_width_nil;
}
hb_unicode_get_mirroring_func_t
hb_unicode_funcs_get_mirroring_func (hb_unicode_funcs_t *ufuncs)
{
return ufuncs->v.get_mirroring;
}
hb_unicode_get_general_category_func_t
hb_unicode_funcs_get_general_category_func (hb_unicode_funcs_t *ufuncs)
{
return ufuncs->v.get_general_category;
}
hb_unicode_get_script_func_t
hb_unicode_funcs_get_script_func (hb_unicode_funcs_t *ufuncs)
{
return ufuncs->v.get_script;
}
hb_unicode_get_combining_class_func_t
hb_unicode_funcs_get_combining_class_func (hb_unicode_funcs_t *ufuncs)
{
return ufuncs->v.get_combining_class;
}
hb_unicode_get_eastasian_width_func_t
hb_unicode_funcs_get_eastasian_width_func (hb_unicode_funcs_t *ufuncs)
{
return ufuncs->v.get_eastasian_width;
}
SETTER(mirroring)
SETTER(general_category)
SETTER(script)
SETTER(combining_class)
SETTER(eastasian_width)
hb_codepoint_t
hb_unicode_get_mirroring (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode)
{
return ufuncs->v.get_mirroring (unicode);
return ufuncs->v.get_mirroring (ufuncs, unicode,
ufuncs->v.get_mirroring_data);
}
hb_unicode_general_category_t
hb_unicode_get_general_category (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode)
{
return ufuncs->v.get_general_category (unicode);
return ufuncs->v.get_general_category (ufuncs, unicode,
ufuncs->v.get_general_category_data);
}
hb_script_t
hb_unicode_get_script (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode)
{
return ufuncs->v.get_script (unicode);
return ufuncs->v.get_script (ufuncs, unicode,
ufuncs->v.get_script_data);
}
unsigned int
hb_unicode_get_combining_class (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode)
{
return ufuncs->v.get_combining_class (unicode);
return ufuncs->v.get_combining_class (ufuncs, unicode,
ufuncs->v.get_combining_class_data);
}
unsigned int
hb_unicode_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode)
{
return ufuncs->v.get_eastasian_width (unicode);
return ufuncs->v.get_eastasian_width (ufuncs, unicode,
ufuncs->v.get_eastasian_width_data);
}

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2009 Red Hat, Inc.
* Copyright © 2011 Codethink Limited
*
* This is part of HarfBuzz, a text shaping library.
*
@ -22,6 +23,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Codethink Author(s): Ryan Lortie
*/
#ifndef HB_UNICODE_H
@ -39,7 +41,7 @@ HB_BEGIN_DECLS
typedef struct _hb_unicode_funcs_t hb_unicode_funcs_t;
hb_unicode_funcs_t *
hb_unicode_funcs_create (void);
hb_unicode_funcs_create (hb_unicode_funcs_t *parent_funcs);
hb_unicode_funcs_t *
hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs);
@ -51,7 +53,7 @@ void
hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs);
hb_unicode_funcs_t *
hb_unicode_funcs_copy (hb_unicode_funcs_t *ufuncs);
hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs);
void
hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs);
@ -63,57 +65,55 @@ hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs);
* funcs
*/
/* typedefs */
typedef hb_codepoint_t (*hb_unicode_get_mirroring_func_t) (hb_codepoint_t unicode);
typedef hb_unicode_general_category_t (*hb_unicode_get_general_category_func_t) (hb_codepoint_t unicode);
typedef hb_script_t (*hb_unicode_get_script_func_t) (hb_codepoint_t unicode);
typedef unsigned int (*hb_unicode_get_combining_class_func_t) (hb_codepoint_t unicode);
typedef unsigned int (*hb_unicode_get_eastasian_width_func_t) (hb_codepoint_t unicode);
typedef hb_codepoint_t (*hb_unicode_get_mirroring_func_t) (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data);
typedef hb_unicode_general_category_t (*hb_unicode_get_general_category_func_t) (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data);
typedef hb_script_t (*hb_unicode_get_script_func_t) (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data);
typedef unsigned int (*hb_unicode_get_combining_class_func_t) (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data);
typedef unsigned int (*hb_unicode_get_eastasian_width_func_t) (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data);
/* setters */
void
hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_get_mirroring_func_t mirroring_func);
hb_unicode_get_mirroring_func_t mirroring_func,
void *user_data,
hb_destroy_func_t destroy);
void
hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_get_general_category_func_t general_category_func);
hb_unicode_get_general_category_func_t general_category_func,
void *user_data,
hb_destroy_func_t destroy);
void
hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_get_script_func_t script_func);
hb_unicode_get_script_func_t script_func,
void *user_data,
hb_destroy_func_t destroy);
void
hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_get_combining_class_func_t combining_class_func);
hb_unicode_get_combining_class_func_t combining_class_func,
void *user_data,
hb_destroy_func_t destroy);
void
hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_get_eastasian_width_func_t eastasian_width_func);
/* getters */
/* These never return NULL. Return fallback defaults instead. */
hb_unicode_get_mirroring_func_t
hb_unicode_funcs_get_mirroring_func (hb_unicode_funcs_t *ufuncs);
hb_unicode_get_general_category_func_t
hb_unicode_funcs_get_general_category_func (hb_unicode_funcs_t *ufuncs);
hb_unicode_get_script_func_t
hb_unicode_funcs_get_script_func (hb_unicode_funcs_t *ufuncs);
hb_unicode_get_combining_class_func_t
hb_unicode_funcs_get_combining_class_func (hb_unicode_funcs_t *ufuncs);
hb_unicode_get_eastasian_width_func_t
hb_unicode_funcs_get_eastasian_width_func (hb_unicode_funcs_t *ufuncs);
hb_unicode_get_eastasian_width_func_t eastasian_width_func,
void *user_data,
hb_destroy_func_t destroy);
/* accessors */

View File

@ -11,6 +11,7 @@ check_PROGRAMS = $(TEST_PROGS)
TEST_PROGS += \
test-buffer \
test-types \
test-unicode \
$(NULL)

215
test/test-unicode.c Normal file
View File

@ -0,0 +1,215 @@
/*
* Copyright (C) 2011 Codethink Limited
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Codethink Author(s): Ryan Lortie
*/
#include "hb-test.h"
/* This file tests the unicode virtual functions interface */
static void
test_nil (void)
{
hb_unicode_funcs_t *uf = hb_unicode_funcs_create (NULL);
g_assert_cmpint (hb_unicode_get_script (uf, 'd'), ==, HB_SCRIPT_UNKNOWN);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
hb_unicode_funcs_destroy (uf);
}
static void
test_glib (void)
{
hb_unicode_funcs_t *uf = hb_glib_get_unicode_funcs ();
g_assert_cmpint (hb_unicode_get_script (uf, 'd'), ==, HB_SCRIPT_LATIN);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 0);
hb_unicode_funcs_destroy (uf);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 0);
}
static gboolean freed0, freed1;
static int unique_pointer0[1];
static int unique_pointer1[1];
static void free_up (void *up)
{
if (up == unique_pointer0) {
g_assert (!freed0);
freed0 = TRUE;
} else if (up == unique_pointer1) {
g_assert (!freed1);
freed1 = TRUE;
} else {
g_assert_not_reached ();
}
}
static hb_script_t
simple_get_script (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t codepoint,
void *user_data)
{
g_assert (hb_unicode_funcs_get_parent (ufuncs) == NULL);
g_assert (unique_pointer0 == user_data);
if ('a' <= codepoint && codepoint <= 'z')
return HB_SCRIPT_LATIN;
else
return HB_SCRIPT_UNKNOWN;
}
static void
test_custom (void)
{
hb_unicode_funcs_t *uf = hb_unicode_funcs_create (NULL);
hb_unicode_funcs_set_script_func (uf, simple_get_script,
unique_pointer0, free_up);
g_assert_cmpint (hb_unicode_get_script (uf, 'a'), ==, HB_SCRIPT_LATIN);
g_assert_cmpint (hb_unicode_get_script (uf, '0'), ==, HB_SCRIPT_UNKNOWN);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
g_assert (!freed0 && !freed1);
hb_unicode_funcs_destroy (uf);
g_assert (freed0 && !freed1);
freed0 = FALSE;
}
static hb_script_t
a_is_for_arabic_get_script (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t codepoint,
void *user_data)
{
g_assert (hb_unicode_funcs_get_parent (ufuncs) != NULL);
g_assert (user_data == unique_pointer1);
if (codepoint == 'a') {
return HB_SCRIPT_ARABIC;
} else {
hb_unicode_funcs_t *parent = hb_unicode_funcs_get_parent (ufuncs);
return hb_unicode_get_script (parent, codepoint);
}
}
static void
test_subclassing_nil (void)
{
hb_unicode_funcs_t *uf = hb_unicode_funcs_create (NULL);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
hb_unicode_funcs_t *aa = hb_unicode_funcs_create (uf);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 2);
hb_unicode_funcs_destroy (uf);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
unique_pointer1, free_up);
g_assert_cmpint (hb_unicode_get_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
g_assert_cmpint (hb_unicode_get_script (aa, 'b'), ==, HB_SCRIPT_UNKNOWN);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (aa), ==, 1);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
g_assert (!freed0 && !freed1);
hb_unicode_funcs_destroy (aa);
g_assert (!freed0 && freed1);
freed1 = FALSE;
}
static void
test_subclassing_glib (void)
{
hb_unicode_funcs_t *uf = hb_glib_get_unicode_funcs ();
g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 0);
hb_unicode_funcs_t *aa = hb_unicode_funcs_create (uf);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 0);
hb_unicode_funcs_destroy (uf);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 0);
hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
unique_pointer1, free_up);
g_assert_cmpint (hb_unicode_get_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
g_assert_cmpint (hb_unicode_get_script (aa, 'b'), ==, HB_SCRIPT_LATIN);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (aa), ==, 1);
g_assert (!freed0 && !freed1);
hb_unicode_funcs_destroy (aa);
g_assert (!freed0 && freed1);
freed1 = FALSE;
}
static void
test_subclassing_deep (void)
{
hb_unicode_funcs_t *uf = hb_unicode_funcs_create (NULL);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
hb_unicode_funcs_set_script_func (uf, simple_get_script,
unique_pointer0, free_up);
hb_unicode_funcs_t *aa = hb_unicode_funcs_create (uf);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (aa), ==, 1);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 2);
hb_unicode_funcs_destroy (uf);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
/* make sure the 'uf' didn't get freed, since 'aa' holds a ref */
g_assert (!freed0);
hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
unique_pointer1, free_up);
g_assert_cmpint (hb_unicode_get_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
g_assert_cmpint (hb_unicode_get_script (aa, 'b'), ==, HB_SCRIPT_LATIN);
g_assert_cmpint (hb_unicode_get_script (aa, '0'), ==, HB_SCRIPT_UNKNOWN);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (aa), ==, 1);
g_assert_cmpint (hb_unicode_funcs_get_reference_count (uf), ==, 1);
g_assert (!freed0 && !freed1);
hb_unicode_funcs_destroy (aa);
g_assert (freed0 && freed1);
freed0 = freed1 = FALSE;
}
int
main (int argc, char **argv)
{
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/unicode/nil", test_nil);
g_test_add_func ("/unicode/glib", test_glib);
g_test_add_func ("/unicode/custom", test_custom);
g_test_add_func ("/unicode/subclassing/nil", test_subclassing_nil);
g_test_add_func ("/unicode/subclassing/glib", test_subclassing_glib);
g_test_add_func ("/unicode/subclassing/deep", test_subclassing_deep);
return g_test_run ();
}