Sync with trunk r47367
[reactos.git] / lib / 3rdparty / freetype / src / cache / ftcmanag.c
1 /***************************************************************************/
2 /* */
3 /* ftcmanag.c */
4 /* */
5 /* FreeType Cache Manager (body). */
6 /* */
7 /* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009 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_MruNode_CompareFunc)NULL,
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 */