/modules/freetype2/src/cache/ftcmanag.c

http://github.com/zpao/v8monkey · C · 743 lines · 477 code · 203 blank · 63 comment · 69 complexity · 402757c93ba690f47c779aa147ceddbc MD5 · raw file

  1. /***************************************************************************/
  2. /* */
  3. /* ftcmanag.c */
  4. /* */
  5. /* FreeType Cache Manager (body). */
  6. /* */
  7. /* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010 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. #include <ft2build.h>
  18. #include FT_CACHE_H
  19. #include "ftcmanag.h"
  20. #include FT_INTERNAL_OBJECTS_H
  21. #include FT_INTERNAL_DEBUG_H
  22. #include FT_SIZES_H
  23. #include "ftccback.h"
  24. #include "ftcerror.h"
  25. #ifdef FT_CONFIG_OPTION_PIC
  26. #error "cache system does not support PIC yet"
  27. #endif
  28. #undef FT_COMPONENT
  29. #define FT_COMPONENT trace_cache
  30. #define FTC_LRU_GET_MANAGER( lru ) ( (FTC_Manager)(lru)->user_data )
  31. static FT_Error
  32. ftc_scaler_lookup_size( FTC_Manager manager,
  33. FTC_Scaler scaler,
  34. FT_Size *asize )
  35. {
  36. FT_Face face;
  37. FT_Size size = NULL;
  38. FT_Error error;
  39. error = FTC_Manager_LookupFace( manager, scaler->face_id, &face );
  40. if ( error )
  41. goto Exit;
  42. error = FT_New_Size( face, &size );
  43. if ( error )
  44. goto Exit;
  45. FT_Activate_Size( size );
  46. if ( scaler->pixel )
  47. error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height );
  48. else
  49. error = FT_Set_Char_Size( face, scaler->width, scaler->height,
  50. scaler->x_res, scaler->y_res );
  51. if ( error )
  52. {
  53. FT_Done_Size( size );
  54. size = NULL;
  55. }
  56. Exit:
  57. *asize = size;
  58. return error;
  59. }
  60. typedef struct FTC_SizeNodeRec_
  61. {
  62. FTC_MruNodeRec node;
  63. FT_Size size;
  64. FTC_ScalerRec scaler;
  65. } FTC_SizeNodeRec, *FTC_SizeNode;
  66. #define FTC_SIZE_NODE( x ) ( (FTC_SizeNode)( x ) )
  67. FT_CALLBACK_DEF( void )
  68. ftc_size_node_done( FTC_MruNode ftcnode,
  69. FT_Pointer data )
  70. {
  71. FTC_SizeNode node = (FTC_SizeNode)ftcnode;
  72. FT_Size size = node->size;
  73. FT_UNUSED( data );
  74. if ( size )
  75. FT_Done_Size( size );
  76. }
  77. FT_CALLBACK_DEF( FT_Bool )
  78. ftc_size_node_compare( FTC_MruNode ftcnode,
  79. FT_Pointer ftcscaler )
  80. {
  81. FTC_SizeNode node = (FTC_SizeNode)ftcnode;
  82. FTC_Scaler scaler = (FTC_Scaler)ftcscaler;
  83. FTC_Scaler scaler0 = &node->scaler;
  84. if ( FTC_SCALER_COMPARE( scaler0, scaler ) )
  85. {
  86. FT_Activate_Size( node->size );
  87. return 1;
  88. }
  89. return 0;
  90. }
  91. FT_CALLBACK_DEF( FT_Error )
  92. ftc_size_node_init( FTC_MruNode ftcnode,
  93. FT_Pointer ftcscaler,
  94. FT_Pointer ftcmanager )
  95. {
  96. FTC_SizeNode node = (FTC_SizeNode)ftcnode;
  97. FTC_Scaler scaler = (FTC_Scaler)ftcscaler;
  98. FTC_Manager manager = (FTC_Manager)ftcmanager;
  99. node->scaler = scaler[0];
  100. return ftc_scaler_lookup_size( manager, scaler, &node->size );
  101. }
  102. FT_CALLBACK_DEF( FT_Error )
  103. ftc_size_node_reset( FTC_MruNode ftcnode,
  104. FT_Pointer ftcscaler,
  105. FT_Pointer ftcmanager )
  106. {
  107. FTC_SizeNode node = (FTC_SizeNode)ftcnode;
  108. FTC_Scaler scaler = (FTC_Scaler)ftcscaler;
  109. FTC_Manager manager = (FTC_Manager)ftcmanager;
  110. FT_Done_Size( node->size );
  111. node->scaler = scaler[0];
  112. return ftc_scaler_lookup_size( manager, scaler, &node->size );
  113. }
  114. FT_CALLBACK_TABLE_DEF
  115. const FTC_MruListClassRec ftc_size_list_class =
  116. {
  117. sizeof ( FTC_SizeNodeRec ),
  118. ftc_size_node_compare,
  119. ftc_size_node_init,
  120. ftc_size_node_reset,
  121. ftc_size_node_done
  122. };
  123. /* helper function used by ftc_face_node_done */
  124. static FT_Bool
  125. ftc_size_node_compare_faceid( FTC_MruNode ftcnode,
  126. FT_Pointer ftcface_id )
  127. {
  128. FTC_SizeNode node = (FTC_SizeNode)ftcnode;
  129. FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
  130. return FT_BOOL( node->scaler.face_id == face_id );
  131. }
  132. /* documentation is in ftcache.h */
  133. FT_EXPORT_DEF( FT_Error )
  134. FTC_Manager_LookupSize( FTC_Manager manager,
  135. FTC_Scaler scaler,
  136. FT_Size *asize )
  137. {
  138. FT_Error error;
  139. FTC_MruNode mrunode;
  140. if ( asize == NULL )
  141. return FTC_Err_Invalid_Argument;
  142. *asize = NULL;
  143. if ( !manager )
  144. return FTC_Err_Invalid_Cache_Handle;
  145. #ifdef FTC_INLINE
  146. FTC_MRULIST_LOOKUP_CMP( &manager->sizes, scaler, ftc_size_node_compare,
  147. mrunode, error );
  148. #else
  149. error = FTC_MruList_Lookup( &manager->sizes, scaler, &mrunode );
  150. #endif
  151. if ( !error )
  152. *asize = FTC_SIZE_NODE( mrunode )->size;
  153. return error;
  154. }
  155. /*************************************************************************/
  156. /*************************************************************************/
  157. /***** *****/
  158. /***** FACE MRU IMPLEMENTATION *****/
  159. /***** *****/
  160. /*************************************************************************/
  161. /*************************************************************************/
  162. typedef struct FTC_FaceNodeRec_
  163. {
  164. FTC_MruNodeRec node;
  165. FTC_FaceID face_id;
  166. FT_Face face;
  167. } FTC_FaceNodeRec, *FTC_FaceNode;
  168. #define FTC_FACE_NODE( x ) ( ( FTC_FaceNode )( x ) )
  169. FT_CALLBACK_DEF( FT_Error )
  170. ftc_face_node_init( FTC_MruNode ftcnode,
  171. FT_Pointer ftcface_id,
  172. FT_Pointer ftcmanager )
  173. {
  174. FTC_FaceNode node = (FTC_FaceNode)ftcnode;
  175. FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
  176. FTC_Manager manager = (FTC_Manager)ftcmanager;
  177. FT_Error error;
  178. node->face_id = face_id;
  179. error = manager->request_face( face_id,
  180. manager->library,
  181. manager->request_data,
  182. &node->face );
  183. if ( !error )
  184. {
  185. /* destroy initial size object; it will be re-created later */
  186. if ( node->face->size )
  187. FT_Done_Size( node->face->size );
  188. }
  189. return error;
  190. }
  191. FT_CALLBACK_DEF( void )
  192. ftc_face_node_done( FTC_MruNode ftcnode,
  193. FT_Pointer ftcmanager )
  194. {
  195. FTC_FaceNode node = (FTC_FaceNode)ftcnode;
  196. FTC_Manager manager = (FTC_Manager)ftcmanager;
  197. /* we must begin by removing all scalers for the target face */
  198. /* from the manager's list */
  199. FTC_MruList_RemoveSelection( &manager->sizes,
  200. ftc_size_node_compare_faceid,
  201. node->face_id );
  202. /* all right, we can discard the face now */
  203. FT_Done_Face( node->face );
  204. node->face = NULL;
  205. node->face_id = NULL;
  206. }
  207. FT_CALLBACK_DEF( FT_Bool )
  208. ftc_face_node_compare( FTC_MruNode ftcnode,
  209. FT_Pointer ftcface_id )
  210. {
  211. FTC_FaceNode node = (FTC_FaceNode)ftcnode;
  212. FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
  213. return FT_BOOL( node->face_id == face_id );
  214. }
  215. FT_CALLBACK_TABLE_DEF
  216. const FTC_MruListClassRec ftc_face_list_class =
  217. {
  218. sizeof ( FTC_FaceNodeRec),
  219. ftc_face_node_compare,
  220. ftc_face_node_init,
  221. 0, /* FTC_MruNode_ResetFunc */
  222. ftc_face_node_done
  223. };
  224. /* documentation is in ftcache.h */
  225. FT_EXPORT_DEF( FT_Error )
  226. FTC_Manager_LookupFace( FTC_Manager manager,
  227. FTC_FaceID face_id,
  228. FT_Face *aface )
  229. {
  230. FT_Error error;
  231. FTC_MruNode mrunode;
  232. if ( aface == NULL )
  233. return FTC_Err_Invalid_Argument;
  234. *aface = NULL;
  235. if ( !manager )
  236. return FTC_Err_Invalid_Cache_Handle;
  237. /* we break encapsulation for the sake of speed */
  238. #ifdef FTC_INLINE
  239. FTC_MRULIST_LOOKUP_CMP( &manager->faces, face_id, ftc_face_node_compare,
  240. mrunode, error );
  241. #else
  242. error = FTC_MruList_Lookup( &manager->faces, face_id, &mrunode );
  243. #endif
  244. if ( !error )
  245. *aface = FTC_FACE_NODE( mrunode )->face;
  246. return error;
  247. }
  248. /*************************************************************************/
  249. /*************************************************************************/
  250. /***** *****/
  251. /***** CACHE MANAGER ROUTINES *****/
  252. /***** *****/
  253. /*************************************************************************/
  254. /*************************************************************************/
  255. /* documentation is in ftcache.h */
  256. FT_EXPORT_DEF( FT_Error )
  257. FTC_Manager_New( FT_Library library,
  258. FT_UInt max_faces,
  259. FT_UInt max_sizes,
  260. FT_ULong max_bytes,
  261. FTC_Face_Requester requester,
  262. FT_Pointer req_data,
  263. FTC_Manager *amanager )
  264. {
  265. FT_Error error;
  266. FT_Memory memory;
  267. FTC_Manager manager = 0;
  268. if ( !library )
  269. return FTC_Err_Invalid_Library_Handle;
  270. memory = library->memory;
  271. if ( FT_NEW( manager ) )
  272. goto Exit;
  273. if ( max_faces == 0 )
  274. max_faces = FTC_MAX_FACES_DEFAULT;
  275. if ( max_sizes == 0 )
  276. max_sizes = FTC_MAX_SIZES_DEFAULT;
  277. if ( max_bytes == 0 )
  278. max_bytes = FTC_MAX_BYTES_DEFAULT;
  279. manager->library = library;
  280. manager->memory = memory;
  281. manager->max_weight = max_bytes;
  282. manager->request_face = requester;
  283. manager->request_data = req_data;
  284. FTC_MruList_Init( &manager->faces,
  285. &ftc_face_list_class,
  286. max_faces,
  287. manager,
  288. memory );
  289. FTC_MruList_Init( &manager->sizes,
  290. &ftc_size_list_class,
  291. max_sizes,
  292. manager,
  293. memory );
  294. *amanager = manager;
  295. Exit:
  296. return error;
  297. }
  298. /* documentation is in ftcache.h */
  299. FT_EXPORT_DEF( void )
  300. FTC_Manager_Done( FTC_Manager manager )
  301. {
  302. FT_Memory memory;
  303. FT_UInt idx;
  304. if ( !manager || !manager->library )
  305. return;
  306. memory = manager->memory;
  307. /* now discard all caches */
  308. for (idx = manager->num_caches; idx-- > 0; )
  309. {
  310. FTC_Cache cache = manager->caches[idx];
  311. if ( cache )
  312. {
  313. cache->clazz.cache_done( cache );
  314. FT_FREE( cache );
  315. manager->caches[idx] = NULL;
  316. }
  317. }
  318. manager->num_caches = 0;
  319. /* discard faces and sizes */
  320. FTC_MruList_Done( &manager->sizes );
  321. FTC_MruList_Done( &manager->faces );
  322. manager->library = NULL;
  323. manager->memory = NULL;
  324. FT_FREE( manager );
  325. }
  326. /* documentation is in ftcache.h */
  327. FT_EXPORT_DEF( void )
  328. FTC_Manager_Reset( FTC_Manager manager )
  329. {
  330. if ( manager )
  331. {
  332. FTC_MruList_Reset( &manager->sizes );
  333. FTC_MruList_Reset( &manager->faces );
  334. }
  335. /* XXX: FIXME: flush the caches? */
  336. }
  337. #ifdef FT_DEBUG_ERROR
  338. static void
  339. FTC_Manager_Check( FTC_Manager manager )
  340. {
  341. FTC_Node node, first;
  342. first = manager->nodes_list;
  343. /* check node weights */
  344. if ( first )
  345. {
  346. FT_ULong weight = 0;
  347. node = first;
  348. do
  349. {
  350. FTC_Cache cache = manager->caches[node->cache_index];
  351. if ( (FT_UInt)node->cache_index >= manager->num_caches )
  352. FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %ld\n",
  353. node->cache_index ));
  354. else
  355. weight += cache->clazz.node_weight( node, cache );
  356. node = FTC_NODE__NEXT( node );
  357. } while ( node != first );
  358. if ( weight != manager->cur_weight )
  359. FT_TRACE0(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
  360. manager->cur_weight, weight ));
  361. }
  362. /* check circular list */
  363. if ( first )
  364. {
  365. FT_UFast count = 0;
  366. node = first;
  367. do
  368. {
  369. count++;
  370. node = FTC_NODE__NEXT( node );
  371. } while ( node != first );
  372. if ( count != manager->num_nodes )
  373. FT_TRACE0(( "FTC_Manager_Check:"
  374. " invalid cache node count %d instead of %d\n",
  375. manager->num_nodes, count ));
  376. }
  377. }
  378. #endif /* FT_DEBUG_ERROR */
  379. /* `Compress' the manager's data, i.e., get rid of old cache nodes */
  380. /* that are not referenced anymore in order to limit the total */
  381. /* memory used by the cache. */
  382. /* documentation is in ftcmanag.h */
  383. FT_LOCAL_DEF( void )
  384. FTC_Manager_Compress( FTC_Manager manager )
  385. {
  386. FTC_Node node, first;
  387. if ( !manager )
  388. return;
  389. first = manager->nodes_list;
  390. #ifdef FT_DEBUG_ERROR
  391. FTC_Manager_Check( manager );
  392. FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
  393. manager->cur_weight, manager->max_weight,
  394. manager->num_nodes ));
  395. #endif
  396. if ( manager->cur_weight < manager->max_weight || first == NULL )
  397. return;
  398. /* go to last node -- it's a circular list */
  399. node = FTC_NODE__PREV( first );
  400. do
  401. {
  402. FTC_Node prev;
  403. prev = ( node == first ) ? NULL : FTC_NODE__PREV( node );
  404. if ( node->ref_count <= 0 )
  405. ftc_node_destroy( node, manager );
  406. node = prev;
  407. } while ( node && manager->cur_weight > manager->max_weight );
  408. }
  409. /* documentation is in ftcmanag.h */
  410. FT_LOCAL_DEF( FT_Error )
  411. FTC_Manager_RegisterCache( FTC_Manager manager,
  412. FTC_CacheClass clazz,
  413. FTC_Cache *acache )
  414. {
  415. FT_Error error = FTC_Err_Invalid_Argument;
  416. FTC_Cache cache = NULL;
  417. if ( manager && clazz && acache )
  418. {
  419. FT_Memory memory = manager->memory;
  420. if ( manager->num_caches >= FTC_MAX_CACHES )
  421. {
  422. error = FTC_Err_Too_Many_Caches;
  423. FT_ERROR(( "FTC_Manager_RegisterCache:"
  424. " too many registered caches\n" ));
  425. goto Exit;
  426. }
  427. if ( !FT_ALLOC( cache, clazz->cache_size ) )
  428. {
  429. cache->manager = manager;
  430. cache->memory = memory;
  431. cache->clazz = clazz[0];
  432. cache->org_class = clazz;
  433. /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */
  434. /* IF IT IS NOT SET CORRECTLY */
  435. cache->index = manager->num_caches;
  436. error = clazz->cache_init( cache );
  437. if ( error )
  438. {
  439. clazz->cache_done( cache );
  440. FT_FREE( cache );
  441. goto Exit;
  442. }
  443. manager->caches[manager->num_caches++] = cache;
  444. }
  445. }
  446. Exit:
  447. if ( acache )
  448. *acache = cache;
  449. return error;
  450. }
  451. FT_LOCAL_DEF( FT_UInt )
  452. FTC_Manager_FlushN( FTC_Manager manager,
  453. FT_UInt count )
  454. {
  455. FTC_Node first = manager->nodes_list;
  456. FTC_Node node;
  457. FT_UInt result;
  458. /* try to remove `count' nodes from the list */
  459. if ( first == NULL ) /* empty list! */
  460. return 0;
  461. /* go to last node - it's a circular list */
  462. node = FTC_NODE__PREV(first);
  463. for ( result = 0; result < count; )
  464. {
  465. FTC_Node prev = FTC_NODE__PREV( node );
  466. /* don't touch locked nodes */
  467. if ( node->ref_count <= 0 )
  468. {
  469. ftc_node_destroy( node, manager );
  470. result++;
  471. }
  472. if ( node == first )
  473. break;
  474. node = prev;
  475. }
  476. return result;
  477. }
  478. /* documentation is in ftcache.h */
  479. FT_EXPORT_DEF( void )
  480. FTC_Manager_RemoveFaceID( FTC_Manager manager,
  481. FTC_FaceID face_id )
  482. {
  483. FT_UInt nn;
  484. /* this will remove all FTC_SizeNode that correspond to
  485. * the face_id as well
  486. */
  487. FTC_MruList_RemoveSelection( &manager->faces,
  488. ftc_face_node_compare,
  489. face_id );
  490. for ( nn = 0; nn < manager->num_caches; nn++ )
  491. FTC_Cache_RemoveFaceID( manager->caches[nn], face_id );
  492. }
  493. /* documentation is in ftcache.h */
  494. FT_EXPORT_DEF( void )
  495. FTC_Node_Unref( FTC_Node node,
  496. FTC_Manager manager )
  497. {
  498. if ( node && (FT_UInt)node->cache_index < manager->num_caches )
  499. node->ref_count--;
  500. }
  501. #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
  502. FT_EXPORT_DEF( FT_Error )
  503. FTC_Manager_Lookup_Face( FTC_Manager manager,
  504. FTC_FaceID face_id,
  505. FT_Face *aface )
  506. {
  507. return FTC_Manager_LookupFace( manager, face_id, aface );
  508. }
  509. FT_EXPORT( FT_Error )
  510. FTC_Manager_Lookup_Size( FTC_Manager manager,
  511. FTC_Font font,
  512. FT_Face *aface,
  513. FT_Size *asize )
  514. {
  515. FTC_ScalerRec scaler;
  516. FT_Error error;
  517. FT_Size size;
  518. FT_Face face;
  519. scaler.face_id = font->face_id;
  520. scaler.width = font->pix_width;
  521. scaler.height = font->pix_height;
  522. scaler.pixel = TRUE;
  523. scaler.x_res = 0;
  524. scaler.y_res = 0;
  525. error = FTC_Manager_LookupSize( manager, &scaler, &size );
  526. if ( error )
  527. {
  528. face = NULL;
  529. size = NULL;
  530. }
  531. else
  532. face = size->face;
  533. if ( aface )
  534. *aface = face;
  535. if ( asize )
  536. *asize = size;
  537. return error;
  538. }
  539. #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
  540. /* END */