ftcsbits.c revision ab8552321c70e947fedfd31709c43c4cb27d496f
1/***************************************************************************/
2/*                                                                         */
3/*  ftcsbits.c                                                             */
4/*                                                                         */
5/*    FreeType sbits manager (body).                                       */
6/*                                                                         */
7/*  Copyright 2000 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/cache/ftcsbits.h>
20#include <freetype/internal/ftobjs.h>
21#include <freetype/internal/ftdebug.h>
22#include <freetype/fterrors.h>
23
24#include <string.h>         /* memcmp() */
25
26
27#define  FTC_SBITSET_ELEMENT_COUNT  16
28
29
30  typedef struct  FTC_SBitSetRec_
31  {
32    FTC_ChunkSetRec  root;
33    FTC_Image_Desc   desc;
34
35  } FTC_SBitSetRec, *FTC_SBitSet;
36
37
38  typedef struct  FTC_SBit_CacheRec_
39  {
40    FTC_Chunk_CacheRec  root;
41
42  } FTC_SBit_CacheRec;
43
44
45
46  /*************************************************************************/
47  /*************************************************************************/
48  /*****                                                               *****/
49  /*****                     SBIT CACHE NODES                          *****/
50  /*****                                                               *****/
51  /*************************************************************************/
52  /*************************************************************************/
53
54
55  LOCAL_FUNC_X
56  void  ftc_sbit_chunk_node_destroy( FTC_ChunkNode  node )
57  {
58    FTC_ChunkSet  cset   = node->cset;
59    FT_Memory     memory = cset->memory;
60    FT_UInt       count  = node->num_elements;
61    FTC_SBit      sbit   = (FTC_SBit)node->elements;
62
63
64    for ( ; count > 0; sbit++, count-- )
65      FREE( sbit->buffer );
66
67    FREE( node->elements );
68    FREE( node );
69  }
70
71
72  LOCAL_FUNC_X
73  FT_Error  ftc_bitmap_copy( FT_Memory   memory,
74                             FT_Bitmap*  source,
75                             FTC_SBit    target )
76  {
77    FT_Error  error;
78    FT_Int    pitch = source->pitch;
79    FT_ULong  size;
80
81
82    if ( pitch < 0 )
83      pitch = -pitch;
84
85    size = (FT_ULong)( pitch * source->rows );
86
87    if ( !ALLOC( target->buffer, size ) )
88      MEM_Copy( target->buffer, source->buffer, size );
89
90    return error;
91  }
92
93
94  LOCAL_FUNC_X
95  FT_Error  ftc_sbit_chunk_node_new( FTC_ChunkSet    cset,
96                                     FT_UInt         index,
97                                     FTC_ChunkNode*  anode )
98  {
99    FT_Error       error;
100    FT_Memory      memory  = cset->memory;
101    FTC_SBitSet    sbitset = (FTC_SBitSet)cset;
102    FTC_ChunkNode  node    = 0;
103    FT_Face        face;
104    FT_Size        size;
105
106
107    /* allocate node */
108    if ( ALLOC( node, sizeof ( *node ) ) )
109      goto Exit;
110
111    /* initialize its inner fields */
112    error = FTC_ChunkNode_Init( node, cset, index, 1 );
113    if ( error )
114      goto Exit;
115
116    /* we will now load all glyph images for this chunk */
117    error = FTC_Manager_Lookup_Size( cset->manager,
118                                     &sbitset->desc.font,
119                                     &face, &size );
120    if ( !error )
121    {
122      FT_UInt   glyph_index = index * cset->element_count;
123      FT_UInt   load_flags  = FT_LOAD_DEFAULT;
124      FT_UInt   image_type  = sbitset->desc.image_type;
125      FT_UInt   count       = node->num_elements;
126      FTC_SBit  sbit        = (FTC_SBit)node->elements;
127
128
129      /* determine load flags, depending on the font description's */
130      /* image type                                                */
131
132      if ( FTC_IMAGE_FORMAT( image_type ) == ftc_image_format_bitmap )
133      {
134        if ( image_type & ftc_image_flag_monochrome )
135          load_flags |= FT_LOAD_MONOCHROME;
136
137        /* disable embedded bitmaps loading if necessary */
138        if ( image_type & ftc_image_flag_no_sbits )
139          load_flags |= FT_LOAD_NO_BITMAP;
140      }
141      else
142      {
143        FT_ERROR(( "FTC_SBit_Cache: cannot load scalable glyphs in an"
144                   " sbit cache, please check your arguments!\n" ));
145        error = FT_Err_Invalid_Argument;
146        goto Exit;
147      }
148
149      /* always render glyphs to bitmaps */
150      load_flags |= FT_LOAD_RENDER;
151
152      if ( image_type & ftc_image_flag_unhinted )
153        load_flags |= FT_LOAD_NO_HINTING;
154
155      if ( image_type & ftc_image_flag_autohinted )
156        load_flags |= FT_LOAD_FORCE_AUTOHINT;
157
158      /* load a chunk of small bitmaps in a row */
159      for ( ; count > 0; count--, glyph_index++, sbit++ )
160      {
161        /* by default, indicates a `missing' glyph */
162        sbit->buffer = 0;
163
164        error = FT_Load_Glyph( face, glyph_index, load_flags );
165        if ( !error )
166        {
167          FT_Int        temp;
168          FT_GlyphSlot  slot   = face->glyph;
169          FT_Bitmap*    bitmap = &slot->bitmap;
170          FT_Int        xadvance, yadvance;
171
172
173          /* check that our values fit into 8-bit containers!       */
174          /* If this is not the case, our bitmap is too large       */
175          /* and we will leave it as `missing' with sbit.buffer = 0 */
176
177#define CHECK_CHAR( d )  ( temp = (FT_Char)d, temp == d )
178#define CHECK_BYTE( d )  ( temp = (FT_Byte)d, temp == d )
179
180          /* XXX: FIXME: add support for vertical layouts maybe */
181
182          /* horizontal advance in pixels */
183          xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6;
184          yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6;
185
186          if ( CHECK_BYTE( bitmap->rows  )     &&
187               CHECK_BYTE( bitmap->width )     &&
188               CHECK_CHAR( bitmap->pitch )     &&
189               CHECK_CHAR( slot->bitmap_left ) &&
190               CHECK_CHAR( slot->bitmap_top  ) &&
191               CHECK_CHAR( xadvance )          &&
192               CHECK_CHAR( yadvance )          )
193          {
194            sbit->width    = (FT_Byte)bitmap->width;
195            sbit->height   = (FT_Byte)bitmap->rows;
196            sbit->pitch    = (FT_Char)bitmap->pitch;
197            sbit->left     = (FT_Char)slot->bitmap_left;
198            sbit->top      = (FT_Char)slot->bitmap_top;
199            sbit->xadvance = (FT_Char)xadvance;
200            sbit->yadvance = (FT_Char)yadvance;
201            sbit->format   = (FT_Byte)bitmap->pixel_mode;
202
203            /* grab the bitmap when possible */
204            if ( slot->flags & ft_glyph_own_bitmap )
205            {
206              slot->flags &= ~ft_glyph_own_bitmap;
207              sbit->buffer = bitmap->buffer;
208            }
209            else
210            {
211              /* copy the bitmap into a new buffer -- ignore error */
212              ftc_bitmap_copy( memory, bitmap, sbit );
213            }
214          }
215        }
216      }
217
218      /* ignore the errors that might have occurred --        */
219      /* we recognize unloaded glyphs with `sbit.buffer == 0' */
220      error = 0;
221    }
222
223  Exit:
224    if ( error && node )
225    {
226      FREE( node->elements );
227      FREE( node );
228    }
229
230    *anode = node;
231
232    return error;
233  }
234
235
236  /* this function is important because it is both part of */
237  /* an FTC_ChunkSet_Class and an FTC_CacheNode_Class      */
238  /*                                                       */
239  LOCAL_FUNC_X
240  FT_ULong  ftc_sbit_chunk_node_size( FTC_ChunkNode  node )
241  {
242    FT_ULong      size;
243    FTC_ChunkSet  cset  = node->cset;
244    FT_UInt       count = node->num_elements;
245    FT_Int        pitch;
246    FTC_SBit      sbit  = (FTC_SBit)node->elements;
247
248
249    /* the node itself */
250    size  = sizeof ( *node );
251    /* the sbit records */
252    size += cset->element_count * sizeof ( FTC_SBitRec );
253
254    for ( ; count > 0; count--, sbit++ )
255    {
256      if ( sbit->buffer )
257      {
258        pitch = sbit->pitch;
259        if ( pitch < 0 )
260          pitch = -pitch;
261
262        /* add the size of a given glyph image */
263        size += pitch * sbit->height;
264      }
265    }
266
267    return size;
268  }
269
270
271  /*************************************************************************/
272  /*************************************************************************/
273  /*****                                                               *****/
274  /*****                     SBIT CHUNK SETS                           *****/
275  /*****                                                               *****/
276  /*************************************************************************/
277  /*************************************************************************/
278
279
280  LOCAL_FUNC_X
281  FT_Error  ftc_sbit_chunk_set_sizes( FTC_ChunkSet     cset,
282                                      FTC_Image_Desc*  desc )
283  {
284    FT_Error  error;
285    FT_Face   face;
286
287
288    cset->element_count = FTC_SBITSET_ELEMENT_COUNT;
289    cset->element_size  = sizeof ( FTC_SBitRec );
290
291    /* lookup the FT_Face to obtain the number of glyphs */
292    error = FTC_Manager_Lookup_Face( cset->manager,
293                                     desc->font.face_id, &face );
294    if ( !error )
295      cset->element_max = face->num_glyphs;
296
297    return error;
298  }
299
300
301  LOCAL_FUNC_X
302  FT_Error  ftc_sbit_chunk_set_init( FTC_SBitSet      sset,
303                                     FTC_Image_Desc*  type )
304  {
305    sset->desc = *type;
306
307    return 0;
308  }
309
310
311  LOCAL_FUNC_X
312  FT_Bool  ftc_sbit_chunk_set_compare( FTC_SBitSet      sset,
313                                       FTC_Image_Desc*  type )
314  {
315    return !memcmp( &sset->desc, type, sizeof ( *type ) );
316  }
317
318
319  FT_CPLUSPLUS( const FTC_ChunkSet_Class )  ftc_sbit_chunk_set_class =
320  {
321    sizeof( FTC_SBitSetRec ),
322
323    (FTC_ChunkSet_InitFunc)       ftc_sbit_chunk_set_init,
324    (FTC_ChunkSet_DoneFunc)       0,
325    (FTC_ChunkSet_CompareFunc)    ftc_sbit_chunk_set_compare,
326    (FTC_ChunkSet_SizesFunc)      ftc_sbit_chunk_set_sizes,
327
328    (FTC_ChunkSet_NewNodeFunc)    ftc_sbit_chunk_node_new,
329    (FTC_ChunkSet_SizeNodeFunc)   ftc_sbit_chunk_node_size,
330    (FTC_ChunkSet_DestroyNodeFunc)ftc_sbit_chunk_node_destroy
331  };
332
333
334  /*************************************************************************/
335  /*************************************************************************/
336  /*****                                                               *****/
337  /*****                     SBITS CACHE                               *****/
338  /*****                                                               *****/
339  /*************************************************************************/
340  /*************************************************************************/
341
342
343  FT_CPLUSPLUS( const FTC_Chunk_Cache_Class )  ftc_sbit_cache_class =
344  {
345    {
346      sizeof( FTC_SBit_CacheRec ),
347      (FTC_Cache_InitFunc)FTC_Chunk_Cache_Init,
348      (FTC_Cache_DoneFunc)FTC_Chunk_Cache_Done
349    },
350    (FTC_ChunkSet_Class*)&ftc_sbit_chunk_set_class
351  };
352
353
354  FT_EXPORT_FUNC( FT_Error )  FTC_SBit_Cache_New( FTC_Manager      manager,
355                                                  FTC_SBit_Cache*  acache )
356  {
357    return FTC_Manager_Register_Cache(
358              manager,
359              (FTC_Cache_Class*)&ftc_sbit_cache_class,
360              (FTC_Cache*)acache );
361  }
362
363
364  FT_EXPORT_DEF( FT_Error )  FTC_SBit_Cache_Lookup( FTC_SBit_Cache   cache,
365                                                    FTC_Image_Desc*  desc,
366                                                    FT_UInt          gindex,
367                                                    FTC_SBit*        asbit )
368  {
369    FT_Error       error;
370    FTC_ChunkSet   cset;
371    FTC_ChunkNode  node;
372    FT_UInt        cindex;
373    FTC_Manager    manager;
374
375    FTC_SBitSet    sset;
376    FTC_SBit       sbit;
377
378
379    /* check for valid `desc' delayed to FT_Lru_Lookup() */
380
381    if ( !cache || !asbit )
382      return FT_Err_Invalid_Argument;
383
384    *asbit = 0;
385    cset   = cache->root.last_cset;
386    sset   = (FTC_SBitSet)cset;
387
388    if ( !cset || memcmp( &sset->desc, desc, sizeof ( *desc ) ) )
389    {
390      error = FT_Lru_Lookup( cache->root.csets_lru,
391                             (FT_LruKey)desc,
392                             (FT_Pointer*)&cset );
393      cache->root.last_cset = cset;
394      if ( error )
395        goto Exit;
396    }
397
398    error = FTC_ChunkSet_Lookup_Node( cset, gindex, &node, &cindex );
399    if ( error )
400      goto Exit;
401
402    /* now compress the manager's cache pool if needed */
403    manager = cache->root.root.manager;
404    if ( manager->num_bytes > manager->max_bytes )
405    {
406      FTC_ChunkNode_Ref   ( node );
407      FTC_Manager_Compress( manager );
408      FTC_ChunkNode_Unref ( node );
409    }
410
411    sbit   = ((FTC_SBit)((FTC_ChunkNode)node)->elements) + cindex;
412    *asbit = sbit;
413
414  Exit:
415    return error;
416  }
417
418
419/* END */
420