1/****************************************************************************
2 *
3 * ftcbasic.c
4 *
5 * The FreeType basic cache interface (body).
6 *
7 * Copyright (C) 2003-2023 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/internal/ftobjs.h>
20#include <freetype/internal/ftdebug.h>
21#include <freetype/ftcache.h>
22#include "ftcglyph.h"
23#include "ftcimage.h"
24#include "ftcsbits.h"
25
26#include "ftccback.h"
27#include "ftcerror.h"
28
29#undef FT_COMPONENT
30#define FT_COMPONENT cache
31
32
33 /*
34 * Basic Families
35 *
36 */
37 typedef struct FTC_BasicAttrRec_
38 {
39 FTC_ScalerRec scaler;
40 FT_UInt load_flags;
41
42 } FTC_BasicAttrRec, *FTC_BasicAttrs;
43
44#define FTC_BASIC_ATTR_COMPARE( a, b ) \
45 FT_BOOL( FTC_SCALER_COMPARE( &(a)->scaler, &(b)->scaler ) && \
46 (a)->load_flags == (b)->load_flags )
47
48#define FTC_BASIC_ATTR_HASH( a ) \
49 ( FTC_SCALER_HASH( &(a)->scaler ) + 31 * (a)->load_flags )
50
51
52 typedef struct FTC_BasicQueryRec_
53 {
54 FTC_GQueryRec gquery;
55 FTC_BasicAttrRec attrs;
56
57 } FTC_BasicQueryRec, *FTC_BasicQuery;
58
59
60 typedef struct FTC_BasicFamilyRec_
61 {
62 FTC_FamilyRec family;
63 FTC_BasicAttrRec attrs;
64
65 } FTC_BasicFamilyRec, *FTC_BasicFamily;
66
67
68 FT_CALLBACK_DEF( FT_Bool )
69 ftc_basic_family_compare( FTC_MruNode ftcfamily,
70 FT_Pointer ftcquery )
71 {
72 FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily;
73 FTC_BasicQuery query = (FTC_BasicQuery)ftcquery;
74
75
76 return FTC_BASIC_ATTR_COMPARE( &family->attrs, &query->attrs );
77 }
78
79
80 FT_CALLBACK_DEF( FT_Error )
81 ftc_basic_family_init( FTC_MruNode ftcfamily,
82 FT_Pointer ftcquery,
83 FT_Pointer ftccache )
84 {
85 FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily;
86 FTC_BasicQuery query = (FTC_BasicQuery)ftcquery;
87 FTC_Cache cache = (FTC_Cache)ftccache;
88
89
90 FTC_Family_Init( FTC_FAMILY( family ), cache );
91 family->attrs = query->attrs;
92 return 0;
93 }
94
95
96 FT_CALLBACK_DEF( FT_UInt )
97 ftc_basic_family_get_count( FTC_Family ftcfamily,
98 FTC_Manager manager )
99 {
100 FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily;
101 FT_Error error;
102 FT_Face face;
103 FT_UInt result = 0;
104
105
106 error = FTC_Manager_LookupFace( manager, family->attrs.scaler.face_id,
107 &face );
108
109 if ( error || !face )
110 return result;
111
112#ifdef FT_DEBUG_LEVEL_TRACE
113 if ( (FT_ULong)face->num_glyphs > FT_UINT_MAX || 0 > face->num_glyphs )
114 {
115 FT_TRACE1(( "ftc_basic_family_get_count:"
116 " the number of glyphs in this face is %ld,\n",
117 face->num_glyphs ));
118 FT_TRACE1(( " "
119 " which is too much and thus truncated\n" ));
120 }
121#endif
122
123 result = (FT_UInt)face->num_glyphs;
124
125 return result;
126 }
127
128
129 FT_CALLBACK_DEF( FT_Error )
130 ftc_basic_family_load_bitmap( FTC_Family ftcfamily,
131 FT_UInt gindex,
132 FTC_Manager manager,
133 FT_Face *aface )
134 {
135 FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily;
136 FT_Error error;
137 FT_Size size;
138
139
140 error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size );
141 if ( !error )
142 {
143 FT_Face face = size->face;
144
145
146 error = FT_Load_Glyph(
147 face,
148 gindex,
149 (FT_Int)family->attrs.load_flags | FT_LOAD_RENDER );
150 if ( !error )
151 *aface = face;
152 }
153
154 return error;
155 }
156
157
158 FT_CALLBACK_DEF( FT_Error )
159 ftc_basic_family_load_glyph( FTC_Family ftcfamily,
160 FT_UInt gindex,
161 FTC_Cache cache,
162 FT_Glyph *aglyph )
163 {
164 FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily;
165 FT_Error error;
166 FTC_Scaler scaler = &family->attrs.scaler;
167 FT_Face face;
168 FT_Size size;
169
170
171 /* we will now load the glyph image */
172 error = FTC_Manager_LookupSize( cache->manager,
173 scaler,
174 &size );
175 if ( !error )
176 {
177 face = size->face;
178
179 error = FT_Load_Glyph( face,
180 gindex,
181 (FT_Int)family->attrs.load_flags );
182 if ( !error )
183 {
184 if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP ||
185 face->glyph->format == FT_GLYPH_FORMAT_OUTLINE ||
186 face->glyph->format == FT_GLYPH_FORMAT_SVG )
187 {
188 /* ok, copy it */
189 FT_Glyph glyph;
190
191
192 error = FT_Get_Glyph( face->glyph, &glyph );
193 if ( !error )
194 {
195 *aglyph = glyph;
196 goto Exit;
197 }
198 }
199 else
200 error = FT_THROW( Invalid_Argument );
201 }
202 }
203
204 Exit:
205 return error;
206 }
207
208
209 FT_CALLBACK_DEF( FT_Bool )
210 ftc_basic_gnode_compare_faceid( FTC_Node ftcgnode,
211 FT_Pointer ftcface_id,
212 FTC_Cache cache,
213 FT_Bool* list_changed )
214 {
215 FTC_GNode gnode = (FTC_GNode)ftcgnode;
216 FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
217 FTC_BasicFamily family = (FTC_BasicFamily)gnode->family;
218 FT_Bool result;
219
220
221 if ( list_changed )
222 *list_changed = FALSE;
223 result = FT_BOOL( family->attrs.scaler.face_id == face_id );
224 if ( result )
225 {
226 /* we must call this function to avoid this node from appearing
227 * in later lookups with the same face_id!
228 */
229 FTC_GNode_UnselectFamily( gnode, cache );
230 }
231 return result;
232 }
233
234
235 /*
236 *
237 * basic image cache
238 *
239 */
240
241 static
242 const FTC_IFamilyClassRec ftc_basic_image_family_class =
243 {
244 {
245 sizeof ( FTC_BasicFamilyRec ),
246
247 ftc_basic_family_compare, /* FTC_MruNode_CompareFunc node_compare */
248 ftc_basic_family_init, /* FTC_MruNode_InitFunc node_init */
249 NULL, /* FTC_MruNode_ResetFunc node_reset */
250 NULL /* FTC_MruNode_DoneFunc node_done */
251 },
252
253 ftc_basic_family_load_glyph /* FTC_IFamily_LoadGlyphFunc family_load_glyph */
254 };
255
256
257 static
258 const FTC_GCacheClassRec ftc_basic_image_cache_class =
259 {
260 {
261 ftc_inode_new, /* FTC_Node_NewFunc node_new */
262 ftc_inode_weight, /* FTC_Node_WeightFunc node_weight */
263 ftc_gnode_compare, /* FTC_Node_CompareFunc node_compare */
264 ftc_basic_gnode_compare_faceid, /* FTC_Node_CompareFunc node_remove_faceid */
265 ftc_inode_free, /* FTC_Node_FreeFunc node_free */
266
267 sizeof ( FTC_GCacheRec ),
268 ftc_gcache_init, /* FTC_Cache_InitFunc cache_init */
269 ftc_gcache_done /* FTC_Cache_DoneFunc cache_done */
270 },
271
272 (FTC_MruListClass)&ftc_basic_image_family_class
273 };
274
275
276 /* documentation is in ftcache.h */
277
278 FT_EXPORT_DEF( FT_Error )
279 FTC_ImageCache_New( FTC_Manager manager,
280 FTC_ImageCache *acache )
281 {
282 return FTC_GCache_New( manager, &ftc_basic_image_cache_class,
283 (FTC_GCache*)acache );
284 }
285
286
287 /* documentation is in ftcache.h */
288
289 FT_EXPORT_DEF( FT_Error )
290 FTC_ImageCache_Lookup( FTC_ImageCache cache,
291 FTC_ImageType type,
292 FT_UInt gindex,
293 FT_Glyph *aglyph,
294 FTC_Node *anode )
295 {
296 FTC_BasicQueryRec query;
297 FTC_Node node = 0; /* make compiler happy */
298 FT_Error error;
299 FT_Offset hash;
300
301
302 /* some argument checks are delayed to `FTC_Cache_Lookup' */
303 if ( !aglyph )
304 {
305 error = FT_THROW( Invalid_Argument );
306 goto Exit;
307 }
308
309 *aglyph = NULL;
310 if ( anode )
311 *anode = NULL;
312
313 /*
314 * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt',
315 * but public `FT_ImageType->flags' is of type `FT_Int32'.
316 *
317 * On 16bit systems, higher bits of type->flags cannot be handled.
318 */
319#if 0xFFFFFFFFUL > FT_UINT_MAX
320 if ( (type->flags & (FT_ULong)FT_UINT_MAX) )
321 FT_TRACE1(( "FTC_ImageCache_Lookup:"
322 " higher bits in load_flags 0x%lx are dropped\n",
323 (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) ));
324#endif
325
326 query.attrs.scaler.face_id = type->face_id;
327 query.attrs.scaler.width = type->width;
328 query.attrs.scaler.height = type->height;
329 query.attrs.load_flags = (FT_UInt)type->flags;
330
331 query.attrs.scaler.pixel = 1;
332 query.attrs.scaler.x_res = 0; /* make compilers happy */
333 query.attrs.scaler.y_res = 0;
334
335 hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
336
337#if 1 /* inlining is about 50% faster! */
338 FTC_GCACHE_LOOKUP_CMP( cache,
339 ftc_basic_family_compare,
340 ftc_gnode_compare,
341 hash, gindex,
342 &query,
343 node,
344 error );
345#else
346 error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
347 hash, gindex,
348 FTC_GQUERY( &query ),
349 &node );
350#endif
351 if ( !error )
352 {
353 *aglyph = FTC_INODE( node )->glyph;
354
355 if ( anode )
356 {
357 *anode = node;
358 node->ref_count++;
359 }
360 }
361
362 Exit:
363 return error;
364 }
365
366
367 /* documentation is in ftcache.h */
368
369 FT_EXPORT_DEF( FT_Error )
370 FTC_ImageCache_LookupScaler( FTC_ImageCache cache,
371 FTC_Scaler scaler,
372 FT_ULong load_flags,
373 FT_UInt gindex,
374 FT_Glyph *aglyph,
375 FTC_Node *anode )
376 {
377 FTC_BasicQueryRec query;
378 FTC_Node node = 0; /* make compiler happy */
379 FT_Error error;
380 FT_Offset hash;
381
382
383 /* some argument checks are delayed to `FTC_Cache_Lookup' */
384 if ( !aglyph || !scaler )
385 {
386 error = FT_THROW( Invalid_Argument );
387 goto Exit;
388 }
389
390 *aglyph = NULL;
391 if ( anode )
392 *anode = NULL;
393
394 /*
395 * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt',
396 * but public `FT_Face->face_flags' is of type `FT_Long'.
397 *
398 * On long > int systems, higher bits of load_flags cannot be handled.
399 */
400#if FT_ULONG_MAX > FT_UINT_MAX
401 if ( load_flags > FT_UINT_MAX )
402 FT_TRACE1(( "FTC_ImageCache_LookupScaler:"
403 " higher bits in load_flags 0x%lx are dropped\n",
404 load_flags & ~((FT_ULong)FT_UINT_MAX) ));
405#endif
406
407 query.attrs.scaler = scaler[0];
408 query.attrs.load_flags = (FT_UInt)load_flags;
409
410 hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
411
412 FTC_GCACHE_LOOKUP_CMP( cache,
413 ftc_basic_family_compare,
414 ftc_gnode_compare,
415 hash, gindex,
416 &query,
417 node,
418 error );
419 if ( !error )
420 {
421 *aglyph = FTC_INODE( node )->glyph;
422
423 if ( anode )
424 {
425 *anode = node;
426 node->ref_count++;
427 }
428 }
429
430 Exit:
431 return error;
432 }
433
434
435 /*
436 *
437 * basic small bitmap cache
438 *
439 */
440
441 static
442 const FTC_SFamilyClassRec ftc_basic_sbit_family_class =
443 {
444 {
445 sizeof ( FTC_BasicFamilyRec ),
446 ftc_basic_family_compare, /* FTC_MruNode_CompareFunc node_compare */
447 ftc_basic_family_init, /* FTC_MruNode_InitFunc node_init */
448 NULL, /* FTC_MruNode_ResetFunc node_reset */
449 NULL /* FTC_MruNode_DoneFunc node_done */
450 },
451
452 ftc_basic_family_get_count,
453 ftc_basic_family_load_bitmap
454 };
455
456
457 static
458 const FTC_GCacheClassRec ftc_basic_sbit_cache_class =
459 {
460 {
461 ftc_snode_new, /* FTC_Node_NewFunc node_new */
462 ftc_snode_weight, /* FTC_Node_WeightFunc node_weight */
463 ftc_snode_compare, /* FTC_Node_CompareFunc node_compare */
464 ftc_basic_gnode_compare_faceid, /* FTC_Node_CompareFunc node_remove_faceid */
465 ftc_snode_free, /* FTC_Node_FreeFunc node_free */
466
467 sizeof ( FTC_GCacheRec ),
468 ftc_gcache_init, /* FTC_Cache_InitFunc cache_init */
469 ftc_gcache_done /* FTC_Cache_DoneFunc cache_done */
470 },
471
472 (FTC_MruListClass)&ftc_basic_sbit_family_class
473 };
474
475
476 /* documentation is in ftcache.h */
477
478 FT_EXPORT_DEF( FT_Error )
479 FTC_SBitCache_New( FTC_Manager manager,
480 FTC_SBitCache *acache )
481 {
482 return FTC_GCache_New( manager, &ftc_basic_sbit_cache_class,
483 (FTC_GCache*)acache );
484 }
485
486
487 /* documentation is in ftcache.h */
488
489 FT_EXPORT_DEF( FT_Error )
490 FTC_SBitCache_Lookup( FTC_SBitCache cache,
491 FTC_ImageType type,
492 FT_UInt gindex,
493 FTC_SBit *ansbit,
494 FTC_Node *anode )
495 {
496 FT_Error error;
497 FTC_BasicQueryRec query;
498 FTC_Node node = 0; /* make compiler happy */
499 FT_Offset hash;
500
501
502 if ( anode )
503 *anode = NULL;
504
505 /* other argument checks delayed to `FTC_Cache_Lookup' */
506 if ( !ansbit )
507 return FT_THROW( Invalid_Argument );
508
509 *ansbit = NULL;
510
511 /*
512 * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt',
513 * but public `FT_ImageType->flags' is of type `FT_Int32'.
514 *
515 * On 16bit systems, higher bits of type->flags cannot be handled.
516 */
517#if 0xFFFFFFFFUL > FT_UINT_MAX
518 if ( (type->flags & (FT_ULong)FT_UINT_MAX) )
519 FT_TRACE1(( "FTC_ImageCache_Lookup:"
520 " higher bits in load_flags 0x%lx are dropped\n",
521 (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) ));
522#endif
523
524 query.attrs.scaler.face_id = type->face_id;
525 query.attrs.scaler.width = type->width;
526 query.attrs.scaler.height = type->height;
527 query.attrs.load_flags = (FT_UInt)type->flags;
528
529 query.attrs.scaler.pixel = 1;
530 query.attrs.scaler.x_res = 0; /* make compilers happy */
531 query.attrs.scaler.y_res = 0;
532
533 /* beware, the hash must be the same for all glyph ranges! */
534 hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
535 gindex / FTC_SBIT_ITEMS_PER_NODE;
536
537#if 1 /* inlining is about 50% faster! */
538 FTC_GCACHE_LOOKUP_CMP( cache,
539 ftc_basic_family_compare,
540 ftc_snode_compare,
541 hash, gindex,
542 &query,
543 node,
544 error );
545#else
546 error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
547 hash,
548 gindex,
549 FTC_GQUERY( &query ),
550 &node );
551#endif
552 if ( error )
553 goto Exit;
554
555 *ansbit = FTC_SNODE( node )->sbits +
556 ( gindex - FTC_GNODE( node )->gindex );
557
558 if ( anode )
559 {
560 *anode = node;
561 node->ref_count++;
562 }
563
564 Exit:
565 return error;
566 }
567
568
569 /* documentation is in ftcache.h */
570
571 FT_EXPORT_DEF( FT_Error )
572 FTC_SBitCache_LookupScaler( FTC_SBitCache cache,
573 FTC_Scaler scaler,
574 FT_ULong load_flags,
575 FT_UInt gindex,
576 FTC_SBit *ansbit,
577 FTC_Node *anode )
578 {
579 FT_Error error;
580 FTC_BasicQueryRec query;
581 FTC_Node node = 0; /* make compiler happy */
582 FT_Offset hash;
583
584
585 if ( anode )
586 *anode = NULL;
587
588 /* other argument checks delayed to `FTC_Cache_Lookup' */
589 if ( !ansbit || !scaler )
590 return FT_THROW( Invalid_Argument );
591
592 *ansbit = NULL;
593
594 /*
595 * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt',
596 * but public `FT_Face->face_flags' is of type `FT_Long'.
597 *
598 * On long > int systems, higher bits of load_flags cannot be handled.
599 */
600#if FT_ULONG_MAX > FT_UINT_MAX
601 if ( load_flags > FT_UINT_MAX )
602 FT_TRACE1(( "FTC_ImageCache_LookupScaler:"
603 " higher bits in load_flags 0x%lx are dropped\n",
604 load_flags & ~((FT_ULong)FT_UINT_MAX) ));
605#endif
606
607 query.attrs.scaler = scaler[0];
608 query.attrs.load_flags = (FT_UInt)load_flags;
609
610 /* beware, the hash must be the same for all glyph ranges! */
611 hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
612 gindex / FTC_SBIT_ITEMS_PER_NODE;
613
614 FTC_GCACHE_LOOKUP_CMP( cache,
615 ftc_basic_family_compare,
616 ftc_snode_compare,
617 hash, gindex,
618 &query,
619 node,
620 error );
621 if ( error )
622 goto Exit;
623
624 *ansbit = FTC_SNODE( node )->sbits +
625 ( gindex - FTC_GNODE( node )->gindex );
626
627 if ( anode )
628 {
629 *anode = node;
630 node->ref_count++;
631 }
632
633 Exit:
634 return error;
635 }
636
637
638/* END */
639