misc/libfreetype/src/cache/ftcsbits.c
author Xeli
Sat, 04 Feb 2012 16:22:46 +0100
changeset 6622 01889d5bc79b
parent 5172 88f2e05288ba
permissions -rw-r--r--
Rewrote the Ammomenu: Added landscape ammomenu At the moment MOBILE indicates landscape, but we could just as easily make a variable out of it Draw to texture once uVariables.AmmoMenuInvalidated indicates a new ammo menu needs to be drawn, see uTeams and uAmmos Slot/Cellsize is dependent on uConsts.AMSlotSize this should make it easier to scale the ammo menu on smaller screens AmmoRect AmmoRect indicates where and how big the ammo menu is, this makes positioning a bit easier imo, because you only need to change the position at one single point needs testing on the iphone (and other systems as well ofcourse..)

/***************************************************************************/
/*                                                                         */
/*  ftcsbits.c                                                             */
/*                                                                         */
/*    FreeType sbits manager (body).                                       */
/*                                                                         */
/*  Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010, 2011 by */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used,       */
/*  modified, and distributed under the terms of the FreeType project      */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/


#include <ft2build.h>
#include FT_CACHE_H
#include "ftcsbits.h"
#include FT_INTERNAL_OBJECTS_H
#include FT_INTERNAL_DEBUG_H
#include FT_ERRORS_H

#include "ftccback.h"
#include "ftcerror.h"

