1 #include <ft2build.h> 2 #include FT_INTERNAL_OBJECT_H 3 #include FT_INTERNAL_DEBUG_H 4 #include FT_INTERNAL_OBJECTS_H 5 6 #define FT_MAGIC_DEATH 0xDEADdead 7 #define FT_MAGIC_CLASS 0x12345678 8 9 #define FT_TYPE_HASH(x) (( (FT_UInt32)(x) >> 2 )^( (FT_UInt32)(x) >> 10 )) 10 11 #define FT_OBJECT_CHECK(o) \ 12 ( FT_OBJECT(o) != NULL && \ 13 FT_OBJECT(o)->clazz != NULL && \ 14 FT_OBJECT(o)->ref_count >= 1 && \ 15 FT_OBJECT(o)->clazz->magic == FT_MAGIC_CLASS ) 16 17 #define FT_CLASS_CHECK(c) \ 18 ( FT_CLASS(c) != NULL && FT_CLASS(c)->magic == FT_MAGIC_CLASS ) 19 20 #define FT_ASSERT_IS_CLASS(c) FT_ASSERT( FT_CLASS_CHECK(c) ) 21 22 /*******************************************************************/ 23 /*******************************************************************/ 24 /***** *****/ 25 /***** *****/ 26 /***** M E T A - C L A S S *****/ 27 /***** *****/ 28 /***** *****/ 29 /*******************************************************************/ 30 /*******************************************************************/ 31 32 /* forward declaration */ 33 FT_BASE_DEF( FT_Error ) 34 ft_metaclass_init( FT_MetaClass meta, 35 FT_Library library ); 36 37 /* forward declaration */ 38 FT_BASE_DEF( void ) 39 ft_metaclass_done( FT_MetaClass meta ); 40 41 42 /* class type for the meta-class itself */ 43 static const FT_TypeRec ft_meta_class_type = 44 { 45 "FT2.MetaClass", 46 NULL, 47 48 sizeof( FT_MetaClassRec ), 49 (FT_Object_InitFunc) ft_metaclass_init, 50 (FT_Object_DoneFunc) ft_metaclass_done, 51 52 sizeof( FT_ClassRec ), 53 (FT_Object_InitFunc) NULL, 54 (FT_Object_DoneFunc) NULL 55 }; 56 57 58 59 60 /* destroy a given class */ 61 static void 62 ft_class_hnode_destroy( FT_ClassHNode node ) 63 { 64 FT_Class clazz = node->clazz; 65 FT_Memory memory = clazz->memory; 66 67 if ( clazz->class_done ) 68 clazz->class_done( (FT_Object) clazz ); 69 70 FT_FREE( clazz ); 71 72 node->clazz = NULL; 73 node->type = NULL; 74 75 FT_FREE( node ); 76 } 77 78 79 static FT_Int 80 ft_type_equal( FT_Type type1, 81 FT_Type type2 ) 82 { 83 if ( type1 == type2 ) 84 goto Ok; 85 86 if ( type1 == NULL || type2 == NULL ) 87 goto Fail; 88 89 /* compare parent types */ 90 if ( type1->super != type2->super ) 91 { 92 if ( type1->super == NULL || 93 type2->super == NULL || 94 !ft_type_equal( type1, type2 ) ) 95 goto Fail; 96 } 97 98 /* compare type names */ 99 if ( type1->name != type2->name ) 100 { 101 if ( type1->name == NULL || 102 type2->name == NULL || 103 ft_strcmp( type1->name, type2->name ) != 0 ) 104 goto Fail; 105 } 106 107 /* compare the other type fields */ 108 if ( type1->class_size != type2->class_size || 109 type1->class_init != type2->class_init || 110 type1->class_done != type2->class_done || 111 type1->obj_size != type2->obj_size || 112 type1->obj_init != type2->obj_init || 113 type1->obj_done != type2->obj_done ) 114 goto Fail; 115 116 Ok: 117 return 1; 118 119 Fail: 120 return 0; 121 } 122 123 124 static FT_Int 125 ft_class_hnode_equal( const FT_ClassHNode node1, 126 const FT_ClassHNode node2 ) 127 { 128 FT_Type type1 = node1->type; 129 FT_Type type2 = node2->type; 130 131 /* comparing the pointers should work in 99% of cases */ 132 return ( type1 == type2 ) ? 1 : ft_type_equal( type1, type2 ); 133 } 134 135 136 FT_BASE_DEF( void ) 137 ft_metaclass_done( FT_MetaClass meta ) 138 { 139 /* clear all classes */ 140 ft_hash_done( &meta->type_to_class, 141 (FT_Hash_ForeachFunc) ft_class_hnode_destroy, 142 NULL ); 143 144 meta->clazz.object.clazz = NULL; 145 meta->clazz.object.ref_count = 0; 146 meta->clazz.magic = FT_MAGIC_DEATH; 147 } 148 149 150 FT_BASE_DEF( FT_Error ) 151 ft_metaclass_init( FT_MetaClass meta, 152 FT_Library library ) 153 { 154 FT_ClassRec* clazz = (FT_ClassRec*) &meta->clazz; 155 156 /* the meta-class is its OWN class !! */ 157 clazz->object.clazz = (FT_Class) clazz; 158 clazz->object.ref_count = 1; 159 clazz->magic = FT_MAGIC_CLASS; 160 clazz->library = library; 161 clazz->memory = library->memory; 162 clazz->type = &ft_meta_class_type; 163 clazz->info = NULL; 164 165 clazz->class_done = (FT_Object_DoneFunc) ft_metaclass_done; 166 167 clazz->obj_size = sizeof( FT_ClassRec ); 168 clazz->obj_init = NULL; 169 clazz->obj_done = NULL; 170 171 return ft_hash_init( &meta->type_to_class, 172 (FT_Hash_EqualFunc) ft_class_hnode_equal, 173 library->memory ); 174 } 175 176 177 /* find or create the class corresponding to a given type */ 178 /* note that this function will retunr NULL in case of */ 179 /* memory overflow */ 180 /* */ 181 static FT_Class 182 ft_metaclass_get_class( FT_MetaClass meta, 183 FT_Type ctype ) 184 { 185 FT_ClassHNodeRec keynode, *node, **pnode; 186 FT_Memory memory; 187 FT_ClassRec* clazz; 188 FT_Class parent; 189 FT_Error error; 190 191 keynode.hnode.hash = FT_TYPE_HASH( ctype ); 192 keynode.type = ctype; 193 194 pnode = (FT_ClassHNode*) ft_hash_lookup( &meta->type_to_class, 195 (FT_HashNode) &keynode ); 196 node = *pnode; 197 if ( node != NULL ) 198 { 199 clazz = (FT_ClassRec*) node->clazz; 200 goto Exit; 201 } 202 203 memory = FT_CLASS__MEMORY(meta); 204 clazz = NULL; 205 parent = NULL; 206 if ( ctype->super != NULL ) 207 { 208 FT_ASSERT( ctype->super->class_size <= ctype->class_size ); 209 FT_ASSERT( ctype->super->obj_size <= ctype->obj_size ); 210 211 parent = ft_metaclass_get_class( meta, ctype->super ); 212 } 213 214 if ( !FT_NEW( node ) ) 215 { 216 if ( !FT_ALLOC( clazz, ctype->class_size ) ) 217 { 218 if ( parent ) 219 FT_MEM_COPY( (FT_ClassRec*)clazz, parent, parent->type->class_size ); 220 221 clazz->object.clazz = (FT_Class) meta; 222 clazz->object.ref_count = 1; 223 224 clazz->memory = memory; 225 clazz->library = FT_CLASS__LIBRARY(meta); 226 clazz->super = parent; 227 clazz->type = ctype; 228 clazz->info = NULL; 229 clazz->magic = FT_MAGIC_CLASS; 230 231 clazz->class_done = ctype->class_done; 232 clazz->obj_size = ctype->obj_size; 233 clazz->obj_init = ctype->obj_init; 234 clazz->obj_done = ctype->obj_done; 235 236 if ( parent ) 237 { 238 if ( clazz->class_done == NULL ) 239 clazz->class_done = parent->class_done; 240 241 if ( clazz->obj_init == NULL ) 242 clazz->obj_init = parent->obj_init; 243 244 if ( clazz->obj_done == NULL ) 245 clazz->obj_done = parent->obj_done; 246 } 247 248 /* find class initializer, if any */ 249 { 250 FT_Type ztype = ctype; 251 FT_Object_InitFunc cinit = NULL; 252 253 do 254 { 255 cinit = ztype->class_init; 256 if ( cinit != NULL ) 257 break; 258 259 ztype = ztype->super; 260 } 261 while ( ztype != NULL ); 262 263 /* then call it when needed */ 264 if ( cinit != NULL ) 265 error = cinit( (FT_Object) clazz, NULL ); 266 } 267 } 268 269 if (error) 270 { 271 if ( clazz ) 272 { 273 /* we always call the class destructor when */ 274 /* an error was detected in the constructor !! */ 275 if ( clazz->class_done ) 276 clazz->class_done( (FT_Object) clazz ); 277 278 FT_FREE( clazz ); 279 } 280 FT_FREE( node ); 281 } 282 } 283 284 Exit: 285 return (FT_Class) clazz; 286 } 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 FT_BASE_DEF( FT_Int ) 302 ft_object_check( FT_Pointer obj ) 303 { 304 return FT_OBJECT_CHECK(obj); 305 } 306 307 308 FT_BASE_DEF( FT_Int ) 309 ft_object_is_a( FT_Pointer obj, 310 FT_Class clazz ) 311 { 312 if ( FT_OBJECT_CHECK(obj) ) 313 { 314 FT_Class c = FT_OBJECT__CLASS(obj); 315 316 do 317 { 318 if ( c == clazz ) 319 return 1; 320 321 c = c->super; 322 } 323 while ( c == NULL ); 324 325 return (clazz == NULL); 326 } 327 return 0; 328 } 329 330 331 FT_BASE_DEF( FT_Error ) 332 ft_object_create( FT_Object *pobject, 333 FT_Class clazz, 334 FT_Pointer init_data ) 335 { 336 FT_Memory memory; 337 FT_Error error; 338 FT_Object obj; 339 340 FT_ASSERT_IS_CLASS(clazz); 341 342 memory = FT_CLASS__MEMORY(clazz); 343 if ( !FT_ALLOC( obj, clazz->obj_size ) ) 344 { 345 obj->clazz = clazz; 346 obj->ref_count = 1; 347 348 if ( clazz->obj_init ) 349 { 350 error = clazz->obj_init( obj, init_data ); 351 if ( error ) 352 { 353 /* IMPORTANT: call the destructor when an error */ 354 /* was detected in the constructor !! */ 355 if ( clazz->obj_done ) 356 clazz->obj_done( obj ); 357 358 FT_FREE( obj ); 359 } 360 } 361 } 362 *pobject = obj; 363 return error; 364 } 365 366 367 FT_BASE_DEF( FT_Class ) 368 ft_class_find_by_type( FT_Type type, 369 FT_Library library ) 370 { 371 FT_MetaClass meta = &library->meta_class; 372 373 return ft_metaclass_get_class( meta, type ); 374 } 375 376 377 FT_BASE_DEF( FT_Error ) 378 ft_object_create_from_type( FT_Object *pobject, 379 FT_Type type, 380 FT_Pointer init_data, 381 FT_Library library ) 382 { 383 FT_Class clazz; 384 FT_Error error; 385 386 clazz = ft_class_find_by_type( type, library ); 387 if ( clazz ) 388 error = ft_object_create( pobject, clazz, init_data ); 389 else 390 { 391 *pobject = NULL; 392 error = FT_Err_Out_Of_Memory; 393 } 394 395 return error; 396 } 397