~ubuntu-branches/ubuntu/gutsy/vnc4/gutsy

« back to all changes in this revision

Viewing changes to unix/xc/extras/freetype2/src/cache/ftcmanag.c

  • Committer: Bazaar Package Importer
  • Author(s): Ola Lundqvist
  • Date: 2006-05-15 20:35:17 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060515203517-l4lre1ku942mn26k
Tags: 4.1.1+X4.3.0-10
* Correction of critical security issue. Thanks to Martin Kogler
  <e9925248@student.tuwien.ac.at> that informed me about the issue,
  and provided the patch.
  This flaw was originally found by Steve Wiseman of intelliadmin.com.
* Applied patch from Javier Kohen <jkohen@users.sourceforge.net> that
  inform the user that only 8 first characters of the password will
  actually be used when typing more than 8 characters, closes:
  #355619.

Show diffs side-by-side

added added

removed removed

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