1/***************************************************************************/
2/*                                                                         */
3/*  ftcbasic.c                                                             */
4/*                                                                         */
5/*    The FreeType basic cache interface (body).                           */
6/*                                                                         */
7/*  Copyright 2003-2007, 2009-2011, 2013, 2014 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 )
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    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 )
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 )
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 )
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  static
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  static
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 )
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 )
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 )
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  static
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  static
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 )
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 )
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 )
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