source: trunk/poppler/freetype-2.1.10/src/cache/ftcmanag.c @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 15 years ago

First import

File size: 16.7 KB
Line 
1/***************************************************************************/
2/*                                                                         */
3/*  ftcmanag.c                                                             */
4/*                                                                         */
5/*    FreeType Cache Manager (body).                                       */
6/*                                                                         */
7/*  Copyright 2000-2001, 2002, 2003, 2004, 2005 by                         */
8/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9/*                                                                         */
10/*  This file is part of the FreeType project, and may only be used,       */
11/*  modified, and distributed under the terms of the FreeType project      */
12/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13/*  this file you indicate that you have read the license and              */
14/*  understand and accept it fully.                                        */
15/*                                                                         */
16/***************************************************************************/
17
18
19#include <ft2build.h>
20#include FT_CACHE_H
21#include FT_CACHE_INTERNAL_MANAGER_H
22#include FT_INTERNAL_OBJECTS_H
23#include FT_INTERNAL_DEBUG_H
24#include FT_SIZES_H
25
26#include "ftcerror.h"
27
28
29#undef  FT_COMPONENT
30#define FT_COMPONENT  trace_cache
31
32#define FTC_LRU_GET_MANAGER( lru )  ( (FTC_Manager)(lru)->user_data )
33
34
35  static FT_Error
36  ftc_scaler_lookup_size( FTC_Manager  manager,
37                          FTC_Scaler   scaler,
38                          FT_Size     *asize )
39  {
40    FT_Face   face;
41    FT_Size   size = NULL;
42    FT_Error  error;
43
44
45    error = FTC_Manager_LookupFace( manager, scaler->face_id, &face );
46    if ( error )
47      goto Exit;
48
49    error = FT_New_Size( face, &size );
50    if ( error )
51      goto Exit;
52
53    FT_Activate_Size( size );
54
55    if ( scaler->pixel )
56      error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height );
57    else
58      error = FT_Set_Char_Size( face, scaler->width, scaler->height,
59                                scaler->x_res, scaler->y_res );
60    if ( error )
61    {
62      FT_Done_Size( size );
63      size = NULL;
64    }
65
66  Exit:
67    *asize = size;
68    return error;
69  }
70
71
72  typedef struct  FTC_SizeNodeRec_
73  {
74    FTC_MruNodeRec  node;
75    FT_Size         size;
76    FTC_ScalerRec   scaler;
77
78  } FTC_SizeNodeRec, *FTC_SizeNode;
79
80
81  FT_CALLBACK_DEF( void )
82  ftc_size_node_done( FTC_MruNode  ftcnode,
83                      FT_Pointer   data )
84  {
85    FTC_SizeNode  node = (FTC_SizeNode)ftcnode;
86    FT_Size       size = node->size;
87    FT_UNUSED( data );
88
89
90    if ( size )
91      FT_Done_Size( size );
92  }
93
94
95  FT_CALLBACK_DEF( FT_Bool )
96  ftc_size_node_compare( FTC_MruNode  ftcnode,
97                         FT_Pointer   ftcscaler )
98  {
99    FTC_SizeNode  node    = (FTC_SizeNode)ftcnode;
100    FTC_Scaler    scaler  = (FTC_Scaler)ftcscaler;
101    FTC_Scaler    scaler0 = &node->scaler;
102
103
104    if ( FTC_SCALER_COMPARE( scaler0, scaler ) )
105    {
106      FT_Activate_Size( node->size );
107      return 1;
108    }
109    return 0;
110  }
111
112
113  FT_CALLBACK_DEF( FT_Error )
114  ftc_size_node_init( FTC_MruNode  ftcnode,
115                      FT_Pointer   ftcscaler,
116                      FT_Pointer   ftcmanager )
117  {
118    FTC_SizeNode  node    = (FTC_SizeNode)ftcnode;
119    FTC_Scaler    scaler  = (FTC_Scaler)ftcscaler;
120    FTC_Manager   manager = (FTC_Manager)ftcmanager;
121
122
123    node->scaler = scaler[0];
124
125    return ftc_scaler_lookup_size( manager, scaler, &node->size );
126  }
127
128
129  FT_CALLBACK_DEF( FT_Error )
130  ftc_size_node_reset( FTC_MruNode  ftcnode,
131                       FT_Pointer   ftcscaler,
132                       FT_Pointer   ftcmanager )
133  {
134    FTC_SizeNode  node    = (FTC_SizeNode)ftcnode;
135    FTC_Scaler    scaler  = (FTC_Scaler)ftcscaler;
136    FTC_Manager   manager = (FTC_Manager)ftcmanager;
137
138
139    FT_Done_Size( node->size );
140
141    node->scaler = scaler[0];
142
143    return ftc_scaler_lookup_size( manager, scaler, &node->size );
144  }
145
146
147  FT_CALLBACK_TABLE_DEF
148  const FTC_MruListClassRec  ftc_size_list_class =
149  {
150    sizeof ( FTC_SizeNodeRec ),
151    ftc_size_node_compare,
152    ftc_size_node_init,
153    ftc_size_node_reset,
154    ftc_size_node_done
155  };
156
157
158  /* helper function used by ftc_face_node_done */
159  static FT_Bool
160  ftc_size_node_compare_faceid( FTC_MruNode  ftcnode,
161                                FT_Pointer   ftcface_id )
162  {
163    FTC_SizeNode  node    = (FTC_SizeNode)ftcnode;
164    FTC_FaceID    face_id = (FTC_FaceID)ftcface_id;
165
166
167    return FT_BOOL( node->scaler.face_id == face_id );
168  }
169
170
171  /* documentation is in ftcache.h */
172
173  FT_EXPORT_DEF( FT_Error )
174  FTC_Manager_LookupSize( FTC_Manager  manager,
175                          FTC_Scaler   scaler,
176                          FT_Size     *asize )
177  {
178    FT_Error      error;
179    FTC_SizeNode  node;
180
181
182    if ( asize == NULL )
183      return FTC_Err_Bad_Argument;
184
185    *asize = NULL;
186
187    if ( !manager )
188      return FTC_Err_Invalid_Cache_Handle;
189
190#ifdef FTC_INLINE
191
192    FTC_MRULIST_LOOKUP_CMP( &manager->sizes, scaler, ftc_size_node_compare,
193                            node, error );
194
195#else
196    error = FTC_MruList_Lookup( &manager->sizes, scaler, (FTC_MruNode*)&node );
197#endif
198
199    if ( !error )
200      *asize = node->size;
201
202    return error;
203  }
204
205
206  /*************************************************************************/
207  /*************************************************************************/
208  /*****                                                               *****/
209  /*****                    FACE MRU IMPLEMENTATION                    *****/
210  /*****                                                               *****/
211  /*************************************************************************/
212  /*************************************************************************/
213
214  typedef struct  FTC_FaceNodeRec_
215  {
216    FTC_MruNodeRec  node;
217    FTC_FaceID      face_id;
218    FT_Face         face;
219
220  } FTC_FaceNodeRec, *FTC_FaceNode;
221
222
223  FT_CALLBACK_DEF( FT_Error )
224  ftc_face_node_init( FTC_MruNode  ftcnode,
225                      FT_Pointer   ftcface_id,
226                      FT_Pointer   ftcmanager )
227  {
228    FTC_FaceNode  node    = (FTC_FaceNode)ftcnode;
229    FTC_FaceID    face_id = (FTC_FaceID)ftcface_id;
230    FTC_Manager   manager = (FTC_Manager)ftcmanager;
231    FT_Error      error;
232
233
234    node->face_id = face_id;
235
236    error = manager->request_face( face_id,
237                                   manager->library,
238                                   manager->request_data,
239                                   &node->face );
240    if ( !error )
241    {
242      /* destroy initial size object; it will be re-created later */
243      if ( node->face->size )
244        FT_Done_Size( node->face->size );
245    }
246
247    return error;
248  }
249
250
251  FT_CALLBACK_DEF( void )
252  ftc_face_node_done( FTC_MruNode  ftcnode,
253                      FT_Pointer   ftcmanager )
254  {
255    FTC_FaceNode  node    = (FTC_FaceNode)ftcnode;
256    FTC_Manager   manager = (FTC_Manager)ftcmanager;
257
258
259    /* we must begin by removing all scalers for the target face */
260    /* from the manager's list                                   */
261    FTC_MruList_RemoveSelection( &manager->sizes,
262                                 ftc_size_node_compare_faceid,
263                                 node->face_id );
264
265    /* all right, we can discard the face now */
266    FT_Done_Face( node->face );
267    node->face    = NULL;
268    node->face_id = NULL;
269  }
270
271
272  FT_CALLBACK_DEF( FT_Bool )
273  ftc_face_node_compare( FTC_MruNode  ftcnode,
274                         FT_Pointer   ftcface_id )
275  {
276    FTC_FaceNode  node    = (FTC_FaceNode)ftcnode;
277    FTC_FaceID    face_id = (FTC_FaceID)ftcface_id;
278
279
280    return FT_BOOL( node->face_id == face_id );
281  }
282
283
284  FT_CALLBACK_TABLE_DEF
285  const FTC_MruListClassRec  ftc_face_list_class =
286  {
287    sizeof ( FTC_FaceNodeRec),
288
289    ftc_face_node_compare,
290    ftc_face_node_init,
291    0,                          /* FTC_MruNode_ResetFunc */
292    ftc_face_node_done
293  };
294
295
296  /* documentation is in ftcache.h */
297
298  FT_EXPORT_DEF( FT_Error )
299  FTC_Manager_LookupFace( FTC_Manager  manager,
300                          FTC_FaceID   face_id,
301                          FT_Face     *aface )
302  {
303    FT_Error      error;
304    FTC_FaceNode  node;
305
306
307    if ( aface == NULL )
308      return FTC_Err_Bad_Argument;
309
310    *aface = NULL;
311
312    if ( !manager )
313      return FTC_Err_Invalid_Cache_Handle;
314
315    /* we break encapsulation for the sake of speed */
316#ifdef FTC_INLINE
317
318    FTC_MRULIST_LOOKUP_CMP( &manager->faces, face_id, ftc_face_node_compare,
319                            node, error );
320
321#else
322    error = FTC_MruList_Lookup( &manager->faces, face_id, (FTC_MruNode*)&node );
323#endif
324
325    if ( !error )
326      *aface = node->face;
327
328    return error;
329  }
330
331
332  /*************************************************************************/
333  /*************************************************************************/
334  /*****                                                               *****/
335  /*****                    CACHE MANAGER ROUTINES                     *****/
336  /*****                                                               *****/
337  /*************************************************************************/
338  /*************************************************************************/
339
340
341  /* documentation is in ftcache.h */
342
343  FT_EXPORT_DEF( FT_Error )
344  FTC_Manager_New( FT_Library          library,
345                   FT_UInt             max_faces,
346                   FT_UInt             max_sizes,
347                   FT_ULong            max_bytes,
348                   FTC_Face_Requester  requester,
349                   FT_Pointer          req_data,
350                   FTC_Manager        *amanager )
351  {
352    FT_Error     error;
353    FT_Memory    memory;
354    FTC_Manager  manager = 0;
355
356
357    if ( !library )
358      return FTC_Err_Invalid_Library_Handle;
359
360    memory = library->memory;
361
362    if ( FT_NEW( manager ) )
363      goto Exit;
364
365    if ( max_faces == 0 )
366      max_faces = FTC_MAX_FACES_DEFAULT;
367
368    if ( max_sizes == 0 )
369      max_sizes = FTC_MAX_SIZES_DEFAULT;
370
371    if ( max_bytes == 0 )
372      max_bytes = FTC_MAX_BYTES_DEFAULT;
373
374    manager->library      = library;
375    manager->memory       = memory;
376    manager->max_weight   = max_bytes;
377
378    manager->request_face = requester;
379    manager->request_data = req_data;
380
381    FTC_MruList_Init( &manager->faces,
382                      &ftc_face_list_class,
383                      max_faces,
384                      manager,
385                      memory );
386
387    FTC_MruList_Init( &manager->sizes,
388                      &ftc_size_list_class,
389                      max_sizes,
390                      manager,
391                      memory );
392
393    *amanager = manager;
394
395  Exit:
396    return error;
397  }
398
399
400  /* documentation is in ftcache.h */
401
402  FT_EXPORT_DEF( void )
403  FTC_Manager_Done( FTC_Manager  manager )
404  {
405    FT_Memory  memory;
406    FT_UInt    idx;
407
408
409    if ( !manager || !manager->library )
410      return;
411
412    memory = manager->memory;
413
414    /* now discard all caches */
415    for (idx = manager->num_caches; idx-- > 0; )
416    {
417      FTC_Cache  cache = manager->caches[idx];
418
419
420      if ( cache )
421      {
422        cache->clazz.cache_done( cache );
423        FT_FREE( cache );
424        manager->caches[idx] = NULL;
425      }
426    }
427    manager->num_caches = 0;
428
429    /* discard faces and sizes */
430    FTC_MruList_Done( &manager->sizes );
431    FTC_MruList_Done( &manager->faces );
432
433    manager->library = NULL;
434    manager->memory  = NULL;
435
436    FT_FREE( manager );
437  }
438
439
440  /* documentation is in ftcache.h */
441
442  FT_EXPORT_DEF( void )
443  FTC_Manager_Reset( FTC_Manager  manager )
444  {
445    if ( manager )
446    {
447      FTC_MruList_Reset( &manager->sizes );
448      FTC_MruList_Reset( &manager->faces );
449    }
450    /* XXX: FIXME: flush the caches? */
451  }
452
453
454#ifdef FT_DEBUG_ERROR
455
456  FT_EXPORT_DEF( void )
457  FTC_Manager_Check( FTC_Manager  manager )
458  {
459    FTC_Node  node, first;
460
461
462    first = manager->nodes_list;
463
464    /* check node weights */
465    if ( first )
466    {
467      FT_ULong  weight = 0;
468
469
470      node = first;
471
472      do
473      {
474        FTC_Cache  cache = manager->caches[node->cache_index];
475
476
477        if ( (FT_UInt)node->cache_index >= manager->num_caches )
478          FT_ERROR(( "FTC_Manager_Check: invalid node (cache index = %ld\n",
479                     node->cache_index ));
480        else
481          weight += cache->clazz.node_weight( node, cache );
482
483        node = FTC_NODE__NEXT( node );
484
485      } while ( node != first );
486
487      if ( weight != manager->cur_weight )
488        FT_ERROR(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
489                   manager->cur_weight, weight ));
490    }
491
492    /* check circular list */
493    if ( first )
494    {
495      FT_UFast  count = 0;
496
497
498      node = first;
499      do
500      {
501        count++;
502        node = FTC_NODE__NEXT( node );
503
504      } while ( node != first );
505
506      if ( count != manager->num_nodes )
507        FT_ERROR((
508          "FTC_Manager_Check: invalid cache node count %d instead of %d\n",
509          manager->num_nodes, count ));
510    }
511  }
512
513#endif /* FT_DEBUG_ERROR */
514
515
516  /* `Compress' the manager's data, i.e., get rid of old cache nodes */
517  /* that are not referenced anymore in order to limit the total     */
518  /* memory used by the cache.                                       */
519
520  /* documentation is in ftcmanag.h */
521
522  FT_EXPORT_DEF( void )
523  FTC_Manager_Compress( FTC_Manager  manager )
524  {
525    FTC_Node   node, first;
526
527
528    if ( !manager )
529      return;
530
531    first = manager->nodes_list;
532
533#ifdef FT_DEBUG_ERROR
534    FTC_Manager_Check( manager );
535
536    FT_ERROR(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
537               manager->cur_weight, manager->max_weight,
538               manager->num_nodes ));
539#endif
540
541    if ( manager->cur_weight < manager->max_weight || first == NULL )
542      return;
543
544    /* go to last node -- it's a circular list */
545    node = FTC_NODE__PREV( first );
546    do
547    {
548      FTC_Node  prev;
549
550
551      prev = ( node == first ) ? NULL : FTC_NODE__PREV( node );
552
553      if ( node->ref_count <= 0 )
554        ftc_node_destroy( node, manager );
555
556      node = prev;
557
558    } while ( node && manager->cur_weight > manager->max_weight );
559  }
560
561
562  /* documentation is in ftcmanag.h */
563
564  FT_EXPORT_DEF( FT_Error )
565  FTC_Manager_RegisterCache( FTC_Manager      manager,
566                             FTC_CacheClass   clazz,
567                             FTC_Cache       *acache )
568  {
569    FT_Error   error = FTC_Err_Invalid_Argument;
570    FTC_Cache  cache = NULL;
571
572
573    if ( manager && clazz && acache )
574    {
575      FT_Memory  memory = manager->memory;
576
577
578      if ( manager->num_caches >= FTC_MAX_CACHES )
579      {
580        error = FTC_Err_Too_Many_Caches;
581        FT_ERROR(( "%s: too many registered caches\n",
582                   "FTC_Manager_Register_Cache" ));
583        goto Exit;
584      }
585
586      if ( !FT_ALLOC( cache, clazz->cache_size ) )
587      {
588        cache->manager   = manager;
589        cache->memory    = memory;
590        cache->clazz     = clazz[0];
591        cache->org_class = clazz;
592
593        /* THIS IS VERY IMPORTANT!  IT WILL WRETCH THE MANAGER */
594        /* IF IT IS NOT SET CORRECTLY                          */
595        cache->index = manager->num_caches;
596
597        error = clazz->cache_init( cache );
598        if ( error )
599        {
600          clazz->cache_done( cache );
601          FT_FREE( cache );
602          goto Exit;
603        }
604
605        manager->caches[manager->num_caches++] = cache;
606      }
607    }
608
609  Exit:
610    *acache = cache;
611    return error;
612  }
613
614
615  FT_EXPORT_DEF( FT_UInt )
616  FTC_Manager_FlushN( FTC_Manager  manager,
617                      FT_UInt      count )
618  {
619    FTC_Node  first = manager->nodes_list;
620    FTC_Node  node;
621    FT_UInt   result;
622
623
624    /* try to remove `count' nodes from the list */
625    if ( first == NULL )  /* empty list! */
626      return 0;
627
628    /* go to last node - it's a circular list */
629    node = FTC_NODE__PREV(first);
630    for ( result = 0; result < count; )
631    {
632      FTC_Node  prev = FTC_NODE__PREV( node );
633
634
635      /* don't touch locked nodes */
636      if ( node->ref_count <= 0 )
637      {
638        ftc_node_destroy( node, manager );
639        result++;
640      }
641
642      if ( node == first )
643        break;
644
645      node = prev;
646    }
647    return  result;
648  }
649
650
651  /* documentation is in ftcache.h */
652
653  FT_EXPORT_DEF( void )
654  FTC_Manager_RemoveFaceID( FTC_Manager  manager,
655                            FTC_FaceID   face_id )
656  {
657    FT_UInt  nn;
658
659    /* this will remove all FTC_SizeNode that correspond to
660     * the face_id as well
661     */
662    FTC_MruList_RemoveSelection( &manager->faces, NULL, face_id );
663
664    for ( nn = 0; nn < manager->num_caches; nn++ )
665      FTC_Cache_RemoveFaceID( manager->caches[nn], face_id );
666  }
667
668
669  /* documentation is in ftcache.h */
670
671  FT_EXPORT_DEF( void )
672  FTC_Node_Unref( FTC_Node     node,
673                  FTC_Manager  manager )
674  {
675    if ( node && (FT_UInt)node->cache_index < manager->num_caches )
676      node->ref_count--;
677  }
678
679
680/* END */
Note: See TracBrowser for help on using the repository browser.