From 37da2899f40661e3e9631e497da8dc59b971cbd0 Mon Sep 17 00:00:00 2001 From: "Charles.Forsyth" Date: Fri, 22 Dec 2006 17:07:39 +0000 Subject: 20060303a --- libfreetype/ftobject.c | 396 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 396 insertions(+) create mode 100644 libfreetype/ftobject.c (limited to 'libfreetype/ftobject.c') diff --git a/libfreetype/ftobject.c b/libfreetype/ftobject.c new file mode 100644 index 00000000..34e41e94 --- /dev/null +++ b/libfreetype/ftobject.c @@ -0,0 +1,396 @@ +#include +#include FT_INTERNAL_OBJECT_H +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_OBJECTS_H + +#define FT_MAGIC_DEATH 0xDEADdead +#define FT_MAGIC_CLASS 0x12345678 + +#define FT_TYPE_HASH(x) (( (FT_UInt32)(x) >> 2 )^( (FT_UInt32)(x) >> 10 )) + +#define FT_OBJECT_CHECK(o) \ + ( FT_OBJECT(o) != NULL && \ + FT_OBJECT(o)->clazz != NULL && \ + FT_OBJECT(o)->ref_count >= 1 && \ + FT_OBJECT(o)->clazz->magic == FT_MAGIC_CLASS ) + +#define FT_CLASS_CHECK(c) \ + ( FT_CLASS(c) != NULL && FT_CLASS(c)->magic == FT_MAGIC_CLASS ) + +#define FT_ASSERT_IS_CLASS(c) FT_ASSERT( FT_CLASS_CHECK(c) ) + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** *****/ + /***** M E T A - C L A S S *****/ + /***** *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + /* forward declaration */ + FT_BASE_DEF( FT_Error ) + ft_metaclass_init( FT_MetaClass meta, + FT_Library library ); + + /* forward declaration */ + FT_BASE_DEF( void ) + ft_metaclass_done( FT_MetaClass meta ); + + + /* class type for the meta-class itself */ + static const FT_TypeRec ft_meta_class_type = + { + "FT2.MetaClass", + NULL, + + sizeof( FT_MetaClassRec ), + (FT_Object_InitFunc) ft_metaclass_init, + (FT_Object_DoneFunc) ft_metaclass_done, + + sizeof( FT_ClassRec ), + (FT_Object_InitFunc) NULL, + (FT_Object_DoneFunc) NULL + }; + + + + + /* destroy a given class */ + static void + ft_class_hnode_destroy( FT_ClassHNode node ) + { + FT_Class clazz = node->clazz; + FT_Memory memory = clazz->memory; + + if ( clazz->class_done ) + clazz->class_done( (FT_Object) clazz ); + + FT_FREE( clazz ); + + node->clazz = NULL; + node->type = NULL; + + FT_FREE( node ); + } + + + static FT_Int + ft_type_equal( FT_Type type1, + FT_Type type2 ) + { + if ( type1 == type2 ) + goto Ok; + + if ( type1 == NULL || type2 == NULL ) + goto Fail; + + /* compare parent types */ + if ( type1->super != type2->super ) + { + if ( type1->super == NULL || + type2->super == NULL || + !ft_type_equal( type1, type2 ) ) + goto Fail; + } + + /* compare type names */ + if ( type1->name != type2->name ) + { + if ( type1->name == NULL || + type2->name == NULL || + ft_strcmp( type1->name, type2->name ) != 0 ) + goto Fail; + } + + /* compare the other type fields */ + if ( type1->class_size != type2->class_size || + type1->class_init != type2->class_init || + type1->class_done != type2->class_done || + type1->obj_size != type2->obj_size || + type1->obj_init != type2->obj_init || + type1->obj_done != type2->obj_done ) + goto Fail; + + Ok: + return 1; + + Fail: + return 0; + } + + + static FT_Int + ft_class_hnode_equal( const FT_ClassHNode node1, + const FT_ClassHNode node2 ) + { + FT_Type type1 = node1->type; + FT_Type type2 = node2->type; + + /* comparing the pointers should work in 99% of cases */ + return ( type1 == type2 ) ? 1 : ft_type_equal( type1, type2 ); + } + + + FT_BASE_DEF( void ) + ft_metaclass_done( FT_MetaClass meta ) + { + /* clear all classes */ + ft_hash_done( &meta->type_to_class, + (FT_Hash_ForeachFunc) ft_class_hnode_destroy, + NULL ); + + meta->clazz.object.clazz = NULL; + meta->clazz.object.ref_count = 0; + meta->clazz.magic = FT_MAGIC_DEATH; + } + + + FT_BASE_DEF( FT_Error ) + ft_metaclass_init( FT_MetaClass meta, + FT_Library library ) + { + FT_ClassRec* clazz = (FT_ClassRec*) &meta->clazz; + + /* the meta-class is its OWN class !! */ + clazz->object.clazz = (FT_Class) clazz; + clazz->object.ref_count = 1; + clazz->magic = FT_MAGIC_CLASS; + clazz->library = library; + clazz->memory = library->memory; + clazz->type = &ft_meta_class_type; + clazz->info = NULL; + + clazz->class_done = (FT_Object_DoneFunc) ft_metaclass_done; + + clazz->obj_size = sizeof( FT_ClassRec ); + clazz->obj_init = NULL; + clazz->obj_done = NULL; + + return ft_hash_init( &meta->type_to_class, + (FT_Hash_EqualFunc) ft_class_hnode_equal, + library->memory ); + } + + + /* find or create the class corresponding to a given type */ + /* note that this function will retunr NULL in case of */ + /* memory overflow */ + /* */ + static FT_Class + ft_metaclass_get_class( FT_MetaClass meta, + FT_Type ctype ) + { + FT_ClassHNodeRec keynode, *node, **pnode; + FT_Memory memory; + FT_ClassRec* clazz; + FT_Class parent; + FT_Error error; + + keynode.hnode.hash = FT_TYPE_HASH( ctype ); + keynode.type = ctype; + + pnode = (FT_ClassHNode*) ft_hash_lookup( &meta->type_to_class, + (FT_HashNode) &keynode ); + node = *pnode; + if ( node != NULL ) + { + clazz = (FT_ClassRec*) node->clazz; + goto Exit; + } + + memory = FT_CLASS__MEMORY(meta); + clazz = NULL; + parent = NULL; + if ( ctype->super != NULL ) + { + FT_ASSERT( ctype->super->class_size <= ctype->class_size ); + FT_ASSERT( ctype->super->obj_size <= ctype->obj_size ); + + parent = ft_metaclass_get_class( meta, ctype->super ); + } + + if ( !FT_NEW( node ) ) + { + if ( !FT_ALLOC( clazz, ctype->class_size ) ) + { + if ( parent ) + FT_MEM_COPY( (FT_ClassRec*)clazz, parent, parent->type->class_size ); + + clazz->object.clazz = (FT_Class) meta; + clazz->object.ref_count = 1; + + clazz->memory = memory; + clazz->library = FT_CLASS__LIBRARY(meta); + clazz->super = parent; + clazz->type = ctype; + clazz->info = NULL; + clazz->magic = FT_MAGIC_CLASS; + + clazz->class_done = ctype->class_done; + clazz->obj_size = ctype->obj_size; + clazz->obj_init = ctype->obj_init; + clazz->obj_done = ctype->obj_done; + + if ( parent ) + { + if ( clazz->class_done == NULL ) + clazz->class_done = parent->class_done; + + if ( clazz->obj_init == NULL ) + clazz->obj_init = parent->obj_init; + + if ( clazz->obj_done == NULL ) + clazz->obj_done = parent->obj_done; + } + + /* find class initializer, if any */ + { + FT_Type ztype = ctype; + FT_Object_InitFunc cinit = NULL; + + do + { + cinit = ztype->class_init; + if ( cinit != NULL ) + break; + + ztype = ztype->super; + } + while ( ztype != NULL ); + + /* then call it when needed */ + if ( cinit != NULL ) + error = cinit( (FT_Object) clazz, NULL ); + } + } + + if (error) + { + if ( clazz ) + { + /* we always call the class destructor when */ + /* an error was detected in the constructor !! */ + if ( clazz->class_done ) + clazz->class_done( (FT_Object) clazz ); + + FT_FREE( clazz ); + } + FT_FREE( node ); + } + } + + Exit: + return (FT_Class) clazz; + } + + + + + + + + + + + + + + + FT_BASE_DEF( FT_Int ) + ft_object_check( FT_Pointer obj ) + { + return FT_OBJECT_CHECK(obj); + } + + + FT_BASE_DEF( FT_Int ) + ft_object_is_a( FT_Pointer obj, + FT_Class clazz ) + { + if ( FT_OBJECT_CHECK(obj) ) + { + FT_Class c = FT_OBJECT__CLASS(obj); + + do + { + if ( c == clazz ) + return 1; + + c = c->super; + } + while ( c == NULL ); + + return (clazz == NULL); + } + return 0; + } + + + FT_BASE_DEF( FT_Error ) + ft_object_create( FT_Object *pobject, + FT_Class clazz, + FT_Pointer init_data ) + { + FT_Memory memory; + FT_Error error; + FT_Object obj; + + FT_ASSERT_IS_CLASS(clazz); + + memory = FT_CLASS__MEMORY(clazz); + if ( !FT_ALLOC( obj, clazz->obj_size ) ) + { + obj->clazz = clazz; + obj->ref_count = 1; + + if ( clazz->obj_init ) + { + error = clazz->obj_init( obj, init_data ); + if ( error ) + { + /* IMPORTANT: call the destructor when an error */ + /* was detected in the constructor !! */ + if ( clazz->obj_done ) + clazz->obj_done( obj ); + + FT_FREE( obj ); + } + } + } + *pobject = obj; + return error; + } + + + FT_BASE_DEF( FT_Class ) + ft_class_find_by_type( FT_Type type, + FT_Library library ) + { + FT_MetaClass meta = &library->meta_class; + + return ft_metaclass_get_class( meta, type ); + } + + + FT_BASE_DEF( FT_Error ) + ft_object_create_from_type( FT_Object *pobject, + FT_Type type, + FT_Pointer init_data, + FT_Library library ) + { + FT_Class clazz; + FT_Error error; + + clazz = ft_class_find_by_type( type, library ); + if ( clazz ) + error = ft_object_create( pobject, clazz, init_data ); + else + { + *pobject = NULL; + error = FT_Err_Out_Of_Memory; + } + + return error; + } -- cgit v1.2.3