/src/freetype/src/cache/ftcsbits.c

https://bitbucket.org/cabalistic/ogredeps/ · C · 421 lines · 254 code · 88 blank · 79 comment · 33 complexity · ea403d3fbbdfd75045c4322da125beb9 MD5 · raw file

  1. /***************************************************************************/
  2. /* */
  3. /* ftcsbits.c */
  4. /* */
  5. /* FreeType sbits manager (body). */
  6. /* */
  7. /* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010, 2011 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 "ftcsbits.h"
  20. #include FT_INTERNAL_OBJECTS_H
  21. #include FT_INTERNAL_DEBUG_H
  22. #include FT_ERRORS_H
  23. #include "ftccback.h"
  24. #include "ftcerror.h"
  25. #undef FT_COMPONENT
  26. #define FT_COMPONENT trace_cache
  27. /*************************************************************************/
  28. /*************************************************************************/
  29. /***** *****/
  30. /***** SBIT CACHE NODES *****/
  31. /***** *****/
  32. /*************************************************************************/
  33. /*************************************************************************/
  34. static FT_Error
  35. ftc_sbit_copy_bitmap( FTC_SBit sbit,
  36. FT_Bitmap* bitmap,
  37. FT_Memory memory )
  38. {
  39. FT_Error error;
  40. FT_Int pitch = bitmap->pitch;
  41. FT_ULong size;
  42. if ( pitch < 0 )
  43. pitch = -pitch;
  44. size = (FT_ULong)( pitch * bitmap->rows );
  45. if ( !FT_ALLOC( sbit->buffer, size ) )
  46. FT_MEM_COPY( sbit->buffer, bitmap->buffer, size );
  47. return error;
  48. }
  49. FT_LOCAL_DEF( void )
  50. ftc_snode_free( FTC_Node ftcsnode,
  51. FTC_Cache cache )
  52. {
  53. FTC_SNode snode = (FTC_SNode)ftcsnode;
  54. FTC_SBit sbit = snode->sbits;
  55. FT_UInt count = snode->count;
  56. FT_Memory memory = cache->memory;
  57. for ( ; count > 0; sbit++, count-- )
  58. FT_FREE( sbit->buffer );
  59. FTC_GNode_Done( FTC_GNODE( snode ), cache );
  60. FT_FREE( snode );
  61. }
  62. FT_LOCAL_DEF( void )
  63. FTC_SNode_Free( FTC_SNode snode,
  64. FTC_Cache cache )
  65. {
  66. ftc_snode_free( FTC_NODE( snode ), cache );
  67. }
  68. /*
  69. * This function tries to load a small bitmap within a given FTC_SNode.
  70. * Note that it returns a non-zero error code _only_ in the case of
  71. * out-of-memory condition. For all other errors (e.g., corresponding
  72. * to a bad font file), this function will mark the sbit as `unavailable'
  73. * and return a value of 0.
  74. *
  75. * You should also read the comment within the @ftc_snode_compare
  76. * function below to see how out-of-memory is handled during a lookup.
  77. */
  78. static FT_Error
  79. ftc_snode_load( FTC_SNode snode,
  80. FTC_Manager manager,
  81. FT_UInt gindex,
  82. FT_ULong *asize )
  83. {
  84. FT_Error error;
  85. FTC_GNode gnode = FTC_GNODE( snode );
  86. FTC_Family family = gnode->family;
  87. FT_Memory memory = manager->memory;
  88. FT_Face face;
  89. FTC_SBit sbit;
  90. FTC_SFamilyClass clazz;
  91. if ( (FT_UInt)(gindex - gnode->gindex) >= snode->count )
  92. {
  93. FT_ERROR(( "ftc_snode_load: invalid glyph index" ));
  94. return FTC_Err_Invalid_Argument;
  95. }
  96. sbit = snode->sbits + ( gindex - gnode->gindex );
  97. clazz = (FTC_SFamilyClass)family->clazz;
  98. sbit->buffer = 0;
  99. error = clazz->family_load_glyph( family, gindex, manager, &face );
  100. if ( error )
  101. goto BadGlyph;
  102. {
  103. FT_Int temp;
  104. FT_GlyphSlot slot = face->glyph;
  105. FT_Bitmap* bitmap = &slot->bitmap;
  106. FT_Pos xadvance, yadvance; /* FT_GlyphSlot->advance.{x|y} */
  107. if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
  108. {
  109. FT_TRACE0(( "ftc_snode_load:"
  110. " glyph loaded didn't return a bitmap\n" ));
  111. goto BadGlyph;
  112. }
  113. /* Check that our values fit into 8-bit containers! */
  114. /* If this is not the case, our bitmap is too large */
  115. /* and we will leave it as `missing' with sbit.buffer = 0 */
  116. #define CHECK_CHAR( d ) ( temp = (FT_Char)d, temp == d )
  117. #define CHECK_BYTE( d ) ( temp = (FT_Byte)d, temp == d )
  118. /* horizontal advance in pixels */
  119. xadvance = ( slot->advance.x + 32 ) >> 6;
  120. yadvance = ( slot->advance.y + 32 ) >> 6;
  121. if ( !CHECK_BYTE( bitmap->rows ) ||
  122. !CHECK_BYTE( bitmap->width ) ||
  123. !CHECK_CHAR( bitmap->pitch ) ||
  124. !CHECK_CHAR( slot->bitmap_left ) ||
  125. !CHECK_CHAR( slot->bitmap_top ) ||
  126. !CHECK_CHAR( xadvance ) ||
  127. !CHECK_CHAR( yadvance ) )
  128. {
  129. FT_TRACE2(( "ftc_snode_load:"
  130. " glyph too large for small bitmap cache\n"));
  131. goto BadGlyph;
  132. }
  133. sbit->width = (FT_Byte)bitmap->width;
  134. sbit->height = (FT_Byte)bitmap->rows;
  135. sbit->pitch = (FT_Char)bitmap->pitch;
  136. sbit->left = (FT_Char)slot->bitmap_left;
  137. sbit->top = (FT_Char)slot->bitmap_top;
  138. sbit->xadvance = (FT_Char)xadvance;
  139. sbit->yadvance = (FT_Char)yadvance;
  140. sbit->format = (FT_Byte)bitmap->pixel_mode;
  141. sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1);
  142. /* copy the bitmap into a new buffer -- ignore error */
  143. error = ftc_sbit_copy_bitmap( sbit, bitmap, memory );
  144. /* now, compute size */
  145. if ( asize )
  146. *asize = FT_ABS( sbit->pitch ) * sbit->height;
  147. } /* glyph loading successful */
  148. /* ignore the errors that might have occurred -- */
  149. /* we mark unloaded glyphs with `sbit.buffer == 0' */
  150. /* and `width == 255', `height == 0' */
  151. /* */
  152. if ( error && error != FTC_Err_Out_Of_Memory )
  153. {
  154. BadGlyph:
  155. sbit->width = 255;
  156. sbit->height = 0;
  157. sbit->buffer = NULL;
  158. error = FTC_Err_Ok;
  159. if ( asize )
  160. *asize = 0;
  161. }
  162. return error;
  163. }
  164. FT_LOCAL_DEF( FT_Error )
  165. FTC_SNode_New( FTC_SNode *psnode,
  166. FTC_GQuery gquery,
  167. FTC_Cache cache )
  168. {
  169. FT_Memory memory = cache->memory;
  170. FT_Error error;
  171. FTC_SNode snode = NULL;
  172. FT_UInt gindex = gquery->gindex;
  173. FTC_Family family = gquery->family;
  174. FTC_SFamilyClass clazz = FTC_CACHE__SFAMILY_CLASS( cache );
  175. FT_UInt total;
  176. FT_UInt node_count;
  177. total = clazz->family_get_count( family, cache->manager );
  178. if ( total == 0 || gindex >= total )
  179. {
  180. error = FTC_Err_Invalid_Argument;
  181. goto Exit;
  182. }
  183. if ( !FT_NEW( snode ) )
  184. {
  185. FT_UInt count, start;
  186. start = gindex - ( gindex % FTC_SBIT_ITEMS_PER_NODE );
  187. count = total - start;
  188. if ( count > FTC_SBIT_ITEMS_PER_NODE )
  189. count = FTC_SBIT_ITEMS_PER_NODE;
  190. FTC_GNode_Init( FTC_GNODE( snode ), start, family );
  191. snode->count = count;
  192. for ( node_count = 0; node_count < count; node_count++ )
  193. {
  194. snode->sbits[node_count].width = 255;
  195. }
  196. error = ftc_snode_load( snode,
  197. cache->manager,
  198. gindex,
  199. NULL );
  200. if ( error )
  201. {
  202. FTC_SNode_Free( snode, cache );
  203. snode = NULL;
  204. }
  205. }
  206. Exit:
  207. *psnode = snode;
  208. return error;
  209. }
  210. FT_LOCAL_DEF( FT_Error )
  211. ftc_snode_new( FTC_Node *ftcpsnode,
  212. FT_Pointer ftcgquery,
  213. FTC_Cache cache )
  214. {
  215. FTC_SNode *psnode = (FTC_SNode*)ftcpsnode;
  216. FTC_GQuery gquery = (FTC_GQuery)ftcgquery;
  217. return FTC_SNode_New( psnode, gquery, cache );
  218. }
  219. FT_LOCAL_DEF( FT_Offset )
  220. ftc_snode_weight( FTC_Node ftcsnode,
  221. FTC_Cache cache )
  222. {
  223. FTC_SNode snode = (FTC_SNode)ftcsnode;
  224. FT_UInt count = snode->count;
  225. FTC_SBit sbit = snode->sbits;
  226. FT_Int pitch;
  227. FT_Offset size;
  228. FT_UNUSED( cache );
  229. FT_ASSERT( snode->count <= FTC_SBIT_ITEMS_PER_NODE );
  230. /* the node itself */
  231. size = sizeof ( *snode );
  232. for ( ; count > 0; count--, sbit++ )
  233. {
  234. if ( sbit->buffer )
  235. {
  236. pitch = sbit->pitch;
  237. if ( pitch < 0 )
  238. pitch = -pitch;
  239. /* add the size of a given glyph image */
  240. size += pitch * sbit->height;
  241. }
  242. }
  243. return size;
  244. }
  245. #if 0
  246. FT_LOCAL_DEF( FT_Offset )
  247. FTC_SNode_Weight( FTC_SNode snode )
  248. {
  249. return ftc_snode_weight( FTC_NODE( snode ), NULL );
  250. }
  251. #endif /* 0 */
  252. FT_LOCAL_DEF( FT_Bool )
  253. ftc_snode_compare( FTC_Node ftcsnode,
  254. FT_Pointer ftcgquery,
  255. FTC_Cache cache,
  256. FT_Bool* list_changed )
  257. {
  258. FTC_SNode snode = (FTC_SNode)ftcsnode;
  259. FTC_GQuery gquery = (FTC_GQuery)ftcgquery;
  260. FTC_GNode gnode = FTC_GNODE( snode );
  261. FT_UInt gindex = gquery->gindex;
  262. FT_Bool result;
  263. if (list_changed)
  264. *list_changed = FALSE;
  265. result = FT_BOOL( gnode->family == gquery->family &&
  266. (FT_UInt)( gindex - gnode->gindex ) < snode->count );
  267. if ( result )
  268. {
  269. /* check if we need to load the glyph bitmap now */
  270. FTC_SBit sbit = snode->sbits + ( gindex - gnode->gindex );
  271. /*
  272. * The following code illustrates what to do when you want to
  273. * perform operations that may fail within a lookup function.
  274. *
  275. * Here, we want to load a small bitmap on-demand; we thus
  276. * need to call the `ftc_snode_load' function which may return
  277. * a non-zero error code only when we are out of memory (OOM).
  278. *
  279. * The correct thing to do is to use @FTC_CACHE_TRYLOOP and
  280. * @FTC_CACHE_TRYLOOP_END in order to implement a retry loop
  281. * that is capable of flushing the cache incrementally when
  282. * an OOM errors occur.
  283. *
  284. * However, we need to `lock' the node before this operation to
  285. * prevent it from being flushed within the loop.
  286. *
  287. * When we exit the loop, we unlock the node, then check the `error'
  288. * variable. If it is non-zero, this means that the cache was
  289. * completely flushed and that no usable memory was found to load
  290. * the bitmap.
  291. *
  292. * We then prefer to return a value of 0 (i.e., NO MATCH). This
  293. * ensures that the caller will try to allocate a new node.
  294. * This operation consequently _fail_ and the lookup function
  295. * returns the appropriate OOM error code.
  296. *
  297. * Note that `buffer == NULL && width == 255' is a hack used to
  298. * tag `unavailable' bitmaps in the array. We should never try
  299. * to load these.
  300. *
  301. */
  302. if ( sbit->buffer == NULL && sbit->width == 255 )
  303. {
  304. FT_ULong size;
  305. FT_Error error;
  306. ftcsnode->ref_count++; /* lock node to prevent flushing */
  307. /* in retry loop */
  308. FTC_CACHE_TRYLOOP( cache )
  309. {
  310. error = ftc_snode_load( snode, cache->manager, gindex, &size );
  311. }
  312. FTC_CACHE_TRYLOOP_END( list_changed );
  313. ftcsnode->ref_count--; /* unlock the node */
  314. if ( error )
  315. result = 0;
  316. else
  317. cache->manager->cur_weight += size;
  318. }
  319. }
  320. return result;
  321. }
  322. #ifdef FTC_INLINE
  323. FT_LOCAL_DEF( FT_Bool )
  324. FTC_SNode_Compare( FTC_SNode snode,
  325. FTC_GQuery gquery,
  326. FTC_Cache cache,
  327. FT_Bool* list_changed )
  328. {
  329. return ftc_snode_compare( FTC_NODE( snode ), gquery,
  330. cache, list_changed );
  331. }
  332. #endif
  333. /* END */