Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / modules / freetype2 / src / cache / ftcsbits.c
blob72f139d565b91dbe8d4fb2f5d60066fc289252bf
1 /***************************************************************************/
2 /* */
3 /* ftcsbits.c */
4 /* */
5 /* FreeType sbits manager (body). */
6 /* */
7 /* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006 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 /***************************************************************************/
19 #include <ft2build.h>
20 #include FT_CACHE_H
21 #include "ftcsbits.h"
22 #include FT_INTERNAL_OBJECTS_H
23 #include FT_INTERNAL_DEBUG_H
24 #include FT_ERRORS_H
26 #include "ftccback.h"
27 #include "ftcerror.h"
30 /*************************************************************************/
31 /*************************************************************************/
32 /***** *****/
33 /***** SBIT CACHE NODES *****/
34 /***** *****/
35 /*************************************************************************/
36 /*************************************************************************/
39 static FT_Error
40 ftc_sbit_copy_bitmap( FTC_SBit sbit,
41 FT_Bitmap* bitmap,
42 FT_Memory memory )
44 FT_Error error;
45 FT_Int pitch = bitmap->pitch;
46 FT_ULong size;
49 if ( pitch < 0 )
50 pitch = -pitch;
52 size = (FT_ULong)( pitch * bitmap->rows );
54 if ( !FT_ALLOC( sbit->buffer, size ) )
55 FT_MEM_COPY( sbit->buffer, bitmap->buffer, size );
57 return error;
61 FT_LOCAL_DEF( void )
62 ftc_snode_free( FTC_Node ftcsnode,
63 FTC_Cache cache )
65 FTC_SNode snode = (FTC_SNode)ftcsnode;
66 FTC_SBit sbit = snode->sbits;
67 FT_UInt count = snode->count;
68 FT_Memory memory = cache->memory;
71 for ( ; count > 0; sbit++, count-- )
72 FT_FREE( sbit->buffer );
74 FTC_GNode_Done( FTC_GNODE( snode ), cache );
76 FT_FREE( snode );
80 FT_LOCAL_DEF( void )
81 FTC_SNode_Free( FTC_SNode snode,
82 FTC_Cache cache )
84 ftc_snode_free( FTC_NODE( snode ), cache );
89 * This function tries to load a small bitmap within a given FTC_SNode.
90 * Note that it returns a non-zero error code _only_ in the case of
91 * out-of-memory condition. For all other errors (e.g., corresponding
92 * to a bad font file), this function will mark the sbit as `unavailable'
93 * and return a value of 0.
95 * You should also read the comment within the @ftc_snode_compare
96 * function below to see how out-of-memory is handled during a lookup.
98 static FT_Error
99 ftc_snode_load( FTC_SNode snode,
100 FTC_Manager manager,
101 FT_UInt gindex,
102 FT_ULong *asize )
104 FT_Error error;
105 FTC_GNode gnode = FTC_GNODE( snode );
106 FTC_Family family = gnode->family;
107 FT_Memory memory = manager->memory;
108 FT_Face face;
109 FTC_SBit sbit;
110 FTC_SFamilyClass clazz;
113 if ( (FT_UInt)(gindex - gnode->gindex) >= snode->count )
115 FT_ERROR(( "ftc_snode_load: invalid glyph index" ));
116 return FTC_Err_Invalid_Argument;
119 sbit = snode->sbits + ( gindex - gnode->gindex );
120 clazz = (FTC_SFamilyClass)family->clazz;
122 sbit->buffer = 0;
124 error = clazz->family_load_glyph( family, gindex, manager, &face );
125 if ( error )
126 goto BadGlyph;
129 FT_Int temp;
130 FT_GlyphSlot slot = face->glyph;
131 FT_Bitmap* bitmap = &slot->bitmap;
132 FT_Int xadvance, yadvance;
135 if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
137 FT_ERROR(( "%s: glyph loaded didn't return a bitmap!\n",
138 "ftc_snode_load" ));
139 goto BadGlyph;
142 /* Check that our values fit into 8-bit containers! */
143 /* If this is not the case, our bitmap is too large */
144 /* and we will leave it as `missing' with sbit.buffer = 0 */
146 #define CHECK_CHAR( d ) ( temp = (FT_Char)d, temp == d )
147 #define CHECK_BYTE( d ) ( temp = (FT_Byte)d, temp == d )
149 /* horizontal advance in pixels */
150 xadvance = ( slot->advance.x + 32 ) >> 6;
151 yadvance = ( slot->advance.y + 32 ) >> 6;
153 if ( !CHECK_BYTE( bitmap->rows ) ||
154 !CHECK_BYTE( bitmap->width ) ||
155 !CHECK_CHAR( bitmap->pitch ) ||
156 !CHECK_CHAR( slot->bitmap_left ) ||
157 !CHECK_CHAR( slot->bitmap_top ) ||
158 !CHECK_CHAR( xadvance ) ||
159 !CHECK_CHAR( yadvance ) )
160 goto BadGlyph;
162 sbit->width = (FT_Byte)bitmap->width;
163 sbit->height = (FT_Byte)bitmap->rows;
164 sbit->pitch = (FT_Char)bitmap->pitch;
165 sbit->left = (FT_Char)slot->bitmap_left;
166 sbit->top = (FT_Char)slot->bitmap_top;
167 sbit->xadvance = (FT_Char)xadvance;
168 sbit->yadvance = (FT_Char)yadvance;
169 sbit->format = (FT_Byte)bitmap->pixel_mode;
170 sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1);
172 /* copy the bitmap into a new buffer -- ignore error */
173 error = ftc_sbit_copy_bitmap( sbit, bitmap, memory );
175 /* now, compute size */
176 if ( asize )
177 *asize = FT_ABS( sbit->pitch ) * sbit->height;
179 } /* glyph loading successful */
181 /* ignore the errors that might have occurred -- */
182 /* we mark unloaded glyphs with `sbit.buffer == 0' */
183 /* and `width == 255', `height == 0' */
184 /* */
185 if ( error && error != FTC_Err_Out_Of_Memory )
187 BadGlyph:
188 sbit->width = 255;
189 sbit->height = 0;
190 sbit->buffer = NULL;
191 error = 0;
192 if ( asize )
193 *asize = 0;
196 return error;
200 FT_LOCAL_DEF( FT_Error )
201 FTC_SNode_New( FTC_SNode *psnode,
202 FTC_GQuery gquery,
203 FTC_Cache cache )
205 FT_Memory memory = cache->memory;
206 FT_Error error;
207 FTC_SNode snode = NULL;
208 FT_UInt gindex = gquery->gindex;
209 FTC_Family family = gquery->family;
211 FTC_SFamilyClass clazz = FTC_CACHE__SFAMILY_CLASS( cache );
212 FT_UInt total;
215 total = clazz->family_get_count( family, cache->manager );
216 if ( total == 0 || gindex >= total )
218 error = FT_Err_Invalid_Argument;
219 goto Exit;
222 if ( !FT_NEW( snode ) )
224 FT_UInt count, start;
227 start = gindex - ( gindex % FTC_SBIT_ITEMS_PER_NODE );
228 count = total - start;
229 if ( count > FTC_SBIT_ITEMS_PER_NODE )
230 count = FTC_SBIT_ITEMS_PER_NODE;
232 FTC_GNode_Init( FTC_GNODE( snode ), start, family );
234 snode->count = count;
236 error = ftc_snode_load( snode,
237 cache->manager,
238 gindex,
239 NULL );
240 if ( error )
242 FTC_SNode_Free( snode, cache );
243 snode = NULL;
247 Exit:
248 *psnode = snode;
249 return error;
253 FT_LOCAL_DEF( FT_Error )
254 ftc_snode_new( FTC_Node *ftcpsnode,
255 FT_Pointer ftcgquery,
256 FTC_Cache cache )
258 FTC_SNode *psnode = (FTC_SNode*)ftcpsnode;
259 FTC_GQuery gquery = (FTC_GQuery)ftcgquery;
262 return FTC_SNode_New( psnode, gquery, cache );
266 FT_LOCAL_DEF( FT_ULong )
267 ftc_snode_weight( FTC_Node ftcsnode,
268 FTC_Cache cache )
270 FTC_SNode snode = (FTC_SNode)ftcsnode;
271 FT_UInt count = snode->count;
272 FTC_SBit sbit = snode->sbits;
273 FT_Int pitch;
274 FT_ULong size;
276 FT_UNUSED( cache );
279 FT_ASSERT( snode->count <= FTC_SBIT_ITEMS_PER_NODE );
281 /* the node itself */
282 size = sizeof ( *snode );
284 for ( ; count > 0; count--, sbit++ )
286 if ( sbit->buffer )
288 pitch = sbit->pitch;
289 if ( pitch < 0 )
290 pitch = -pitch;
292 /* add the size of a given glyph image */
293 size += pitch * sbit->height;
297 return size;
301 #if 0
303 FT_LOCAL_DEF( FT_ULong )
304 FTC_SNode_Weight( FTC_SNode snode )
306 return ftc_snode_weight( FTC_NODE( snode ), NULL );
309 #endif /* 0 */
312 FT_LOCAL_DEF( FT_Bool )
313 ftc_snode_compare( FTC_Node ftcsnode,
314 FT_Pointer ftcgquery,
315 FTC_Cache cache )
317 FTC_SNode snode = (FTC_SNode)ftcsnode;
318 FTC_GQuery gquery = (FTC_GQuery)ftcgquery;
319 FTC_GNode gnode = FTC_GNODE( snode );
320 FT_UInt gindex = gquery->gindex;
321 FT_Bool result;
324 result = FT_BOOL( gnode->family == gquery->family &&
325 (FT_UInt)( gindex - gnode->gindex ) < snode->count );
326 if ( result )
328 /* check if we need to load the glyph bitmap now */
329 FTC_SBit sbit = snode->sbits + ( gindex - gnode->gindex );
333 * The following code illustrates what to do when you want to
334 * perform operations that may fail within a lookup function.
336 * Here, we want to load a small bitmap on-demand; we thus
337 * need to call the `ftc_snode_load' function which may return
338 * a non-zero error code only when we are out of memory (OOM).
340 * The correct thing to do is to use @FTC_CACHE_TRYLOOP and
341 * @FTC_CACHE_TRYLOOP_END in order to implement a retry loop
342 * that is capable of flushing the cache incrementally when
343 * an OOM errors occur.
345 * However, we need to `lock' the node before this operation to
346 * prevent it from being flushed within the loop.
348 * When we exit the loop, we unlock the node, then check the `error'
349 * variable. If it is non-zero, this means that the cache was
350 * completely flushed and that no usable memory was found to load
351 * the bitmap.
353 * We then prefer to return a value of 0 (i.e., NO MATCH). This
354 * ensures that the caller will try to allocate a new node.
355 * This operation consequently _fail_ and the lookup function
356 * returns the appropriate OOM error code.
358 * Note that `buffer == NULL && width == 255' is a hack used to
359 * tag `unavailable' bitmaps in the array. We should never try
360 * to load these.
364 if ( sbit->buffer == NULL && sbit->width != 255 )
366 FT_ULong size;
367 FT_Error error;
370 ftcsnode->ref_count++; /* lock node to prevent flushing */
371 /* in retry loop */
373 FTC_CACHE_TRYLOOP( cache )
375 error = ftc_snode_load( snode, cache->manager, gindex, &size );
377 FTC_CACHE_TRYLOOP_END();
379 ftcsnode->ref_count--; /* unlock the node */
381 if ( error )
382 result = 0;
383 else
384 cache->manager->cur_weight += size;
388 return result;
392 FT_LOCAL_DEF( FT_Bool )
393 FTC_SNode_Compare( FTC_SNode snode,
394 FTC_GQuery gquery,
395 FTC_Cache cache )
397 return ftc_snode_compare( FTC_NODE( snode ), gquery, cache );
401 /* END */