1 /***************************************************************************/
5 /* FreeType sbits manager (body). */
7 /* Copyright 2000-2018 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
;
59 if ( !FT_ALLOC( sbit
->buffer
, size
) )
60 FT_MEM_COPY( sbit
->buffer
, bitmap
->buffer
, size
);
67 ftc_snode_free( FTC_Node ftcsnode
,
70 FTC_SNode snode
= (FTC_SNode
)ftcsnode
;
71 FTC_SBit sbit
= snode
->sbits
;
72 FT_UInt count
= snode
->count
;
73 FT_Memory memory
= cache
->memory
;
76 for ( ; count
> 0; sbit
++, count
-- )
77 FT_FREE( sbit
->buffer
);
79 FTC_GNode_Done( FTC_GNODE( snode
), cache
);
86 FTC_SNode_Free( FTC_SNode snode
,
89 ftc_snode_free( FTC_NODE( snode
), cache
);
94 * This function tries to load a small bitmap within a given FTC_SNode.
95 * Note that it returns a non-zero error code _only_ in the case of
96 * out-of-memory condition. For all other errors (e.g., corresponding
97 * to a bad font file), this function will mark the sbit as `unavailable'
98 * and return a value of 0.
100 * You should also read the comment within the @ftc_snode_compare
101 * function below to see how out-of-memory is handled during a lookup.
104 ftc_snode_load( FTC_SNode snode
,
110 FTC_GNode gnode
= FTC_GNODE( snode
);
111 FTC_Family family
= gnode
->family
;
112 FT_Memory memory
= manager
->memory
;
115 FTC_SFamilyClass clazz
;
118 if ( (FT_UInt
)(gindex
- gnode
->gindex
) >= snode
->count
)
120 FT_ERROR(( "ftc_snode_load: invalid glyph index" ));
121 return FT_THROW( Invalid_Argument
);
124 sbit
= snode
->sbits
+ ( gindex
- gnode
->gindex
);
125 clazz
= (FTC_SFamilyClass
)family
->clazz
;
129 error
= clazz
->family_load_glyph( family
, gindex
, manager
, &face
);
135 FT_GlyphSlot slot
= face
->glyph
;
136 FT_Bitmap
* bitmap
= &slot
->bitmap
;
137 FT_Pos xadvance
, yadvance
; /* FT_GlyphSlot->advance.{x|y} */
140 if ( slot
->format
!= FT_GLYPH_FORMAT_BITMAP
)
142 FT_TRACE0(( "ftc_snode_load:"
143 " glyph loaded didn't return a bitmap\n" ));
147 /* Check whether our values fit into 8-bit containers! */
148 /* If this is not the case, our bitmap is too large */
149 /* and we will leave it as `missing' with sbit.buffer = 0 */
151 #define CHECK_CHAR( d ) ( temp = (FT_Char)d, (FT_Int) temp == (FT_Int) d )
152 #define CHECK_BYTE( d ) ( temp = (FT_Byte)d, (FT_UInt)temp == (FT_UInt)d )
154 /* horizontal advance in pixels */
155 xadvance
= ( slot
->advance
.x
+ 32 ) >> 6;
156 yadvance
= ( slot
->advance
.y
+ 32 ) >> 6;
158 if ( !CHECK_BYTE( bitmap
->rows
) ||
159 !CHECK_BYTE( bitmap
->width
) ||
160 !CHECK_CHAR( bitmap
->pitch
) ||
161 !CHECK_CHAR( slot
->bitmap_left
) ||
162 !CHECK_CHAR( slot
->bitmap_top
) ||
163 !CHECK_CHAR( xadvance
) ||
164 !CHECK_CHAR( yadvance
) )
166 FT_TRACE2(( "ftc_snode_load:"
167 " glyph too large for small bitmap cache\n"));
171 sbit
->width
= (FT_Byte
)bitmap
->width
;
172 sbit
->height
= (FT_Byte
)bitmap
->rows
;
173 sbit
->pitch
= (FT_Char
)bitmap
->pitch
;
174 sbit
->left
= (FT_Char
)slot
->bitmap_left
;
175 sbit
->top
= (FT_Char
)slot
->bitmap_top
;
176 sbit
->xadvance
= (FT_Char
)xadvance
;
177 sbit
->yadvance
= (FT_Char
)yadvance
;
178 sbit
->format
= (FT_Byte
)bitmap
->pixel_mode
;
179 sbit
->max_grays
= (FT_Byte
)(bitmap
->num_grays
- 1);
181 /* copy the bitmap into a new buffer -- ignore error */
182 error
= ftc_sbit_copy_bitmap( sbit
, bitmap
, memory
);
184 /* now, compute size */
186 *asize
= (FT_ULong
)FT_ABS( sbit
->pitch
) * sbit
->height
;
188 } /* glyph loading successful */
190 /* ignore the errors that might have occurred -- */
191 /* we mark unloaded glyphs with `sbit.buffer == 0' */
192 /* and `width == 255', `height == 0' */
194 if ( error
&& FT_ERR_NEQ( error
, Out_Of_Memory
) )
209 FT_LOCAL_DEF( FT_Error
)
210 FTC_SNode_New( FTC_SNode
*psnode
,
214 FT_Memory memory
= cache
->memory
;
216 FTC_SNode snode
= NULL
;
217 FT_UInt gindex
= gquery
->gindex
;
218 FTC_Family family
= gquery
->family
;
220 FTC_SFamilyClass clazz
= FTC_CACHE_SFAMILY_CLASS( cache
);
225 total
= clazz
->family_get_count( family
, cache
->manager
);
226 if ( total
== 0 || gindex
>= total
)
228 error
= FT_THROW( Invalid_Argument
);
232 if ( !FT_NEW( snode
) )
234 FT_UInt count
, start
;
237 start
= gindex
- ( gindex
% FTC_SBIT_ITEMS_PER_NODE
);
238 count
= total
- start
;
239 if ( count
> FTC_SBIT_ITEMS_PER_NODE
)
240 count
= FTC_SBIT_ITEMS_PER_NODE
;
242 FTC_GNode_Init( FTC_GNODE( snode
), start
, family
);
244 snode
->count
= count
;
245 for ( node_count
= 0; node_count
< count
; node_count
++ )
247 snode
->sbits
[node_count
].width
= 255;
250 error
= ftc_snode_load( snode
,
256 FTC_SNode_Free( snode
, cache
);
267 FT_LOCAL_DEF( FT_Error
)
268 ftc_snode_new( FTC_Node
*ftcpsnode
,
269 FT_Pointer ftcgquery
,
272 FTC_SNode
*psnode
= (FTC_SNode
*)ftcpsnode
;
273 FTC_GQuery gquery
= (FTC_GQuery
)ftcgquery
;
276 return FTC_SNode_New( psnode
, gquery
, cache
);
280 FT_LOCAL_DEF( FT_Offset
)
281 ftc_snode_weight( FTC_Node ftcsnode
,
284 FTC_SNode snode
= (FTC_SNode
)ftcsnode
;
285 FT_UInt count
= snode
->count
;
286 FTC_SBit sbit
= snode
->sbits
;
293 FT_ASSERT( snode
->count
<= FTC_SBIT_ITEMS_PER_NODE
);
295 /* the node itself */
296 size
= sizeof ( *snode
);
298 for ( ; count
> 0; count
--, sbit
++ )
306 /* add the size of a given glyph image */
307 size
+= (FT_Offset
)pitch
* sbit
->height
;
317 FT_LOCAL_DEF( FT_Offset
)
318 FTC_SNode_Weight( FTC_SNode snode
)
320 return ftc_snode_weight( FTC_NODE( snode
), NULL
);
326 FT_LOCAL_DEF( FT_Bool
)
327 ftc_snode_compare( FTC_Node ftcsnode
,
328 FT_Pointer ftcgquery
,
330 FT_Bool
* list_changed
)
332 FTC_SNode snode
= (FTC_SNode
)ftcsnode
;
333 FTC_GQuery gquery
= (FTC_GQuery
)ftcgquery
;
334 FTC_GNode gnode
= FTC_GNODE( snode
);
335 FT_UInt gindex
= gquery
->gindex
;
340 *list_changed
= FALSE
;
341 result
= FT_BOOL( gnode
->family
== gquery
->family
&&
342 (FT_UInt
)( gindex
- gnode
->gindex
) < snode
->count
);
345 /* check if we need to load the glyph bitmap now */
346 FTC_SBit sbit
= snode
->sbits
+ ( gindex
- gnode
->gindex
);
350 * The following code illustrates what to do when you want to
351 * perform operations that may fail within a lookup function.
353 * Here, we want to load a small bitmap on-demand; we thus
354 * need to call the `ftc_snode_load' function which may return
355 * a non-zero error code only when we are out of memory (OOM).
357 * The correct thing to do is to use @FTC_CACHE_TRYLOOP and
358 * @FTC_CACHE_TRYLOOP_END in order to implement a retry loop
359 * that is capable of flushing the cache incrementally when
360 * an OOM errors occur.
362 * However, we need to `lock' the node before this operation to
363 * prevent it from being flushed within the loop.
365 * When we exit the loop, we unlock the node, then check the `error'
366 * variable. If it is non-zero, this means that the cache was
367 * completely flushed and that no usable memory was found to load
370 * We then prefer to return a value of 0 (i.e., NO MATCH). This
371 * ensures that the caller will try to allocate a new node.
372 * This operation consequently _fail_ and the lookup function
373 * returns the appropriate OOM error code.
375 * Note that `buffer == NULL && width == 255' is a hack used to
376 * tag `unavailable' bitmaps in the array. We should never try
381 if ( !sbit
->buffer
&& sbit
->width
== 255 )
387 ftcsnode
->ref_count
++; /* lock node to prevent flushing */
390 FTC_CACHE_TRYLOOP( cache
)
392 error
= ftc_snode_load( snode
, cache
->manager
, gindex
, &size
);
394 FTC_CACHE_TRYLOOP_END( list_changed
);
396 ftcsnode
->ref_count
--; /* unlock the node */
401 cache
->manager
->cur_weight
+= size
;
411 FT_LOCAL_DEF( FT_Bool
)
412 FTC_SNode_Compare( FTC_SNode snode
,
415 FT_Bool
* list_changed
)
417 return ftc_snode_compare( FTC_NODE( snode
), gquery
,
418 cache
, list_changed
);