5840382412eef018af27ff8d9b41ad440639dbc2
[reactos.git] / lib / freetype / src / cache / ftcsbits.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftcsbits.c                                                             */
4 /*                                                                         */
5 /*    FreeType sbits manager (body).                                       */
6 /*                                                                         */
7 /*  Copyright 2000-2001, 2002 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_CACHE_H
21 #include FT_CACHE_SMALL_BITMAPS_H
22 #include FT_CACHE_INTERNAL_GLYPH_H
23 #include FT_INTERNAL_OBJECTS_H
24 #include FT_INTERNAL_DEBUG_H
25 #include FT_ERRORS_H
26
27 #include "ftcerror.h"
28
29
30 #define FTC_SBIT_ITEMS_PER_NODE  16
31
32
33   typedef struct FTC_SBitNodeRec_*  FTC_SBitNode;
34
35   typedef struct  FTC_SBitNodeRec_
36   {
37     FTC_GlyphNodeRec  gnode;
38     FTC_SBitRec       sbits[FTC_SBIT_ITEMS_PER_NODE];
39
40   } FTC_SBitNodeRec;
41
42
43 #define FTC_SBIT_NODE( x )  ( (FTC_SBitNode)( x ) )
44
45
46   typedef struct  FTC_SBitQueryRec_
47   {
48     FTC_GlyphQueryRec  gquery;
49     FTC_ImageTypeRec   type;
50
51   } FTC_SBitQueryRec, *FTC_SBitQuery;
52
53
54 #define FTC_SBIT_QUERY( x ) ( (FTC_SBitQuery)( x ) )
55
56
57   typedef struct FTC_SBitFamilyRec_*  FTC_SBitFamily;
58
59   /* sbit family structure */
60   typedef struct  FTC_SBitFamilyRec_
61   {
62     FTC_GlyphFamilyRec  gfam;
63     FTC_ImageTypeRec    type;
64
65   } FTC_SBitFamilyRec;
66
67
68 #define FTC_SBIT_FAMILY( x )         ( (FTC_SBitFamily)( x ) )
69 #define FTC_SBIT_FAMILY_MEMORY( x )  FTC_GLYPH_FAMILY_MEMORY( &( x )->cset )
70
71
72   /*************************************************************************/
73   /*************************************************************************/
74   /*****                                                               *****/
75   /*****                     SBIT CACHE NODES                          *****/
76   /*****                                                               *****/
77   /*************************************************************************/
78   /*************************************************************************/
79
80
81   static FT_Error
82   ftc_sbit_copy_bitmap( FTC_SBit    sbit,
83                         FT_Bitmap*  bitmap,
84                         FT_Memory   memory )
85   {
86     FT_Error  error;
87     FT_Int    pitch = bitmap->pitch;
88     FT_ULong  size;
89
90
91     if ( pitch < 0 )
92       pitch = -pitch;
93
94     size = (FT_ULong)( pitch * bitmap->rows );
95
96     if ( !FT_ALLOC( sbit->buffer, size ) )
97       FT_MEM_COPY( sbit->buffer, bitmap->buffer, size );
98
99     return error;
100   }
101
102
103   FT_CALLBACK_DEF( void )
104   ftc_sbit_node_done( FTC_SBitNode  snode,
105                       FTC_Cache     cache )
106   {
107     FTC_SBit   sbit   = snode->sbits;
108     FT_UInt    count  = FTC_GLYPH_NODE( snode )->item_count;
109     FT_Memory  memory = cache->memory;
110
111
112     for ( ; count > 0; sbit++, count-- )
113       FT_FREE( sbit->buffer );
114
115     ftc_glyph_node_done( FTC_GLYPH_NODE( snode ), cache );
116   }
117
118
119   static FT_Error
120   ftc_sbit_node_load( FTC_SBitNode    snode,
121                       FTC_Manager     manager,
122                       FTC_SBitFamily  sfam,
123                       FT_UInt         gindex,
124                       FT_ULong       *asize )
125   {
126     FT_Error       error;
127     FTC_GlyphNode  gnode = FTC_GLYPH_NODE( snode );
128     FT_Memory      memory;
129     FT_Face        face;
130     FT_Size        size;
131     FTC_SBit       sbit;
132
133
134     if ( gindex <  (FT_UInt)gnode->item_start                     ||
135          gindex >= (FT_UInt)gnode->item_start + gnode->item_count )
136     {
137       FT_ERROR(( "ftc_sbit_node_load: invalid glyph index" ));
138       return FTC_Err_Invalid_Argument;
139     }
140
141     memory = manager->library->memory;
142
143     sbit = snode->sbits + ( gindex - gnode->item_start );
144
145     error = FTC_Manager_Lookup_Size( manager, &sfam->type.font,
146                                      &face, &size );
147     if ( !error )
148     {
149       /* by default, indicates a `missing' glyph */
150       sbit->buffer = 0;
151
152       error = FT_Load_Glyph( face, gindex, sfam->type.flags | FT_LOAD_RENDER );
153       if ( !error )
154       {
155         FT_Int        temp;
156         FT_GlyphSlot  slot   = face->glyph;
157         FT_Bitmap*    bitmap = &slot->bitmap;
158         FT_Int        xadvance, yadvance;
159
160
161         /* check that our values fit into 8-bit containers!       */
162         /* If this is not the case, our bitmap is too large       */
163         /* and we will leave it as `missing' with sbit.buffer = 0 */
164
165 #define CHECK_CHAR( d )  ( temp = (FT_Char)d, temp == d )
166 #define CHECK_BYTE( d )  ( temp = (FT_Byte)d, temp == d )
167
168         /* XXX: FIXME: add support for vertical layouts maybe */
169
170         /* horizontal advance in pixels */
171         xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6;
172         yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6;
173
174         if ( CHECK_BYTE( bitmap->rows  )     &&
175              CHECK_BYTE( bitmap->width )     &&
176              CHECK_CHAR( bitmap->pitch )     &&
177              CHECK_CHAR( slot->bitmap_left ) &&
178              CHECK_CHAR( slot->bitmap_top  ) &&
179              CHECK_CHAR( xadvance )          &&
180              CHECK_CHAR( yadvance )          )
181         {
182           sbit->width     = (FT_Byte)bitmap->width;
183           sbit->height    = (FT_Byte)bitmap->rows;
184           sbit->pitch     = (FT_Char)bitmap->pitch;
185           sbit->left      = (FT_Char)slot->bitmap_left;
186           sbit->top       = (FT_Char)slot->bitmap_top;
187           sbit->xadvance  = (FT_Char)xadvance;
188           sbit->yadvance  = (FT_Char)yadvance;
189           sbit->format    = (FT_Byte)bitmap->pixel_mode;
190           sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1);
191
192 #if 0 /* this doesn't work well with embedded bitmaps !! */
193
194           /* grab the bitmap when possible - this is a hack! */
195           if ( slot->flags & FT_GLYPH_OWN_BITMAP )
196           {
197             slot->flags &= ~FT_GLYPH_OWN_BITMAP;
198             sbit->buffer = bitmap->buffer;
199           }
200           else
201 #endif
202           {
203             /* copy the bitmap into a new buffer -- ignore error */
204             error = ftc_sbit_copy_bitmap( sbit, bitmap, memory );
205           }
206
207           /* now, compute size */
208           if ( asize )
209             *asize = ABS( sbit->pitch ) * sbit->height;
210
211         }  /* glyph dimensions ok */
212
213       } /* glyph loading successful */
214
215       /* ignore the errors that might have occurred --   */
216       /* we mark unloaded glyphs with `sbit.buffer == 0' */
217       /* and 'width == 255', 'height == 0'               */
218       /*                                                 */
219       if ( error && error != FT_Err_Out_Of_Memory )
220       {
221         sbit->width = 255;
222         error       = 0;
223         /* sbit->buffer == NULL too! */
224       }
225     }
226
227     return error;
228   }
229
230
231   FT_CALLBACK_DEF( FT_Error )
232   ftc_sbit_node_init( FTC_SBitNode    snode,
233                       FTC_GlyphQuery  gquery,
234                       FTC_Cache       cache )
235   {
236     FT_Error  error;
237
238
239     ftc_glyph_node_init( FTC_GLYPH_NODE( snode ),
240                          gquery->gindex,
241                          FTC_GLYPH_FAMILY( gquery->query.family ) );
242
243     error = ftc_sbit_node_load( snode,
244                                 cache->manager,
245                                 FTC_SBIT_FAMILY( FTC_QUERY( gquery )->family ),
246                                 gquery->gindex,
247                                 NULL );
248     if ( error )
249       ftc_glyph_node_done( FTC_GLYPH_NODE( snode ), cache );
250
251     return error;
252   }
253
254
255   FT_CALLBACK_DEF( FT_ULong )
256   ftc_sbit_node_weight( FTC_SBitNode  snode )
257   {
258     FTC_GlyphNode  gnode = FTC_GLYPH_NODE( snode );
259     FT_UInt        count = gnode->item_count;
260     FTC_SBit       sbit  = snode->sbits;
261     FT_Int         pitch;
262     FT_ULong       size;
263
264
265     /* the node itself */
266     size = sizeof ( *snode );
267
268     /* the sbit records */
269     size += FTC_GLYPH_NODE( snode )->item_count * sizeof ( FTC_SBitRec );
270
271     for ( ; count > 0; count--, sbit++ )
272     {
273       if ( sbit->buffer )
274       {
275         pitch = sbit->pitch;
276         if ( pitch < 0 )
277           pitch = -pitch;
278
279         /* add the size of a given glyph image */
280         size += pitch * sbit->height;
281       }
282     }
283
284     return size;
285   }
286
287
288   FT_CALLBACK_DEF( FT_Bool )
289   ftc_sbit_node_compare( FTC_SBitNode   snode,
290                          FTC_SBitQuery  squery,
291                          FTC_Cache      cache )
292   {
293     FTC_GlyphQuery  gquery = FTC_GLYPH_QUERY( squery );
294     FTC_GlyphNode   gnode  = FTC_GLYPH_NODE( snode );
295     FT_Bool         result;
296
297
298     result = ftc_glyph_node_compare( gnode, gquery );
299     if ( result )
300     {
301       /* check if we need to load the glyph bitmap now */
302       FT_UInt   gindex = gquery->gindex;
303       FTC_SBit  sbit   = snode->sbits + ( gindex - gnode->item_start );
304
305
306       if ( sbit->buffer == NULL && sbit->width != 255 )
307       {
308         FT_ULong  size;
309
310
311         /* yes, it's safe to ignore errors here */
312         ftc_sbit_node_load( snode,
313                             cache->manager,
314                             FTC_SBIT_FAMILY( FTC_QUERY( squery )->family ),
315                             gindex,
316                             &size );
317
318         cache->manager->cur_weight += size;
319       }
320     }
321
322     return result;
323   }
324
325
326   /*************************************************************************/
327   /*************************************************************************/
328   /*****                                                               *****/
329   /*****                     SBITS FAMILIES                            *****/
330   /*****                                                               *****/
331   /*************************************************************************/
332   /*************************************************************************/
333
334
335   FT_CALLBACK_DEF( FT_Error )
336   ftc_sbit_family_init( FTC_SBitFamily  sfam,
337                         FTC_SBitQuery   squery,
338                         FTC_Cache       cache )
339   {
340     FTC_Manager  manager = cache->manager;
341     FT_Error     error;
342     FT_Face      face;
343
344
345     sfam->type = squery->type;
346
347     /* we need to compute "cquery.item_total" now */
348     error = FTC_Manager_Lookup_Face( manager,
349                                      squery->type.font.face_id,
350                                      &face );
351     if ( !error )
352     {
353       error = ftc_glyph_family_init( FTC_GLYPH_FAMILY( sfam ),
354                                      FTC_IMAGE_TYPE_HASH( &sfam->type ),
355                                      FTC_SBIT_ITEMS_PER_NODE,
356                                      face->num_glyphs,
357                                      FTC_GLYPH_QUERY( squery ),
358                                      cache );
359     }
360
361     return error;
362   }
363
364
365   FT_CALLBACK_DEF( FT_Bool )
366   ftc_sbit_family_compare( FTC_SBitFamily  sfam,
367                            FTC_SBitQuery   squery )
368   {
369     FT_Bool  result;
370
371
372     /* we need to set the "cquery.cset" field or our query for */
373     /* faster glyph comparisons in ftc_sbit_node_compare       */
374     /*                                                         */
375     result = FT_BOOL( FTC_IMAGE_TYPE_COMPARE( &sfam->type, &squery->type ) );
376     if ( result )
377       FTC_GLYPH_FAMILY_FOUND( sfam, squery );
378
379     return result;
380   }
381
382
383   /*************************************************************************/
384   /*************************************************************************/
385   /*****                                                               *****/
386   /*****                     SBITS CACHE                               *****/
387   /*****                                                               *****/
388   /*************************************************************************/
389   /*************************************************************************/
390
391
392   FT_CALLBACK_TABLE_DEF
393   const FTC_Cache_ClassRec  ftc_sbit_cache_class =
394   {
395     sizeof ( FTC_CacheRec ),
396     (FTC_Cache_InitFunc) ftc_cache_init,
397     (FTC_Cache_ClearFunc)ftc_cache_clear,
398     (FTC_Cache_DoneFunc) ftc_cache_done,
399
400     sizeof ( FTC_SBitFamilyRec ),
401     (FTC_Family_InitFunc)   ftc_sbit_family_init,
402     (FTC_Family_CompareFunc)ftc_sbit_family_compare,
403     (FTC_Family_DoneFunc)   ftc_glyph_family_done,
404
405     sizeof ( FTC_SBitNodeRec ),
406     (FTC_Node_InitFunc)   ftc_sbit_node_init,
407     (FTC_Node_WeightFunc) ftc_sbit_node_weight,
408     (FTC_Node_CompareFunc)ftc_sbit_node_compare,
409     (FTC_Node_DoneFunc)   ftc_sbit_node_done
410   };
411
412
413   /* documentation is in ftcsbits.h */
414
415   FT_EXPORT_DEF( FT_Error )
416   FTC_SBitCache_New( FTC_Manager     manager,
417                      FTC_SBitCache  *acache )
418   {
419     return FTC_Manager_Register_Cache( manager,
420                                        &ftc_sbit_cache_class,
421                                        (FTC_Cache*)acache );
422   }
423
424
425   /* documentation is in ftcsbits.h */
426
427 #ifdef FTC_CACHE_USE_INLINE
428
429 #define GEN_CACHE_FAMILY_COMPARE( f, q, c ) \
430           ftc_sbit_family_compare( (FTC_SBitFamily)(f), (FTC_SBitQuery)(q) )
431
432 #define GEN_CACHE_NODE_COMPARE( n, q, c ) \
433           ftc_sbit_node_compare( (FTC_SBitNode)(n), (FTC_SBitQuery)(q), c )
434
435 #define GEN_CACHE_LOOKUP  ftc_sbit_cache_lookup
436 #include "ftccache.i"
437
438 #else  /* !FTC_CACHE_USE_INLINE */
439
440 #define ftc_sbit_cache_lookup  ftc_cache_lookup
441
442 #endif /* !FTC_CACHE_USE_INLINE */
443
444   FT_EXPORT_DEF( FT_Error )
445   FTC_SBitCache_Lookup( FTC_SBitCache   cache,
446                         FTC_ImageType   type,
447                         FT_UInt         gindex,
448                         FTC_SBit       *ansbit,
449                         FTC_Node       *anode )
450   {
451     FT_Error          error;
452     FTC_SBitQueryRec  squery;
453     FTC_SBitNode      node;
454
455
456     /* other argument checks delayed to ftc_cache_lookup */
457     if ( !ansbit )
458       return FTC_Err_Invalid_Argument;
459
460     *ansbit = NULL;
461
462     if ( anode )
463       *anode = NULL;
464
465     squery.gquery.gindex = gindex;
466     squery.type          = *type;
467
468     error = ftc_sbit_cache_lookup( FTC_CACHE( cache ),
469                                    FTC_QUERY( &squery ),
470                                    (FTC_Node*)&node );
471     if ( !error )
472     {
473       *ansbit = node->sbits + ( gindex - FTC_GLYPH_NODE( node )->item_start );
474
475       if ( anode )
476       {
477         *anode = FTC_NODE( node );
478         FTC_NODE( node )->ref_count++;
479       }
480     }
481     return error;
482   }
483
484
485   /* backwards-compatibility functions */
486
487   FT_EXPORT_DEF( FT_Error )
488   FTC_SBit_Cache_New( FTC_Manager      manager,
489                       FTC_SBit_Cache  *acache )
490   {
491     return FTC_SBitCache_New( manager, (FTC_SBitCache*)acache );
492   }
493
494
495   FT_EXPORT_DEF( FT_Error )
496   FTC_SBit_Cache_Lookup( FTC_SBit_Cache   cache,
497                          FTC_Image_Desc*  desc,
498                          FT_UInt          gindex,
499                          FTC_SBit        *ansbit )
500   {
501     FTC_ImageTypeRec  type0;
502
503
504     if ( !desc )
505       return FTC_Err_Invalid_Argument;
506
507     type0.font  = desc->font;
508     type0.flags = 0;
509
510     /* convert image type flags to load flags */
511     {
512       FT_UInt  load_flags = FT_LOAD_DEFAULT;
513       FT_UInt  type       = desc->image_type;
514
515
516       /* determine load flags, depending on the font description's */
517       /* image type                                                */
518
519       if ( ftc_image_format( type ) == ftc_image_format_bitmap )
520       {
521         if ( type & ftc_image_flag_monochrome )
522           load_flags |= FT_LOAD_MONOCHROME;
523
524         /* disable embedded bitmaps loading if necessary */
525         if ( type & ftc_image_flag_no_sbits )
526           load_flags |= FT_LOAD_NO_BITMAP;
527       }
528       else
529       {
530         /* we want an outline, don't load embedded bitmaps */
531         load_flags |= FT_LOAD_NO_BITMAP;
532
533         if ( type & ftc_image_flag_unscaled )
534           load_flags |= FT_LOAD_NO_SCALE;
535       }
536
537       /* always render glyphs to bitmaps */
538       load_flags |= FT_LOAD_RENDER;
539
540       if ( type & ftc_image_flag_unhinted )
541         load_flags |= FT_LOAD_NO_HINTING;
542
543       if ( type & ftc_image_flag_autohinted )
544         load_flags |= FT_LOAD_FORCE_AUTOHINT;
545
546       type0.flags = load_flags;
547     }
548
549     return FTC_SBitCache_Lookup( (FTC_SBitCache)cache,
550                                   &type0,
551                                   gindex,
552                                   ansbit,
553                                   NULL );
554   }
555
556
557 /* END */