1
/***************************************************************************/
5
/* FreeType sbits manager (body). */
7
/* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010 by */
8
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16
/***************************************************************************/
22
#include FT_INTERNAL_OBJECTS_H
23
#include FT_INTERNAL_DEBUG_H
30
#define FT_COMPONENT trace_cache
33
/*************************************************************************/
34
/*************************************************************************/
36
/***** SBIT CACHE NODES *****/
38
/*************************************************************************/
39
/*************************************************************************/
43
ftc_sbit_copy_bitmap( FTC_SBit sbit,
48
FT_Int pitch = bitmap->pitch;
55
size = (FT_ULong)( pitch * bitmap->rows );
57
if ( !FT_ALLOC( sbit->buffer, size ) )
58
FT_MEM_COPY( sbit->buffer, bitmap->buffer, size );
65
ftc_snode_free( FTC_Node ftcsnode,
68
FTC_SNode snode = (FTC_SNode)ftcsnode;
69
FTC_SBit sbit = snode->sbits;
70
FT_UInt count = snode->count;
71
FT_Memory memory = cache->memory;
74
for ( ; count > 0; sbit++, count-- )
75
FT_FREE( sbit->buffer );
77
FTC_GNode_Done( FTC_GNODE( snode ), cache );
84
FTC_SNode_Free( FTC_SNode snode,
87
ftc_snode_free( FTC_NODE( snode ), cache );
92
* This function tries to load a small bitmap within a given FTC_SNode.
93
* Note that it returns a non-zero error code _only_ in the case of
94
* out-of-memory condition. For all other errors (e.g., corresponding
95
* to a bad font file), this function will mark the sbit as `unavailable'
96
* and return a value of 0.
98
* You should also read the comment within the @ftc_snode_compare
99
* function below to see how out-of-memory is handled during a lookup.
102
ftc_snode_load( FTC_SNode snode,
108
FTC_GNode gnode = FTC_GNODE( snode );
109
FTC_Family family = gnode->family;
110
FT_Memory memory = manager->memory;
113
FTC_SFamilyClass clazz;
116
if ( (FT_UInt)(gindex - gnode->gindex) >= snode->count )
118
FT_ERROR(( "ftc_snode_load: invalid glyph index" ));
119
return FTC_Err_Invalid_Argument;
122
sbit = snode->sbits + ( gindex - gnode->gindex );
123
clazz = (FTC_SFamilyClass)family->clazz;
127
error = clazz->family_load_glyph( family, gindex, manager, &face );
133
FT_GlyphSlot slot = face->glyph;
134
FT_Bitmap* bitmap = &slot->bitmap;
135
FT_Pos xadvance, yadvance; /* FT_GlyphSlot->advance.{x|y} */
138
if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
140
FT_TRACE0(( "ftc_snode_load:"
141
" glyph loaded didn't return a bitmap\n" ));
145
/* Check that our values fit into 8-bit containers! */
146
/* If this is not the case, our bitmap is too large */
147
/* and we will leave it as `missing' with sbit.buffer = 0 */
149
#define CHECK_CHAR( d ) ( temp = (FT_Char)d, temp == d )
150
#define CHECK_BYTE( d ) ( temp = (FT_Byte)d, temp == d )
152
/* horizontal advance in pixels */
153
xadvance = ( slot->advance.x + 32 ) >> 6;
154
yadvance = ( slot->advance.y + 32 ) >> 6;
156
if ( !CHECK_BYTE( bitmap->rows ) ||
157
!CHECK_BYTE( bitmap->width ) ||
158
!CHECK_CHAR( bitmap->pitch ) ||
159
!CHECK_CHAR( slot->bitmap_left ) ||
160
!CHECK_CHAR( slot->bitmap_top ) ||
161
!CHECK_CHAR( xadvance ) ||
162
!CHECK_CHAR( yadvance ) )
164
FT_TRACE2(( "ftc_snode_load:"
165
" glyph too large for small bitmap cache\n"));
169
sbit->width = (FT_Byte)bitmap->width;
170
sbit->height = (FT_Byte)bitmap->rows;
171
sbit->pitch = (FT_Char)bitmap->pitch;
172
sbit->left = (FT_Char)slot->bitmap_left;
173
sbit->top = (FT_Char)slot->bitmap_top;
174
sbit->xadvance = (FT_Char)xadvance;
175
sbit->yadvance = (FT_Char)yadvance;
176
sbit->format = (FT_Byte)bitmap->pixel_mode;
177
sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1);
179
/* copy the bitmap into a new buffer -- ignore error */
180
error = ftc_sbit_copy_bitmap( sbit, bitmap, memory );
182
/* now, compute size */
184
*asize = FT_ABS( sbit->pitch ) * sbit->height;
186
} /* glyph loading successful */
188
/* ignore the errors that might have occurred -- */
189
/* we mark unloaded glyphs with `sbit.buffer == 0' */
190
/* and `width == 255', `height == 0' */
192
if ( error && error != FTC_Err_Out_Of_Memory )
207
FT_LOCAL_DEF( FT_Error )
208
FTC_SNode_New( FTC_SNode *psnode,
212
FT_Memory memory = cache->memory;
214
FTC_SNode snode = NULL;
215
FT_UInt gindex = gquery->gindex;
216
FTC_Family family = gquery->family;
218
FTC_SFamilyClass clazz = FTC_CACHE__SFAMILY_CLASS( cache );
222
total = clazz->family_get_count( family, cache->manager );
223
if ( total == 0 || gindex >= total )
225
error = FTC_Err_Invalid_Argument;
229
if ( !FT_NEW( snode ) )
231
FT_UInt count, start;
234
start = gindex - ( gindex % FTC_SBIT_ITEMS_PER_NODE );
235
count = total - start;
236
if ( count > FTC_SBIT_ITEMS_PER_NODE )
237
count = FTC_SBIT_ITEMS_PER_NODE;
239
FTC_GNode_Init( FTC_GNODE( snode ), start, family );
241
snode->count = count;
243
error = ftc_snode_load( snode,
249
FTC_SNode_Free( snode, cache );
260
FT_LOCAL_DEF( FT_Error )
261
ftc_snode_new( FTC_Node *ftcpsnode,
262
FT_Pointer ftcgquery,
265
FTC_SNode *psnode = (FTC_SNode*)ftcpsnode;
266
FTC_GQuery gquery = (FTC_GQuery)ftcgquery;
269
return FTC_SNode_New( psnode, gquery, cache );
273
FT_LOCAL_DEF( FT_Offset )
274
ftc_snode_weight( FTC_Node ftcsnode,
277
FTC_SNode snode = (FTC_SNode)ftcsnode;
278
FT_UInt count = snode->count;
279
FTC_SBit sbit = snode->sbits;
286
FT_ASSERT( snode->count <= FTC_SBIT_ITEMS_PER_NODE );
288
/* the node itself */
289
size = sizeof ( *snode );
291
for ( ; count > 0; count--, sbit++ )
299
/* add the size of a given glyph image */
300
size += pitch * sbit->height;
310
FT_LOCAL_DEF( FT_Offset )
311
FTC_SNode_Weight( FTC_SNode snode )
313
return ftc_snode_weight( FTC_NODE( snode ), NULL );
319
FT_LOCAL_DEF( FT_Bool )
320
ftc_snode_compare( FTC_Node ftcsnode,
321
FT_Pointer ftcgquery,
324
FTC_SNode snode = (FTC_SNode)ftcsnode;
325
FTC_GQuery gquery = (FTC_GQuery)ftcgquery;
326
FTC_GNode gnode = FTC_GNODE( snode );
327
FT_UInt gindex = gquery->gindex;
331
result = FT_BOOL( gnode->family == gquery->family &&
332
(FT_UInt)( gindex - gnode->gindex ) < snode->count );
335
/* check if we need to load the glyph bitmap now */
336
FTC_SBit sbit = snode->sbits + ( gindex - gnode->gindex );
340
* The following code illustrates what to do when you want to
341
* perform operations that may fail within a lookup function.
343
* Here, we want to load a small bitmap on-demand; we thus
344
* need to call the `ftc_snode_load' function which may return
345
* a non-zero error code only when we are out of memory (OOM).
347
* The correct thing to do is to use @FTC_CACHE_TRYLOOP and
348
* @FTC_CACHE_TRYLOOP_END in order to implement a retry loop
349
* that is capable of flushing the cache incrementally when
350
* an OOM errors occur.
352
* However, we need to `lock' the node before this operation to
353
* prevent it from being flushed within the loop.
355
* When we exit the loop, we unlock the node, then check the `error'
356
* variable. If it is non-zero, this means that the cache was
357
* completely flushed and that no usable memory was found to load
360
* We then prefer to return a value of 0 (i.e., NO MATCH). This
361
* ensures that the caller will try to allocate a new node.
362
* This operation consequently _fail_ and the lookup function
363
* returns the appropriate OOM error code.
365
* Note that `buffer == NULL && width == 255' is a hack used to
366
* tag `unavailable' bitmaps in the array. We should never try
371
if ( sbit->buffer == NULL && sbit->width != 255 )
377
ftcsnode->ref_count++; /* lock node to prevent flushing */
380
FTC_CACHE_TRYLOOP( cache )
382
error = ftc_snode_load( snode, cache->manager, gindex, &size );
384
FTC_CACHE_TRYLOOP_END();
386
ftcsnode->ref_count--; /* unlock the node */
391
cache->manager->cur_weight += size;
399
FT_LOCAL_DEF( FT_Bool )
400
FTC_SNode_Compare( FTC_SNode snode,
404
return ftc_snode_compare( FTC_NODE( snode ), gquery, cache );