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