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