sdk-world v2026.11.05
PS2 SDK - world tier (copyleft-allowed, non-essential packages)
Loading...
Searching...
No Matches
ftcmanag.c
1/****************************************************************************
2 *
3 * ftcmanag.c
4 *
5 * FreeType Cache Manager (body).
6 *
7 * Copyright (C) 2000-2025 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 <freetype/ftcache.h>
20#include "ftcmanag.h"
23#include <freetype/ftsizes.h>
24
25#include "ftcerror.h"
26
27
28#undef FT_COMPONENT
29#define FT_COMPONENT cache
30
31
32 static FT_Error
33 ftc_scaler_lookup_size( FTC_Manager manager,
34 FTC_Scaler scaler,
35 FT_Size *asize )
36 {
37 FT_Face face;
38 FT_Size size = NULL;
39 FT_Error error;
40
41
42 error = FTC_Manager_LookupFace( manager, scaler->face_id, &face );
43 if ( error )
44 goto Exit;
45
46 error = FT_New_Size( face, &size );
47 if ( error )
48 goto Exit;
49
50 FT_Activate_Size( size );
51
52 if ( scaler->pixel )
53 error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height );
54 else
55 error = FT_Set_Char_Size( face,
56 (FT_F26Dot6)scaler->width,
57 (FT_F26Dot6)scaler->height,
58 scaler->x_res,
59 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#define FTC_SIZE_NODE( x ) ( (FTC_SizeNode)( x ) )
81
82
83 FT_CALLBACK_DEF( void )
84 ftc_size_node_done( FTC_MruNode ftcnode,
85 FT_Pointer data )
86 {
87 FTC_SizeNode node = (FTC_SizeNode)ftcnode;
88 FT_UNUSED( data );
89
90
91 FT_Done_Size( node->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 FT_Error error;
119 FT_Size size;
120 FTC_SizeNode node = (FTC_SizeNode)ftcnode;
121 FTC_Scaler scaler = (FTC_Scaler)ftcscaler;
122 FTC_Manager manager = (FTC_Manager)ftcmanager;
123
124
125 error = ftc_scaler_lookup_size( manager, scaler, &size );
126 if ( !error )
127 {
128 node->size = size;
129 node->scaler = scaler[0];
130 }
131
132 return error;
133 }
134
135
136 static
137 const FTC_MruListClassRec ftc_size_list_class =
138 {
139 sizeof ( FTC_SizeNodeRec ),
140
141 ftc_size_node_compare, /* FTC_MruNode_CompareFunc node_compare */
142 ftc_size_node_init, /* FTC_MruNode_InitFunc node_init */
143 ftc_size_node_done /* FTC_MruNode_DoneFunc node_done */
144 };
145
146
147 /* helper function used by ftc_face_node_done */
148 static FT_Bool
149 ftc_size_node_compare_faceid( FTC_MruNode ftcnode,
150 FT_Pointer ftcface_id )
151 {
152 FTC_SizeNode node = (FTC_SizeNode)ftcnode;
153 FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
154
155
156 return FT_BOOL( node->scaler.face_id == face_id );
157 }
158
159
160 /* documentation is in ftcache.h */
161
162 FT_EXPORT_DEF( FT_Error )
163 FTC_Manager_LookupSize( FTC_Manager manager,
164 FTC_Scaler scaler,
165 FT_Size *asize )
166 {
167 FT_Error error;
168 FTC_MruNode mrunode;
169
170
171 if ( !asize || !scaler )
172 return FT_THROW( Invalid_Argument );
173
174 *asize = NULL;
175
176 if ( !manager )
177 return FT_THROW( Invalid_Cache_Handle );
178
179#ifdef FTC_INLINE
180
181 FTC_MRULIST_LOOKUP_CMP( &manager->sizes, scaler, ftc_size_node_compare,
182 mrunode, error );
183
184#else
185 error = FTC_MruList_Lookup( &manager->sizes, scaler, &mrunode );
186#endif
187
188 if ( !error )
189 *asize = FTC_SIZE_NODE( mrunode )->size;
190
191 return error;
192 }
193
194
195 /*************************************************************************/
196 /*************************************************************************/
197 /***** *****/
198 /***** FACE MRU IMPLEMENTATION *****/
199 /***** *****/
200 /*************************************************************************/
201 /*************************************************************************/
202
203 typedef struct FTC_FaceNodeRec_
204 {
205 FTC_MruNodeRec node;
206 FTC_FaceID face_id;
207 FT_Face face;
208
209 } FTC_FaceNodeRec, *FTC_FaceNode;
210
211#define FTC_FACE_NODE( x ) ( ( FTC_FaceNode )( x ) )
212
213
214 FT_CALLBACK_DEF( FT_Error )
215 ftc_face_node_init( FTC_MruNode ftcnode,
216 FT_Pointer ftcface_id,
217 FT_Pointer ftcmanager )
218 {
219 FT_Error error;
220 FT_Face face;
221 FTC_FaceNode node = (FTC_FaceNode)ftcnode;
222 FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
223 FTC_Manager manager = (FTC_Manager)ftcmanager;
224
225
226 error = manager->request_face( face_id,
227 manager->library,
228 manager->request_data,
229 &face );
230 if ( !error )
231 {
232 /* destroy initial size object; it will be re-created later */
233 if ( face->size )
234 FT_Done_Size( face->size );
235
236 node->face = face;
237 node->face_id = face_id;
238 }
239
240 return error;
241 }
242
243
244 FT_CALLBACK_DEF( void )
245 ftc_face_node_done( FTC_MruNode ftcnode,
246 FT_Pointer ftcmanager )
247 {
248 FTC_FaceNode node = (FTC_FaceNode)ftcnode;
249 FTC_Manager manager = (FTC_Manager)ftcmanager;
250
251
252 /* we must begin by removing all scalers for the target face */
253 /* from the manager's list */
254 FTC_MruList_RemoveSelection( &manager->sizes,
255 ftc_size_node_compare_faceid,
256 node->face_id );
257
258 /* all right, we can discard the face now */
259 FT_Done_Face( node->face );
260 node->face = NULL;
261 node->face_id = NULL;
262 }
263
264
265 FT_CALLBACK_DEF( FT_Bool )
266 ftc_face_node_compare( FTC_MruNode ftcnode,
267 FT_Pointer ftcface_id )
268 {
269 FTC_FaceNode node = (FTC_FaceNode)ftcnode;
270 FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
271
272
273 return FT_BOOL( node->face_id == face_id );
274 }
275
276
277 static
278 const FTC_MruListClassRec ftc_face_list_class =
279 {
280 sizeof ( FTC_FaceNodeRec),
281
282 ftc_face_node_compare, /* FTC_MruNode_CompareFunc node_compare */
283 ftc_face_node_init, /* FTC_MruNode_InitFunc node_init */
284 ftc_face_node_done /* FTC_MruNode_DoneFunc node_done */
285 };
286
287
288 /* documentation is in ftcache.h */
289
290 FT_EXPORT_DEF( FT_Error )
291 FTC_Manager_LookupFace( FTC_Manager manager,
292 FTC_FaceID face_id,
293 FT_Face *aface )
294 {
295 FT_Error error;
296 FTC_MruNode mrunode;
297
298
299 if ( !aface )
300 return FT_THROW( Invalid_Argument );
301
302 *aface = NULL;
303
304 if ( !manager )
305 return FT_THROW( Invalid_Cache_Handle );
306
307 /* we break encapsulation for the sake of speed */
308#ifdef FTC_INLINE
309
310 FTC_MRULIST_LOOKUP_CMP( &manager->faces, face_id, ftc_face_node_compare,
311 mrunode, error );
312
313#else
314 error = FTC_MruList_Lookup( &manager->faces, face_id, &mrunode );
315#endif
316
317 if ( !error )
318 *aface = FTC_FACE_NODE( mrunode )->face;
319
320 return error;
321 }
322
323
324 /*************************************************************************/
325 /*************************************************************************/
326 /***** *****/
327 /***** CACHE MANAGER ROUTINES *****/
328 /***** *****/
329 /*************************************************************************/
330 /*************************************************************************/
331
332
333 /* documentation is in ftcache.h */
334
335 FT_EXPORT_DEF( FT_Error )
336 FTC_Manager_New( FT_Library library,
337 FT_UInt max_faces,
338 FT_UInt max_sizes,
339 FT_ULong max_bytes,
340 FTC_Face_Requester requester,
341 FT_Pointer req_data,
342 FTC_Manager *amanager )
343 {
344 FT_Error error;
345 FT_Memory memory;
346 FTC_Manager manager = NULL;
347
348
349 if ( !library )
350 return FT_THROW( Invalid_Library_Handle );
351
352 if ( !amanager || !requester )
353 return FT_THROW( Invalid_Argument );
354
355 memory = library->memory;
356
357 if ( FT_QNEW( manager ) )
358 goto Exit;
359
360 if ( max_faces == 0 )
361 max_faces = FTC_MAX_FACES_DEFAULT;
362
363 if ( max_sizes == 0 )
364 max_sizes = FTC_MAX_SIZES_DEFAULT;
365
366 if ( max_bytes == 0 )
367 max_bytes = FTC_MAX_BYTES_DEFAULT;
368
369 manager->library = library;
370 manager->memory = memory;
371 manager->max_weight = max_bytes;
372 manager->cur_weight = 0;
373
374 manager->request_face = requester;
375 manager->request_data = req_data;
376
377 FTC_MruList_Init( &manager->faces,
378 &ftc_face_list_class,
379 max_faces,
380 manager,
381 memory );
382
383 FTC_MruList_Init( &manager->sizes,
384 &ftc_size_list_class,
385 max_sizes,
386 manager,
387 memory );
388
389 manager->nodes_list = NULL;
390 manager->num_nodes = 0;
391 manager->num_caches = 0;
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 }
425 }
426
427 /* discard faces and sizes */
428 FTC_MruList_Done( &manager->sizes );
429 FTC_MruList_Done( &manager->faces );
430
431 FT_FREE( manager );
432 }
433
434
435 /* documentation is in ftcache.h */
436
437 FT_EXPORT_DEF( void )
438 FTC_Manager_Reset( FTC_Manager manager )
439 {
440 if ( !manager )
441 return;
442
443 FTC_MruList_Reset( &manager->sizes );
444 FTC_MruList_Reset( &manager->faces );
445
446 FTC_Manager_FlushN( manager, manager->num_nodes );
447 }
448
449
450#ifdef FT_DEBUG_ERROR
451
452 static void
453 FTC_Manager_Check( FTC_Manager manager )
454 {
455 FTC_Node node, first;
456
457
458 first = manager->nodes_list;
459
460 /* check node weights */
461 if ( first )
462 {
463 FT_Offset weight = 0;
464
465
466 node = first;
467
468 do
469 {
470 FTC_Cache cache = manager->caches[node->cache_index];
471
472
473 if ( node->cache_index >= manager->num_caches )
474 FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %hu\n",
475 node->cache_index ));
476 else
477 weight += cache->clazz.node_weight( node, cache );
478
479 node = FTC_NODE_NEXT( node );
480
481 } while ( node != first );
482
483 if ( weight != manager->cur_weight )
484 FT_TRACE0(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
485 manager->cur_weight, weight ));
486 }
487
488 /* check circular list */
489 if ( first )
490 {
491 FT_UFast count = 0;
492
493
494 node = first;
495 do
496 {
497 count++;
498 node = FTC_NODE_NEXT( node );
499
500 } while ( node != first );
501
502 if ( count != manager->num_nodes )
503 FT_TRACE0(( "FTC_Manager_Check:"
504 " invalid cache node count %u instead of %u\n",
505 manager->num_nodes, count ));
506 }
507 }
508
509#endif /* FT_DEBUG_ERROR */
510
511
512 /* `Compress' the manager's data, i.e., get rid of old cache nodes */
513 /* that are not referenced anymore in order to limit the total */
514 /* memory used by the cache. */
515
516 /* documentation is in ftcmanag.h */
517
518 FT_LOCAL_DEF( void )
519 FTC_Manager_Compress( FTC_Manager manager )
520 {
521 FTC_Node node, prev, first;
522
523
524 if ( !manager )
525 return;
526
527 first = manager->nodes_list;
528
529#ifdef FT_DEBUG_ERROR
530 FTC_Manager_Check( manager );
531
532 FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %u\n",
533 manager->cur_weight, manager->max_weight,
534 manager->num_nodes ));
535#endif
536
537 if ( manager->cur_weight < manager->max_weight || !first )
538 return;
539
540 /* go to last node -- it's a circular list */
541 prev = FTC_NODE_PREV( first );
542 do
543 {
544 node = prev;
545 prev = FTC_NODE_PREV( node );
546
547 if ( node->ref_count <= 0 )
548 ftc_node_destroy( node, manager );
549
550 } while ( node != first && manager->cur_weight > manager->max_weight );
551 }
552
553
554 /* documentation is in ftcmanag.h */
555
556 FT_LOCAL_DEF( FT_Error )
557 FTC_Manager_RegisterCache( FTC_Manager manager,
558 FTC_CacheClass clazz,
559 FTC_Cache *acache )
560 {
561 FT_Error error = FT_ERR( Invalid_Argument );
562 FTC_Cache cache = NULL;
563
564
565 if ( manager && clazz && acache )
566 {
567 FT_Memory memory = manager->memory;
568
569
570 if ( manager->num_caches >= FTC_MAX_CACHES )
571 {
572 error = FT_THROW( Too_Many_Caches );
573 FT_ERROR(( "FTC_Manager_RegisterCache:"
574 " too many registered caches\n" ));
575 goto Exit;
576 }
577
578 if ( !FT_QALLOC( cache, clazz->cache_size ) )
579 {
580 cache->manager = manager;
581 cache->memory = memory;
582 cache->clazz = clazz[0];
583 cache->org_class = clazz;
584
585 /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */
586 /* IF IT IS NOT SET CORRECTLY */
587 cache->index = manager->num_caches;
588
589 error = clazz->cache_init( cache );
590 if ( error )
591 {
592 clazz->cache_done( cache );
593 FT_FREE( cache );
594 goto Exit;
595 }
596
597 manager->caches[manager->num_caches++] = cache;
598 }
599 }
600
601 Exit:
602 if ( acache )
603 *acache = cache;
604 return error;
605 }
606
607
608 FT_LOCAL_DEF( FT_UInt )
609 FTC_Manager_FlushN( FTC_Manager manager,
610 FT_UInt count )
611 {
612 FTC_Node first = manager->nodes_list;
613 FTC_Node prev, node;
614 FT_UInt result = 0;
615
616
617 /* try to remove `count' nodes from the list */
618 if ( !first || !count )
619 return result;
620
621 /* go to last node -- it's a circular list */
622 prev = FTC_NODE_PREV( first );
623 do
624 {
625 node = prev;
626 prev = FTC_NODE_PREV( node );
627
628 /* don't touch locked nodes */
629 if ( node->ref_count <= 0 )
630 {
631 ftc_node_destroy( node, manager );
632 result++;
633 }
634 } while ( node != first && result < count );
635
636 return result;
637 }
638
639
640 /* documentation is in ftcache.h */
641
642 FT_EXPORT_DEF( void )
643 FTC_Manager_RemoveFaceID( FTC_Manager manager,
644 FTC_FaceID face_id )
645 {
646 FT_UInt nn;
647
648
649 if ( !manager )
650 return;
651
652 /* this will remove all FTC_SizeNode that correspond to
653 * the face_id as well
654 */
655 FTC_MruList_RemoveSelection( &manager->faces,
656 ftc_face_node_compare,
657 face_id );
658
659 for ( nn = 0; nn < manager->num_caches; nn++ )
660 FTC_Cache_RemoveFaceID( manager->caches[nn], face_id );
661 }
662
663
664 /* documentation is in ftcache.h */
665
666 FT_EXPORT_DEF( void )
667 FTC_Node_Unref( FTC_Node node,
668 FTC_Manager manager )
669 {
670 if ( node &&
671 manager &&
672 node->cache_index < manager->num_caches )
673 node->ref_count--;
674 }
675
676
677/* END */