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