#undef  FT_COMPONENT
#define FT_COMPONENT  trace_cache


  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****                     SBIT CACHE NODES                          *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/


  static FT_Error
  ftc_sbit_copy_bitmap( FTC_SBit    sbit,
                        FT_Bitmap*  bitmap,
                        FT_Memory   memory )
  {
    FT_Error  error;
    FT_Int    pitch = bitmap->pitch;
    FT_ULong  size;


    if ( pitch < 0 )
      pitch = -pitch;

    size = (FT_ULong)( pitch * bitmap->rows );

    if ( !FT_ALLOC( sbit->buffer, size ) )
      FT_MEM_COPY( sbit->buffer, bitmap->buffer, size );

    return error;
  }


  FT_LOCAL_DEF( void )
  ftc_snode_free( FTC_Node   ftcsnode,
                  FTC_Cache  cache )
  {
    FTC_SNode  snode  = (FTC_SNode)ftcsnode;
    FTC_SBit   sbit   = snode->sbits;
    FT_UInt    count  = snode->count;
    FT_Memory  memory = cache->memory;


    for ( ; count > 0; sbit++, count-- )
      FT_FREE( sbit->buffer );

    FTC_GNode_Done( FTC_GNODE( snode ), cache );

    FT_FREE( snode );
  }


  FT_LOCAL_DEF( void )
  FTC_SNode_Free( FTC_SNode  snode,
                  FTC_Cache  cache )
  {
    ftc_snode_free( FTC_NODE( snode ), cache );
  }


  /*
   *  This function tries to load a small bitmap within a given FTC_SNode.
   *  Note that it returns a non-zero error code _only_ in the case of
   *  out-of-memory condition.  For all other errors (e.g., corresponding
   *  to a bad font file), this function will mark the sbit as `unavailable'
   *  and return a value of 0.
   *
   *  You should also read the comment within the @ftc_snode_compare
   *  function below to see how out-of-memory is handled during a lookup.
   */
  static FT_Error
  ftc_snode_load( FTC_SNode    snode,
                  FTC_Manager  manager,
                  FT_UInt      gindex,
                  FT_ULong    *asize )
  {
    FT_Error          error;
    FTC_GNode         gnode  = FTC_GNODE( snode );
    FTC_Family        family = gnode->family;
    FT_Memory         memory = manager->memory;
    FT_Face           face;
    FTC_SBit          sbit;
    FTC_SFamilyClass  clazz;


    if ( (FT_UInt)(gindex - gnode->gindex) >= snode->count )
    {
      FT_ERROR(( "ftc_snode_load: invalid glyph index" ));
      return FTC_Err_Invalid_Argument;
    }

    sbit  = snode->sbits + ( gindex - gnode->gindex );
    clazz = (FTC_SFamilyClass)family->clazz;

    sbit->buffer = 0;

    error = clazz->family_load_glyph( family, gindex, manager, &face );
    if ( error )
      goto BadGlyph;

    {
      FT_Int        temp;
      FT_GlyphSlot  slot   = face->glyph;
      FT_Bitmap*    bitmap = &slot->bitmap;
      FT_Pos        xadvance, yadvance; /* FT_GlyphSlot->advance.{x|y} */


      if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
      {
        FT_TRACE0(( "ftc_snode_load:"
                    " glyph loaded didn't return a bitmap\n" ));
        goto BadGlyph;
      }

      /* Check that our values fit into 8-bit containers!       */
      /* If this is not the case, our bitmap is too large       */
      /* and we will leave it as `missing' with sbit.buffer = 0 */

#define CHECK_CHAR( d )  ( temp = (FT_Char)d, temp == d )
#define CHECK_BYTE( d )  ( temp = (FT_Byte)d, temp == d )

      /* horizontal advance in pixels */
      xadvance = ( slot->advance.x + 32 ) >> 6;
      yadvance = ( slot->advance.y + 32 ) >> 6;

      if ( !CHECK_BYTE( bitmap->rows  )     ||
           !CHECK_BYTE( bitmap->width )     ||
           !CHECK_CHAR( bitmap->pitch )     ||
           !CHECK_CHAR( slot->bitmap_left ) ||
           !CHECK_CHAR( slot->bitmap_top  ) ||
           !CHECK_CHAR( xadvance )          ||
           !CHECK_CHAR( yadvance )          )
      {
        FT_TRACE2(( "ftc_snode_load:"
                    " glyph too large for small bitmap cache\n"));
        goto BadGlyph;
      }

      sbit->width     = (FT_Byte)bitmap->width;
      sbit->height    = (FT_Byte)bitmap->rows;
      sbit->pitch     = (FT_Char)bitmap->pitch;
      sbit->left      = (FT_Char)slot->bitmap_left;
      sbit->top       = (FT_Char)slot->bitmap_top;
      sbit->xadvance  = (FT_Char)xadvance;
      sbit->yadvance  = (FT_Char)yadvance;
      sbit->format    = (FT_Byte)bitmap->pixel_mode;
      sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1);

      /* copy the bitmap into a new buffer -- ignore error */
      error = ftc_sbit_copy_bitmap( sbit, bitmap, memory );

      /* now, compute size */
      if ( asize )
        *asize = FT_ABS( sbit->pitch ) * sbit->height;

    } /* glyph loading successful */

    /* ignore the errors that might have occurred --   */
    /* we mark unloaded glyphs with `sbit.buffer == 0' */
    /* and `width == 255', `height == 0'               */
    /*                                                 */
    if ( error && error != FTC_Err_Out_Of_Memory )
    {
    BadGlyph:
      sbit->width  = 255;
      sbit->height = 0;
      sbit->buffer = NULL;
      error        = FTC_Err_Ok;
      if ( asize )
        *asize = 0;
    }

    return error;
  }


  FT_LOCAL_DEF( FT_Error )
  FTC_SNode_New( FTC_SNode  *psnode,
                 FTC_GQuery  gquery,
                 FTC_Cache   cache )
  {
    FT_Memory   memory = cache->memory;
    FT_Error    error;
    FTC_SNode   snode  = NULL;
    FT_UInt     gindex = gquery->gindex;
    FTC_Family  family = gquery->family;

    FTC_SFamilyClass  clazz = FTC_CACHE__SFAMILY_CLASS( cache );
    FT_UInt           total;
    FT_UInt           node_count;


    total = clazz->family_get_count( family, cache->manager );
    if ( total == 0 || gindex >= total )
    {
      error = FTC_Err_Invalid_Argument;
      goto Exit;
    }

    if ( !FT_NEW( snode ) )
    {
      FT_UInt  count, start;


      start = gindex - ( gindex % FTC_SBIT_ITEMS_PER_NODE );
      count = total - start;
      if ( count > FTC_SBIT_ITEMS_PER_NODE )
        count = FTC_SBIT_ITEMS_PER_NODE;

      FTC_GNode_Init( FTC_GNODE( snode ), start, family );

      snode->count = count;
      for ( node_count = 0; node_count < count; node_count++ )
      {
        snode->sbits[node_count].width = 255;
      }

      error = ftc_snode_load( snode,
                              cache->manager,
                              gindex,
                              NULL );
      if ( error )
      {
        FTC_SNode_Free( snode, cache );
        snode = NULL;
      }
    }

  Exit:
    *psnode = snode;
    return error;
  }


  FT_LOCAL_DEF( FT_Error )
  ftc_snode_new( FTC_Node   *ftcpsnode,
                 FT_Pointer  ftcgquery,
                 FTC_Cache   cache )
  {
    FTC_SNode  *psnode = (FTC_SNode*)ftcpsnode;
    FTC_GQuery  gquery = (FTC_GQuery)ftcgquery;


    return FTC_SNode_New( psnode, gquery, cache );
  }


  FT_LOCAL_DEF( FT_Offset )
  ftc_snode_weight( FTC_Node   ftcsnode,
                    FTC_Cache  cache )
  {
    FTC_SNode  snode = (FTC_SNode)ftcsnode;
    FT_UInt    count = snode->count;
    FTC_SBit   sbit  = snode->sbits;
    FT_Int     pitch;
    FT_Offset  size;

    FT_UNUSED( cache );


    FT_ASSERT( snode->count <= FTC_SBIT_ITEMS_PER_NODE );

    /* the node itself */
    size = sizeof ( *snode );

    for ( ; count > 0; count--, sbit++ )
    {
      if ( sbit->buffer )
      {
        pitch = sbit->pitch;
        if ( pitch < 0 )
          pitch = -pitch;

        /* add the size of a given glyph image */
        size += pitch * sbit->height;
      }
    }

    return size;
  }


