update for HEAD-2003050101
[reactos.git] / lib / freetype / src / base / ftobject.c
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   }