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