#if 0

  FT_LOCAL_DEF( FT_Offset )
  FTC_SNode_Weight( FTC_SNode  snode )
  {
    return ftc_snode_weight( FTC_NODE( snode ), NULL );
  }

#endif /* 0 */


  FT_LOCAL_DEF( FT_Bool )
  ftc_snode_compare( FTC_Node    ftcsnode,
                     FT_Pointer  ftcgquery,
                     FTC_Cache   cache,
                     FT_Bool*    list_changed )
  {
    FTC_SNode   snode  = (FTC_SNode)ftcsnode;
    FTC_GQuery  gquery = (FTC_GQuery)ftcgquery;
    FTC_GNode   gnode  = FTC_GNODE( snode );
    FT_UInt     gindex = gquery->gindex;
    FT_Bool     result;


    if (list_changed)
      *list_changed = FALSE;
    result = FT_BOOL( gnode->family == gquery->family                    &&
                      (FT_UInt)( gindex - gnode->gindex ) < snode->count );
    if ( result )
    {
      /* check if we need to load the glyph bitmap now */
      FTC_SBit  sbit = snode->sbits + ( gindex - gnode->gindex );


      /*
       *  The following code illustrates what to do when you want to
       *  perform operations that may fail within a lookup function.
       *
       *  Here, we want to load a small bitmap on-demand; we thus
       *  need to call the `ftc_snode_load' function which may return
       *  a non-zero error code only when we are out of memory (OOM).
       *
       *  The correct thing to do is to use @FTC_CACHE_TRYLOOP and
       *  @FTC_CACHE_TRYLOOP_END in order to implement a retry loop
       *  that is capable of flushing the cache incrementally when
       *  an OOM errors occur.
       *
       *  However, we need to `lock' the node before this operation to
       *  prevent it from being flushed within the loop.
       *
       *  When we exit the loop, we unlock the node, then check the `error'
       *  variable.  If it is non-zero, this means that the cache was
       *  completely flushed and that no usable memory was found to load
       *  the bitmap.
       *
       *  We then prefer to return a value of 0 (i.e., NO MATCH).  This
       *  ensures that the caller will try to allocate a new node.
       *  This operation consequently _fail_ and the lookup function
       *  returns the appropriate OOM error code.
       *
       *  Note that `buffer == NULL && width == 255' is a hack used to
       *  tag `unavailable' bitmaps in the array.  We should never try
       *  to load these.
       *
       */

      if ( sbit->buffer == NULL && sbit->width == 255 )
      {
        FT_ULong  size;
        FT_Error  error;


        ftcsnode->ref_count++;  /* lock node to prevent flushing */
                                /* in retry loop                 */

        FTC_CACHE_TRYLOOP( cache )
        {
          error = ftc_snode_load( snode, cache->manager, gindex, &size );
        }
        FTC_CACHE_TRYLOOP_END( list_changed );

        ftcsnode->ref_count--;  /* unlock the node */

        if ( error )
          result = 0;
        else
          cache->manager->cur_weight += size;
      }
    }

    return result;
  }


#ifdef FTC_INLINE

  FT_LOCAL_DEF( FT_Bool )
  FTC_SNode_Compare( FTC_SNode   snode,
                     FTC_GQuery  gquery,
                     FTC_Cache   cache,
                     FT_Bool*    list_changed )
  {
    return ftc_snode_compare( FTC_NODE( snode ), gquery,
                              cache, list_changed );
  }

#endif

/* END */