1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftcbasic.c                                                             */
4 /*                                                                         */
5 /*    The FreeType basic cache interface (body).                           */
6 /*                                                                         */
7 /*  Copyright 2003-2015 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 <ft2build.h>
20 #include FT_INTERNAL_OBJECTS_H
21 #include FT_INTERNAL_DEBUG_H
22 #include FT_CACHE_H
23 #include "ftcglyph.h"
24 #include "ftcimage.h"
25 #include "ftcsbits.h"
26 
27 #include "ftccback.h"
28 #include "ftcerror.h"
29 
30 #define FT_COMPONENT  trace_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 )
ftc_basic_family_compare(FTC_MruNode ftcfamily,FT_Pointer ftcquery)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 )
ftc_basic_family_init(FTC_MruNode ftcfamily,FT_Pointer ftcquery,FT_Pointer ftccache)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 )
ftc_basic_family_get_count(FTC_Family ftcfamily,FTC_Manager manager)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     if ( (FT_ULong)face->num_glyphs > FT_UINT_MAX || 0 > face->num_glyphs )
113       FT_TRACE1(( "ftc_basic_family_get_count:"
114                   " too large number of glyphs in this face, truncated\n",
115                   face->num_glyphs ));
116 
117     if ( !error )
118       result = (FT_UInt)face->num_glyphs;
119 
120     return result;
121   }
122 
123 
124   FT_CALLBACK_DEF( FT_Error )
ftc_basic_family_load_bitmap(FTC_Family ftcfamily,FT_UInt gindex,FTC_Manager manager,FT_Face * aface)125   ftc_basic_family_load_bitmap( FTC_Family   ftcfamily,
126                                 FT_UInt      gindex,
127                                 FTC_Manager  manager,
128                                 FT_Face     *aface )
129   {
130     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
131     FT_Error         error;
132     FT_Size          size;
133 
134 
135     error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size );
136     if ( !error )
137     {
138       FT_Face  face = size->face;
139 
140 
141       error = FT_Load_Glyph(
142                 face,
143                 gindex,
144                 (FT_Int)family->attrs.load_flags | FT_LOAD_RENDER );
145       if ( !error )
146         *aface = face;
147     }
148 
149     return error;
150   }
151 
152 
153   FT_CALLBACK_DEF( FT_Error )
ftc_basic_family_load_glyph(FTC_Family ftcfamily,FT_UInt gindex,FTC_Cache cache,FT_Glyph * aglyph)154   ftc_basic_family_load_glyph( FTC_Family  ftcfamily,
155                                FT_UInt     gindex,
156                                FTC_Cache   cache,
157                                FT_Glyph   *aglyph )
158   {
159     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
160     FT_Error         error;
161     FTC_Scaler       scaler = &family->attrs.scaler;
162     FT_Face          face;
163     FT_Size          size;
164 
165 
166     /* we will now load the glyph image */
167     error = FTC_Manager_LookupSize( cache->manager,
168                                     scaler,
169                                     &size );
170     if ( !error )
171     {
172       face = size->face;
173 
174       error = FT_Load_Glyph( face,
175                              gindex,
176                              (FT_Int)family->attrs.load_flags );
177       if ( !error )
178       {
179         if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP  ||
180              face->glyph->format == FT_GLYPH_FORMAT_OUTLINE )
181         {
182           /* ok, copy it */
183           FT_Glyph  glyph;
184 
185 
186           error = FT_Get_Glyph( face->glyph, &glyph );
187           if ( !error )
188           {
189             *aglyph = glyph;
190             goto Exit;
191           }
192         }
193         else
194           error = FT_THROW( Invalid_Argument );
195       }
196     }
197 
198   Exit:
199     return error;
200   }
201 
202 
203   FT_CALLBACK_DEF( FT_Bool )
ftc_basic_gnode_compare_faceid(FTC_Node ftcgnode,FT_Pointer ftcface_id,FTC_Cache cache,FT_Bool * list_changed)204   ftc_basic_gnode_compare_faceid( FTC_Node    ftcgnode,
205                                   FT_Pointer  ftcface_id,
206                                   FTC_Cache   cache,
207                                   FT_Bool*    list_changed )
208   {
209     FTC_GNode        gnode   = (FTC_GNode)ftcgnode;
210     FTC_FaceID       face_id = (FTC_FaceID)ftcface_id;
211     FTC_BasicFamily  family  = (FTC_BasicFamily)gnode->family;
212     FT_Bool          result;
213 
214 
215     if ( list_changed )
216       *list_changed = FALSE;
217     result = FT_BOOL( family->attrs.scaler.face_id == face_id );
218     if ( result )
219     {
220       /* we must call this function to avoid this node from appearing
221        * in later lookups with the same face_id!
222        */
223       FTC_GNode_UnselectFamily( gnode, cache );
224     }
225     return result;
226   }
227 
228 
229  /*
230   *
231   * basic image cache
232   *
233   */
234 
235   static
236   const FTC_IFamilyClassRec  ftc_basic_image_family_class =
237   {
238     {
239       sizeof ( FTC_BasicFamilyRec ),
240       ftc_basic_family_compare,
241       ftc_basic_family_init,
242       0,                        /* FTC_MruNode_ResetFunc */
243       0                         /* FTC_MruNode_DoneFunc  */
244     },
245     ftc_basic_family_load_glyph
246   };
247 
248 
249   static
250   const FTC_GCacheClassRec  ftc_basic_image_cache_class =
251   {
252     {
253       ftc_inode_new,
254       ftc_inode_weight,
255       ftc_gnode_compare,
256       ftc_basic_gnode_compare_faceid,
257       ftc_inode_free,
258 
259       sizeof ( FTC_GCacheRec ),
260       ftc_gcache_init,
261       ftc_gcache_done
262     },
263     (FTC_MruListClass)&ftc_basic_image_family_class
264   };
265 
266 
267   /* documentation is in ftcache.h */
268 
269   FT_EXPORT_DEF( FT_Error )
FTC_ImageCache_New(FTC_Manager manager,FTC_ImageCache * acache)270   FTC_ImageCache_New( FTC_Manager      manager,
271                       FTC_ImageCache  *acache )
272   {
273     return FTC_GCache_New( manager, &ftc_basic_image_cache_class,
274                            (FTC_GCache*)acache );
275   }
276 
277 
278   /* documentation is in ftcache.h */
279 
280   FT_EXPORT_DEF( FT_Error )
FTC_ImageCache_Lookup(FTC_ImageCache cache,FTC_ImageType type,FT_UInt gindex,FT_Glyph * aglyph,FTC_Node * anode)281   FTC_ImageCache_Lookup( FTC_ImageCache  cache,
282                          FTC_ImageType   type,
283                          FT_UInt         gindex,
284                          FT_Glyph       *aglyph,
285                          FTC_Node       *anode )
286   {
287     FTC_BasicQueryRec  query;
288     FTC_Node           node = 0; /* make compiler happy */
289     FT_Error           error;
290     FT_Offset          hash;
291 
292 
293     /* some argument checks are delayed to `FTC_Cache_Lookup' */
294     if ( !aglyph )
295     {
296       error = FT_THROW( Invalid_Argument );
297       goto Exit;
298     }
299 
300     *aglyph = NULL;
301     if ( anode )
302       *anode  = NULL;
303 
304     if ( (FT_ULong)( type->flags - FT_INT_MIN ) > FT_UINT_MAX )
305       FT_TRACE1(( "FTC_ImageCache_Lookup:"
306                   " higher bits in load_flags 0x%x are dropped\n",
307                   (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) ));
308 
309     query.attrs.scaler.face_id = type->face_id;
310     query.attrs.scaler.width   = type->width;
311     query.attrs.scaler.height  = type->height;
312     query.attrs.load_flags     = (FT_UInt)type->flags;
313 
314     query.attrs.scaler.pixel = 1;
315     query.attrs.scaler.x_res = 0;  /* make compilers happy */
316     query.attrs.scaler.y_res = 0;
317 
318     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
319 
320 #if 1  /* inlining is about 50% faster! */
321     FTC_GCACHE_LOOKUP_CMP( cache,
322                            ftc_basic_family_compare,
323                            FTC_GNode_Compare,
324                            hash, gindex,
325                            &query,
326                            node,
327                            error );
328 #else
329     error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
330                                hash, gindex,
331                                FTC_GQUERY( &query ),
332                                &node );
333 #endif
334     if ( !error )
335     {
336       *aglyph = FTC_INODE( node )->glyph;
337 
338       if ( anode )
339       {
340         *anode = node;
341         node->ref_count++;
342       }
343     }
344 
345   Exit:
346     return error;
347   }
348 
349 
350   /* documentation is in ftcache.h */
351 
352   FT_EXPORT_DEF( FT_Error )
FTC_ImageCache_LookupScaler(FTC_ImageCache cache,FTC_Scaler scaler,FT_ULong load_flags,FT_UInt gindex,FT_Glyph * aglyph,FTC_Node * anode)353   FTC_ImageCache_LookupScaler( FTC_ImageCache  cache,
354                                FTC_Scaler      scaler,
355                                FT_ULong        load_flags,
356                                FT_UInt         gindex,
357                                FT_Glyph       *aglyph,
358                                FTC_Node       *anode )
359   {
360     FTC_BasicQueryRec  query;
361     FTC_Node           node = 0; /* make compiler happy */
362     FT_Error           error;
363     FT_Offset          hash;
364 
365 
366     /* some argument checks are delayed to `FTC_Cache_Lookup' */
367     if ( !aglyph || !scaler )
368     {
369       error = FT_THROW( Invalid_Argument );
370       goto Exit;
371     }
372 
373     *aglyph = NULL;
374     if ( anode )
375       *anode  = NULL;
376 
377     /* `FT_Load_Glyph' and `FT_Load_Char' take FT_UInt flags */
378     if ( load_flags > FT_UINT_MAX )
379       FT_TRACE1(( "FTC_ImageCache_LookupScaler:"
380                   " higher bits in load_flags 0x%x are dropped\n",
381                   load_flags & ~((FT_ULong)FT_UINT_MAX) ));
382 
383     query.attrs.scaler     = scaler[0];
384     query.attrs.load_flags = (FT_UInt)load_flags;
385 
386     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
387 
388     FTC_GCACHE_LOOKUP_CMP( cache,
389                            ftc_basic_family_compare,
390                            FTC_GNode_Compare,
391                            hash, gindex,
392                            &query,
393                            node,
394                            error );
395     if ( !error )
396     {
397       *aglyph = FTC_INODE( node )->glyph;
398 
399       if ( anode )
400       {
401         *anode = node;
402         node->ref_count++;
403       }
404     }
405 
406   Exit:
407     return error;
408   }
409 
410 
411   /*
412    *
413    * basic small bitmap cache
414    *
415    */
416 
417   static
418   const FTC_SFamilyClassRec  ftc_basic_sbit_family_class =
419   {
420     {
421       sizeof ( FTC_BasicFamilyRec ),
422       ftc_basic_family_compare,
423       ftc_basic_family_init,
424       0,                            /* FTC_MruNode_ResetFunc */
425       0                             /* FTC_MruNode_DoneFunc  */
426     },
427     ftc_basic_family_get_count,
428     ftc_basic_family_load_bitmap
429   };
430 
431 
432   static
433   const FTC_GCacheClassRec  ftc_basic_sbit_cache_class =
434   {
435     {
436       ftc_snode_new,
437       ftc_snode_weight,
438       ftc_snode_compare,
439       ftc_basic_gnode_compare_faceid,
440       ftc_snode_free,
441 
442       sizeof ( FTC_GCacheRec ),
443       ftc_gcache_init,
444       ftc_gcache_done
445     },
446     (FTC_MruListClass)&ftc_basic_sbit_family_class
447   };
448 
449 
450   /* documentation is in ftcache.h */
451 
452   FT_EXPORT_DEF( FT_Error )
FTC_SBitCache_New(FTC_Manager manager,FTC_SBitCache * acache)453   FTC_SBitCache_New( FTC_Manager     manager,
454                      FTC_SBitCache  *acache )
455   {
456     return FTC_GCache_New( manager, &ftc_basic_sbit_cache_class,
457                            (FTC_GCache*)acache );
458   }
459 
460 
461   /* documentation is in ftcache.h */
462 
463   FT_EXPORT_DEF( FT_Error )
FTC_SBitCache_Lookup(FTC_SBitCache cache,FTC_ImageType type,FT_UInt gindex,FTC_SBit * ansbit,FTC_Node * anode)464   FTC_SBitCache_Lookup( FTC_SBitCache  cache,
465                         FTC_ImageType  type,
466                         FT_UInt        gindex,
467                         FTC_SBit      *ansbit,
468                         FTC_Node      *anode )
469   {
470     FT_Error           error;
471     FTC_BasicQueryRec  query;
472     FTC_Node           node = 0; /* make compiler happy */
473     FT_Offset          hash;
474 
475 
476     if ( anode )
477       *anode = NULL;
478 
479     /* other argument checks delayed to `FTC_Cache_Lookup' */
480     if ( !ansbit )
481       return FT_THROW( Invalid_Argument );
482 
483     *ansbit = NULL;
484 
485     if ( (FT_ULong)( type->flags - FT_INT_MIN ) > FT_UINT_MAX )
486       FT_TRACE1(( "FTC_ImageCache_Lookup:"
487                   " higher bits in load_flags 0x%x are dropped\n",
488                   (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) ));
489 
490     query.attrs.scaler.face_id = type->face_id;
491     query.attrs.scaler.width   = type->width;
492     query.attrs.scaler.height  = type->height;
493     query.attrs.load_flags     = (FT_UInt)type->flags;
494 
495     query.attrs.scaler.pixel = 1;
496     query.attrs.scaler.x_res = 0;  /* make compilers happy */
497     query.attrs.scaler.y_res = 0;
498 
499     /* beware, the hash must be the same for all glyph ranges! */
500     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
501            gindex / FTC_SBIT_ITEMS_PER_NODE;
502 
503 #if 1  /* inlining is about 50% faster! */
504     FTC_GCACHE_LOOKUP_CMP( cache,
505                            ftc_basic_family_compare,
506                            FTC_SNode_Compare,
507                            hash, gindex,
508                            &query,
509                            node,
510                            error );
511 #else
512     error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
513                                hash,
514                                gindex,
515                                FTC_GQUERY( &query ),
516                                &node );
517 #endif
518     if ( error )
519       goto Exit;
520 
521     *ansbit = FTC_SNODE( node )->sbits +
522               ( gindex - FTC_GNODE( node )->gindex );
523 
524     if ( anode )
525     {
526       *anode = node;
527       node->ref_count++;
528     }
529 
530   Exit:
531     return error;
532   }
533 
534 
535   /* documentation is in ftcache.h */
536 
537   FT_EXPORT_DEF( FT_Error )
FTC_SBitCache_LookupScaler(FTC_SBitCache cache,FTC_Scaler scaler,FT_ULong load_flags,FT_UInt gindex,FTC_SBit * ansbit,FTC_Node * anode)538   FTC_SBitCache_LookupScaler( FTC_SBitCache  cache,
539                               FTC_Scaler     scaler,
540                               FT_ULong       load_flags,
541                               FT_UInt        gindex,
542                               FTC_SBit      *ansbit,
543                               FTC_Node      *anode )
544   {
545     FT_Error           error;
546     FTC_BasicQueryRec  query;
547     FTC_Node           node = 0; /* make compiler happy */
548     FT_Offset          hash;
549 
550 
551     if ( anode )
552         *anode = NULL;
553 
554     /* other argument checks delayed to `FTC_Cache_Lookup' */
555     if ( !ansbit || !scaler )
556         return FT_THROW( Invalid_Argument );
557 
558     *ansbit = NULL;
559 
560     /* `FT_Load_Glyph' and `FT_Load_Char' take FT_UInt flags */
561     if ( load_flags > FT_UINT_MAX )
562       FT_TRACE1(( "FTC_ImageCache_LookupScaler:"
563                   " higher bits in load_flags 0x%x are dropped\n",
564                   load_flags & ~((FT_ULong)FT_UINT_MAX) ));
565 
566     query.attrs.scaler     = scaler[0];
567     query.attrs.load_flags = (FT_UInt)load_flags;
568 
569     /* beware, the hash must be the same for all glyph ranges! */
570     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
571              gindex / FTC_SBIT_ITEMS_PER_NODE;
572 
573     FTC_GCACHE_LOOKUP_CMP( cache,
574                            ftc_basic_family_compare,
575                            FTC_SNode_Compare,
576                            hash, gindex,
577                            &query,
578                            node,
579                            error );
580     if ( error )
581       goto Exit;
582 
583     *ansbit = FTC_SNODE( node )->sbits +
584               ( gindex - FTC_GNODE( node )->gindex );
585 
586     if ( anode )
587     {
588       *anode = node;
589       node->ref_count++;
590     }
591 
592   Exit:
593     return error;
594   }
595 
596 
597 /* END */
598