Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/***************************************************************************/
2
/*                                                                         */
3
/*  ftcmanag.c                                                             */
4
/*                                                                         */
5
/*    FreeType Cache Manager (body).                                       */
6
/*                                                                         */
7
/*  Copyright 2000-2006, 2008-2010, 2013 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 
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 FT_THROW( Invalid_Argument );
191
 
192
    *asize = NULL;
193
 
194
    if ( !manager )
195
      return FT_THROW( 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 FT_THROW( Invalid_Argument );
318
 
319
    *aface = NULL;
320
 
321
    if ( !manager )
322
      return FT_THROW( 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 FT_THROW( 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
 
460
    FTC_Manager_FlushN( manager, manager->num_nodes );
461
  }
462
 
463
 
464
#ifdef FT_DEBUG_ERROR
465
 
466
  static void
467
  FTC_Manager_Check( FTC_Manager  manager )
468
  {
469
    FTC_Node  node, first;
470
 
471
 
472
    first = manager->nodes_list;
473
 
474
    /* check node weights */
475
    if ( first )
476
    {
477
      FT_Offset  weight = 0;
478
 
479
 
480
      node = first;
481
 
482
      do
483
      {
484
        FTC_Cache  cache = manager->caches[node->cache_index];
485
 
486
 
487
        if ( (FT_UInt)node->cache_index >= manager->num_caches )
488
          FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %ld\n",
489
                      node->cache_index ));
490
        else
491
          weight += cache->clazz.node_weight( node, cache );
492
 
493
        node = FTC_NODE__NEXT( node );
494
 
495
      } while ( node != first );
496
 
497
      if ( weight != manager->cur_weight )
498
        FT_TRACE0(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
499
                    manager->cur_weight, weight ));
500
    }
501
 
502
    /* check circular list */
503
    if ( first )
504
    {
505
      FT_UFast  count = 0;
506
 
507
 
508
      node = first;
509
      do
510
      {
511
        count++;
512
        node = FTC_NODE__NEXT( node );
513
 
514
      } while ( node != first );
515
 
516
      if ( count != manager->num_nodes )
517
        FT_TRACE0(( "FTC_Manager_Check:"
518
                    " invalid cache node count %d instead of %d\n",
519
                    manager->num_nodes, count ));
520
    }
521
  }
522
 
523
#endif /* FT_DEBUG_ERROR */
524
 
525
 
526
  /* `Compress' the manager's data, i.e., get rid of old cache nodes */
527
  /* that are not referenced anymore in order to limit the total     */
528
  /* memory used by the cache.                                       */
529
 
530
  /* documentation is in ftcmanag.h */
531
 
532
  FT_LOCAL_DEF( void )
533
  FTC_Manager_Compress( FTC_Manager  manager )
534
  {
535
    FTC_Node   node, first;
536
 
537
 
538
    if ( !manager )
539
      return;
540
 
541
    first = manager->nodes_list;
542
 
543
#ifdef FT_DEBUG_ERROR
544
    FTC_Manager_Check( manager );
545
 
546
    FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
547
                manager->cur_weight, manager->max_weight,
548
                manager->num_nodes ));
549
#endif
550
 
551
    if ( manager->cur_weight < manager->max_weight || first == NULL )
552
      return;
553
 
554
    /* go to last node -- it's a circular list */
555
    node = FTC_NODE__PREV( first );
556
    do
557
    {
558
      FTC_Node  prev;
559
 
560
 
561
      prev = ( node == first ) ? NULL : FTC_NODE__PREV( node );
562
 
563
      if ( node->ref_count <= 0 )
564
        ftc_node_destroy( node, manager );
565
 
566
      node = prev;
567
 
568
    } while ( node && manager->cur_weight > manager->max_weight );
569
  }
570
 
571
 
572
  /* documentation is in ftcmanag.h */
573
 
574
  FT_LOCAL_DEF( FT_Error )
575
  FTC_Manager_RegisterCache( FTC_Manager      manager,
576
                             FTC_CacheClass   clazz,
577
                             FTC_Cache       *acache )
578
  {
579
    FT_Error   error = FT_ERR( Invalid_Argument );
580
    FTC_Cache  cache = NULL;
581
 
582
 
583
    if ( manager && clazz && acache )
584
    {
585
      FT_Memory  memory = manager->memory;
586
 
587
 
588
      if ( manager->num_caches >= FTC_MAX_CACHES )
589
      {
590
        error = FT_THROW( Too_Many_Caches );
591
        FT_ERROR(( "FTC_Manager_RegisterCache:"
592
                   " too many registered caches\n" ));
593
        goto Exit;
594
      }
595
 
596
      if ( !FT_ALLOC( cache, clazz->cache_size ) )
597
      {
598
        cache->manager   = manager;
599
        cache->memory    = memory;
600
        cache->clazz     = clazz[0];
601
        cache->org_class = clazz;
602
 
603
        /* THIS IS VERY IMPORTANT!  IT WILL WRETCH THE MANAGER */
604
        /* IF IT IS NOT SET CORRECTLY                          */
605
        cache->index = manager->num_caches;
606
 
607
        error = clazz->cache_init( cache );
608
        if ( error )
609
        {
610
          clazz->cache_done( cache );
611
          FT_FREE( cache );
612
          goto Exit;
613
        }
614
 
615
        manager->caches[manager->num_caches++] = cache;
616
      }
617
    }
618
 
619
  Exit:
620
    if ( acache )
621
      *acache = cache;
622
    return error;
623
  }
624
 
625
 
626
  FT_LOCAL_DEF( FT_UInt )
627
  FTC_Manager_FlushN( FTC_Manager  manager,
628
                      FT_UInt      count )
629
  {
630
    FTC_Node  first = manager->nodes_list;
631
    FTC_Node  node;
632
    FT_UInt   result;
633
 
634
 
635
    /* try to remove `count' nodes from the list */
636
    if ( first == NULL )  /* empty list! */
637
      return 0;
638
 
639
    /* go to last node - it's a circular list */
640
    node = FTC_NODE__PREV(first);
641
    for ( result = 0; result < count; )
642
    {
643
      FTC_Node  prev = FTC_NODE__PREV( node );
644
 
645
 
646
      /* don't touch locked nodes */
647
      if ( node->ref_count <= 0 )
648
      {
649
        ftc_node_destroy( node, manager );
650
        result++;
651
      }
652
 
653
      if ( node == first )
654
        break;
655
 
656
      node = prev;
657
    }
658
    return  result;
659
  }
660
 
661
 
662
  /* documentation is in ftcache.h */
663
 
664
  FT_EXPORT_DEF( void )
665
  FTC_Manager_RemoveFaceID( FTC_Manager  manager,
666
                            FTC_FaceID   face_id )
667
  {
668
    FT_UInt  nn;
669
 
670
    /* this will remove all FTC_SizeNode that correspond to
671
     * the face_id as well
672
     */
673
    FTC_MruList_RemoveSelection( &manager->faces,
674
                                 ftc_face_node_compare,
675
                                 face_id );
676
 
677
    for ( nn = 0; nn < manager->num_caches; nn++ )
678
      FTC_Cache_RemoveFaceID( manager->caches[nn], face_id );
679
  }
680
 
681
 
682
  /* documentation is in ftcache.h */
683
 
684
  FT_EXPORT_DEF( void )
685
  FTC_Node_Unref( FTC_Node     node,
686
                  FTC_Manager  manager )
687
  {
688
    if ( node && (FT_UInt)node->cache_index < manager->num_caches )
689
      node->ref_count--;
690
  }
691
 
692
 
693
/* END */