Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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