source: trunk/poppler/freetype-2.1.10/src/cache/ftcsbits.c @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 15 years ago

First import

File size: 11.8 KB
Line 
1/***************************************************************************/
2/*                                                                         */
3/*  ftcsbits.c                                                             */
4/*                                                                         */
5/*    FreeType sbits manager (body).                                       */
6/*                                                                         */
7/*  Copyright 2000-2001, 2002, 2003, 2004, 2005 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_INTERNAL_SBITS_H
22#include FT_INTERNAL_OBJECTS_H
23#include FT_INTERNAL_DEBUG_H
24#include FT_ERRORS_H
25
26#include "ftccback.h"
27#include "ftcerror.h"
28
29
30  /*************************************************************************/
31  /*************************************************************************/
32  /*****                                                               *****/
33  /*****                     SBIT CACHE NODES                          *****/
34  /*****                                                               *****/
35  /*************************************************************************/
36  /*************************************************************************/
37
38
39  static FT_Error
40  ftc_sbit_copy_bitmap( FTC_SBit    sbit,
41                        FT_Bitmap*  bitmap,
42                        FT_Memory   memory )
43  {
44    FT_Error  error;
45    FT_Int    pitch = bitmap->pitch;
46    FT_ULong  size;
47
48
49    if ( pitch < 0 )
50      pitch = -pitch;
51
52    size = (FT_ULong)( pitch * bitmap->rows );
53
54    if ( !FT_ALLOC( sbit->buffer, size ) )
55      FT_MEM_COPY( sbit->buffer, bitmap->buffer, size );
56
57    return error;
58  }
59
60
61  FT_LOCAL_DEF( void )
62  ftc_snode_free( FTC_Node   ftcsnode,
63                  FTC_Cache  cache )
64  {
65    FTC_SNode  snode  = (FTC_SNode)ftcsnode;
66    FTC_SBit   sbit   = snode->sbits;
67    FT_UInt    count  = snode->count;
68    FT_Memory  memory = cache->memory;
69
70
71    for ( ; count > 0; sbit++, count-- )
72      FT_FREE( sbit->buffer );
73
74    FTC_GNode_Done( FTC_GNODE( snode ), cache );
75
76    FT_FREE( snode );
77  }
78
79
80  FT_EXPORT_DEF( void )
81  FTC_SNode_Free( FTC_SNode  snode,
82                  FTC_Cache  cache )
83  {
84    ftc_snode_free( FTC_NODE( snode ), cache );
85  }
86
87
88  /*
89   *  This function tries to load a small bitmap within a given FTC_SNode.
90   *  Note that it returns a non-zero error code _only_ in the case of
91   *  out-of-memory condition.  For all other errors (e.g., corresponding
92   *  to a bad font file), this function will mark the sbit as `unavailable'
93   *  and return a value of 0.
94   *
95   *  You should also read the comment within the @ftc_snode_compare
96   *  function below to see how out-of-memory is handled during a lookup.
97   */
98  static FT_Error
99  ftc_snode_load( FTC_SNode    snode,
100                  FTC_Manager  manager,
101                  FT_UInt      gindex,
102                  FT_ULong    *asize )
103  {
104    FT_Error          error;
105    FTC_GNode         gnode  = FTC_GNODE( snode );
106    FTC_Family        family = gnode->family;
107    FT_Memory         memory = manager->memory;
108    FT_Face           face;
109    FTC_SBit          sbit;
110    FTC_SFamilyClass  clazz;
111
112
113    if ( (FT_UInt)(gindex - gnode->gindex) >= snode->count )
114    {
115      FT_ERROR(( "ftc_snode_load: invalid glyph index" ));
116      return FTC_Err_Invalid_Argument;
117    }
118
119    sbit  = snode->sbits + ( gindex - gnode->gindex );
120    clazz = (FTC_SFamilyClass)family->clazz;
121
122    sbit->buffer = 0;
123
124    error = clazz->family_load_glyph( family, gindex, manager, &face );
125    if ( error )
126      goto BadGlyph;
127
128    {
129      FT_Int        temp;
130      FT_GlyphSlot  slot   = face->glyph;
131      FT_Bitmap*    bitmap = &slot->bitmap;
132      FT_Int        xadvance, yadvance;
133
134
135      if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
136      {
137        FT_ERROR(( "%s: glyph loaded didn't return a bitmap!\n",
138                   "ftc_snode_load" ));
139        goto BadGlyph;
140      }
141
142      /* Check that our values fit into 8-bit containers!       */
143      /* If this is not the case, our bitmap is too large       */
144      /* and we will leave it as `missing' with sbit.buffer = 0 */
145
146#define CHECK_CHAR( d )  ( temp = (FT_Char)d, temp == d )
147#define CHECK_BYTE( d )  ( temp = (FT_Byte)d, temp == d )
148
149      /* horizontal advance in pixels */
150      xadvance = ( slot->advance.x + 32 ) >> 6;
151      yadvance = ( slot->advance.y + 32 ) >> 6;
152
153      if ( !CHECK_BYTE( bitmap->rows  )     ||
154           !CHECK_BYTE( bitmap->width )     ||
155           !CHECK_CHAR( bitmap->pitch )     ||
156           !CHECK_CHAR( slot->bitmap_left ) ||
157           !CHECK_CHAR( slot->bitmap_top  ) ||
158           !CHECK_CHAR( xadvance )          ||
159           !CHECK_CHAR( yadvance )          )
160        goto BadGlyph;
161
162      sbit->width     = (FT_Byte)bitmap->width;
163      sbit->height    = (FT_Byte)bitmap->rows;
164      sbit->pitch     = (FT_Char)bitmap->pitch;
165      sbit->left      = (FT_Char)slot->bitmap_left;
166      sbit->top       = (FT_Char)slot->bitmap_top;
167      sbit->xadvance  = (FT_Char)xadvance;
168      sbit->yadvance  = (FT_Char)yadvance;
169      sbit->format    = (FT_Byte)bitmap->pixel_mode;
170      sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1);
171
172      /* copy the bitmap into a new buffer -- ignore error */
173      error = ftc_sbit_copy_bitmap( sbit, bitmap, memory );
174
175      /* now, compute size */
176      if ( asize )
177        *asize = FT_ABS( sbit->pitch ) * sbit->height;
178
179    } /* glyph loading successful */
180
181    /* ignore the errors that might have occurred --   */
182    /* we mark unloaded glyphs with `sbit.buffer == 0' */
183    /* and `width == 255', `height == 0'               */
184    /*                                                 */
185    if ( error && error != FTC_Err_Out_Of_Memory )
186    {
187    BadGlyph:
188      sbit->width  = 255;
189      sbit->height = 0;
190      sbit->buffer = NULL;
191      error        = 0;
192      if ( asize )
193        *asize = 0;
194    }
195
196    return error;
197  }
198
199
200  FT_EXPORT_DEF( FT_Error )
201  FTC_SNode_New( FTC_SNode  *psnode,
202                 FTC_GQuery  gquery,
203                 FTC_Cache   cache )
204  {
205    FT_Memory   memory = cache->memory;
206    FT_Error    error;
207    FTC_SNode   snode  = NULL;
208    FT_UInt     gindex = gquery->gindex;
209    FTC_Family  family = gquery->family;
210
211    FTC_SFamilyClass  clazz = FTC_CACHE__SFAMILY_CLASS( cache );
212    FT_UInt           total;
213
214
215    total = clazz->family_get_count( family, cache->manager );
216    if ( total == 0 || gindex >= total )
217    {
218      error = FT_Err_Invalid_Argument;
219      goto Exit;
220    }
221
222    if ( !FT_NEW( snode ) )
223    {
224      FT_UInt  count, start;
225
226
227      start = gindex - ( gindex % FTC_SBIT_ITEMS_PER_NODE );
228      count = total - start;
229      if ( count > FTC_SBIT_ITEMS_PER_NODE )
230        count = FTC_SBIT_ITEMS_PER_NODE;
231
232      FTC_GNode_Init( FTC_GNODE( snode ), start, family );
233
234      snode->count = count;
235
236      error = ftc_snode_load( snode,
237                              cache->manager,
238                              gindex,
239                              NULL );
240      if ( error )
241      {
242        FTC_SNode_Free( snode, cache );
243        snode = NULL;
244      }
245    }
246
247  Exit:
248    *psnode = snode;
249    return error;
250  }
251
252
253  FT_LOCAL_DEF( FT_Error )
254  ftc_snode_new( FTC_Node   *ftcpsnode,
255                 FT_Pointer  ftcgquery,
256                 FTC_Cache   cache )
257  {
258    FTC_SNode  *psnode = (FTC_SNode*)ftcpsnode;
259    FTC_GQuery  gquery = (FTC_GQuery)ftcgquery;
260
261
262    return FTC_SNode_New( psnode, gquery, cache );
263  }
264
265
266  FT_LOCAL_DEF( FT_ULong )
267  ftc_snode_weight( FTC_Node   ftcsnode,
268                    FTC_Cache  cache )
269  {
270    FTC_SNode  snode = (FTC_SNode)ftcsnode;
271    FT_UInt    count = snode->count;
272    FTC_SBit   sbit  = snode->sbits;
273    FT_Int     pitch;
274    FT_ULong   size;
275
276    FT_UNUSED( cache );
277
278
279    FT_ASSERT( snode->count <= FTC_SBIT_ITEMS_PER_NODE );
280
281    /* the node itself */
282    size = sizeof ( *snode );
283
284    for ( ; count > 0; count--, sbit++ )
285    {
286      if ( sbit->buffer )
287      {
288        pitch = sbit->pitch;
289        if ( pitch < 0 )
290          pitch = -pitch;
291
292        /* add the size of a given glyph image */
293        size += pitch * sbit->height;
294      }
295    }
296
297    return size;
298  }
299
300
301  FT_EXPORT_DEF( FT_ULong )
302  FTC_SNode_Weight( FTC_SNode  snode )
303  {
304    return ftc_snode_weight( FTC_NODE( snode ), NULL );
305  }
306
307
308  FT_LOCAL_DEF( FT_Bool )
309  ftc_snode_compare( FTC_Node    ftcsnode,
310                     FT_Pointer  ftcgquery,
311                     FTC_Cache   cache )
312  {
313    FTC_SNode   snode  = (FTC_SNode)ftcsnode;
314    FTC_GQuery  gquery = (FTC_GQuery)ftcgquery;
315    FTC_GNode   gnode  = FTC_GNODE( snode );
316    FT_UInt     gindex = gquery->gindex;
317    FT_Bool     result;
318
319
320    result = FT_BOOL( gnode->family == gquery->family                    &&
321                      (FT_UInt)( gindex - gnode->gindex ) < snode->count );
322    if ( result )
323    {
324      /* check if we need to load the glyph bitmap now */
325      FTC_SBit  sbit = snode->sbits + ( gindex - gnode->gindex );
326
327
328      /*
329       *  The following code illustrates what to do when you want to
330       *  perform operations that may fail within a lookup function.
331       *
332       *  Here, we want to load a small bitmap on-demand; we thus
333       *  need to call the `ftc_snode_load' function which may return
334       *  a non-zero error code only when we are out of memory (OOM).
335       *
336       *  The correct thing to do is to use @FTC_CACHE_TRYLOOP and
337       *  @FTC_CACHE_TRYLOOP_END in order to implement a retry loop
338       *  that is capable of flushing the cache incrementally when
339       *  an OOM errors occur.
340       *
341       *  However, we need to `lock' the node before this operation to
342       *  prevent it from being flushed within the loop.
343       *
344       *  When we exit the loop, we unlock the node, then check the `error'
345       *  variable.  If it is non-zero, this means that the cache was
346       *  completely flushed and that no usable memory was found to load
347       *  the bitmap.
348       *
349       *  We then prefer to return a value of 0 (i.e., NO MATCH).  This
350       *  ensures that the caller will try to allocate a new node.
351       *  This operation consequently _fail_ and the lookup function
352       *  returns the appropriate OOM error code.
353       *
354       *  Note that `buffer == NULL && width == 255' is a hack used to
355       *  tag `unavailable' bitmaps in the array.  We should never try
356       *  to load these.
357       *
358       */
359
360      if ( sbit->buffer == NULL && sbit->width != 255 )
361      {
362        FT_ULong  size;
363        FT_Error  error;
364
365
366        ftcsnode->ref_count++;  /* lock node to prevent flushing */
367                                /* in retry loop                 */
368
369        FTC_CACHE_TRYLOOP( cache )
370        {
371          error = ftc_snode_load( snode, cache->manager, gindex, &size );
372        }
373        FTC_CACHE_TRYLOOP_END();
374
375        ftcsnode->ref_count--;  /* unlock the node */
376
377        if ( error )
378          result = 0;
379        else
380          cache->manager->cur_weight += size;
381      }
382    }
383
384    return result;
385  }
386
387
388  FT_EXPORT_DEF( FT_Bool )
389  FTC_SNode_Compare( FTC_SNode   snode,
390                     FTC_GQuery  gquery,
391                     FTC_Cache   cache )
392  {
393    return ftc_snode_compare( FTC_NODE( snode ), gquery, cache );
394  }
395
396
397/* END */
Note: See TracBrowser for help on using the repository browser.