source: trunk/poppler/freetype2/src/cache/ftcmanag.c @ 262

Last change on this file since 262 was 262, checked in by Eugene Romanenko, 13 years ago

PDF plugin: freetype library updated to version 2.3.8

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