PageRenderTime 33ms CodeModel.GetById 2ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

/src/freetype/src/cache/ftcmanag.c

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