Edit

kc3-lang/freetype/src/pfr/pfrsbit.c

Branch :

  • Show log

    Commit

  • Author : Werner Lemberg
    Date : 2010-06-24 10:34:29
    Hash : f765e440
    Message : */*: Use module specific error names where appropriate.

  • src/pfr/pfrsbit.c
  • /***************************************************************************/
    /*                                                                         */
    /*  pfrsbit.c                                                              */
    /*                                                                         */
    /*    FreeType PFR bitmap loader (body).                                   */
    /*                                                                         */
    /*  Copyright 2002, 2003, 2006, 2009, 2010 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 "pfrsbit.h"
    #include "pfrload.h"
    #include FT_INTERNAL_DEBUG_H
    #include FT_INTERNAL_STREAM_H
    
    #include "pfrerror.h"
    
    #undef  FT_COMPONENT
    #define FT_COMPONENT  trace_pfr
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                      PFR BIT WRITER                           *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
      typedef struct  PFR_BitWriter_
      {
        FT_Byte*  line;      /* current line start                    */
        FT_Int    pitch;     /* line size in bytes                    */
        FT_Int    width;     /* width in pixels/bits                  */
        FT_Int    rows;      /* number of remaining rows to scan      */
        FT_Int    total;     /* total number of bits to draw          */
    
      } PFR_BitWriterRec, *PFR_BitWriter;
    
    
      static void
      pfr_bitwriter_init( PFR_BitWriter  writer,
                          FT_Bitmap*     target,
                          FT_Bool        decreasing )
      {
        writer->line   = target->buffer;
        writer->pitch  = target->pitch;
        writer->width  = target->width;
        writer->rows   = target->rows;
        writer->total  = writer->width * writer->rows;
    
        if ( !decreasing )
        {
          writer->line += writer->pitch * ( target->rows-1 );
          writer->pitch = -writer->pitch;
        }
      }
    
    
      static void
      pfr_bitwriter_decode_bytes( PFR_BitWriter  writer,
                                  FT_Byte*       p,
                                  FT_Byte*       limit )
      {
        FT_Int    n, reload;
        FT_Int    left = writer->width;
        FT_Byte*  cur  = writer->line;
        FT_UInt   mask = 0x80;
        FT_UInt   val  = 0;
        FT_UInt   c    = 0;
    
    
        n = (FT_Int)( limit - p ) * 8;
        if ( n > writer->total )
          n = writer->total;
    
        reload = n & 7;
    
        for ( ; n > 0; n-- )
        {
          if ( ( n & 7 ) == reload )
            val = *p++;
    
          if ( val & 0x80 )
            c |= mask;
    
          val  <<= 1;
          mask >>= 1;
    
          if ( --left <= 0 )
          {
            cur[0] = (FT_Byte)c;
            left   = writer->width;
            mask   = 0x80;
    
            writer->line += writer->pitch;
            cur           = writer->line;
            c             = 0;
          }
          else if ( mask == 0 )
          {
            cur[0] = (FT_Byte)c;
            mask   = 0x80;
            c      = 0;
            cur ++;
          }
        }
    
        if ( mask != 0x80 )
          cur[0] = (FT_Byte)c;
      }
    
    
      static void
      pfr_bitwriter_decode_rle1( PFR_BitWriter  writer,
                                 FT_Byte*       p,
                                 FT_Byte*       limit )
      {
        FT_Int    n, phase, count, counts[2], reload;
        FT_Int    left = writer->width;
        FT_Byte*  cur  = writer->line;
        FT_UInt   mask = 0x80;
        FT_UInt   c    = 0;
    
    
        n = writer->total;
    
        phase     = 1;
        counts[0] = 0;
        counts[1] = 0;
        count     = 0;
        reload    = 1;
    
        for ( ; n > 0; n-- )
        {
          if ( reload )
          {
            do
            {
              if ( phase )
              {
                FT_Int  v;
    
    
                if ( p >= limit )
                  break;
    
                v         = *p++;
                counts[0] = v >> 4;
                counts[1] = v & 15;
                phase     = 0;
                count     = counts[0];
              }
              else
              {
                phase = 1;
                count = counts[1];
              }
    
            } while ( count == 0 );
          }
    
          if ( phase )
            c |= mask;
    
          mask >>= 1;
    
          if ( --left <= 0 )
          {
            cur[0] = (FT_Byte) c;
            left   = writer->width;
            mask   = 0x80;
    
            writer->line += writer->pitch;
            cur           = writer->line;
            c             = 0;
          }
          else if ( mask == 0 )
          {
            cur[0] = (FT_Byte)c;
            mask   = 0x80;
            c      = 0;
            cur ++;
          }
    
          reload = ( --count <= 0 );
        }
    
        if ( mask != 0x80 )
          cur[0] = (FT_Byte) c;
      }
    
    
      static void
      pfr_bitwriter_decode_rle2( PFR_BitWriter  writer,
                                 FT_Byte*       p,
                                 FT_Byte*       limit )
      {
        FT_Int    n, phase, count, reload;
        FT_Int    left = writer->width;
        FT_Byte*  cur  = writer->line;
        FT_UInt   mask = 0x80;
        FT_UInt   c    = 0;
    
    
        n = writer->total;
    
        phase  = 1;
        count  = 0;
        reload = 1;
    
        for ( ; n > 0; n-- )
        {
          if ( reload )
          {
            do
            {
              if ( p >= limit )
                break;
    
              count = *p++;
              phase = phase ^ 1;
    
            } while ( count == 0 );
          }
    
          if ( phase )
            c |= mask;
    
          mask >>= 1;
    
          if ( --left <= 0 )
          {
            cur[0] = (FT_Byte) c;
            c      = 0;
            mask   = 0x80;
            left   = writer->width;
    
            writer->line += writer->pitch;
            cur           = writer->line;
          }
          else if ( mask == 0 )
          {
            cur[0] = (FT_Byte)c;
            c      = 0;
            mask   = 0x80;
            cur ++;
          }
    
          reload = ( --count <= 0 );
        }
    
        if ( mask != 0x80 )
          cur[0] = (FT_Byte) c;
      }
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                  BITMAP DATA DECODING                         *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
      static void
      pfr_lookup_bitmap_data( FT_Byte*   base,
                              FT_Byte*   limit,
                              FT_UInt    count,
                              FT_UInt    flags,
                              FT_UInt    char_code,
                              FT_ULong*  found_offset,
                              FT_ULong*  found_size )
      {
        FT_UInt   left, right, char_len;
        FT_Bool   two = FT_BOOL( flags & 1 );
        FT_Byte*  buff;
    
    
        char_len = 4;
        if ( two )       char_len += 1;
        if ( flags & 2 ) char_len += 1;
        if ( flags & 4 ) char_len += 1;
    
        left  = 0;
        right = count;
    
        while ( left < right )
        {
          FT_UInt  middle, code;
    
    
          middle = ( left + right ) >> 1;
          buff   = base + middle * char_len;
    
          /* check that we are not outside of the table -- */
          /* this is possible with broken fonts...         */
          if ( buff + char_len > limit )
            goto Fail;
    
          if ( two )
            code = PFR_NEXT_USHORT( buff );
          else
            code = PFR_NEXT_BYTE( buff );
    
          if ( code == char_code )
            goto Found_It;
    
          if ( code < char_code )
            left = middle;
          else
            right = middle;
        }
    
      Fail:
        /* Not found */
        *found_size   = 0;
        *found_offset = 0;
        return;
    
      Found_It:
        if ( flags & 2 )
          *found_size = PFR_NEXT_USHORT( buff );
        else
          *found_size = PFR_NEXT_BYTE( buff );
    
        if ( flags & 4 )
          *found_offset = PFR_NEXT_ULONG( buff );
        else
          *found_offset = PFR_NEXT_USHORT( buff );
      }
    
    
      /* load bitmap metrics.  "*padvance" must be set to the default value */
      /* before calling this function...                                    */
      /*                                                                    */
      static FT_Error
      pfr_load_bitmap_metrics( FT_Byte**  pdata,
                               FT_Byte*   limit,
                               FT_Long    scaled_advance,
                               FT_Long   *axpos,
                               FT_Long   *aypos,
                               FT_UInt   *axsize,
                               FT_UInt   *aysize,
                               FT_Long   *aadvance,
                               FT_UInt   *aformat )
      {
        FT_Error  error = PFR_Err_Ok;
        FT_Byte   flags;
        FT_Char   b;
        FT_Byte*  p = *pdata;
        FT_Long   xpos, ypos, advance;
        FT_UInt   xsize, ysize;
    
    
        PFR_CHECK( 1 );
        flags = PFR_NEXT_BYTE( p );
    
        xpos    = 0;
        ypos    = 0;
        xsize   = 0;
        ysize   = 0;
        advance = 0;
    
        switch ( flags & 3 )
        {
        case 0:
          PFR_CHECK( 1 );
          b    = PFR_NEXT_INT8( p );
          xpos = b >> 4;
          ypos = ( (FT_Char)( b << 4 ) ) >> 4;
          break;
    
        case 1:
          PFR_CHECK( 2 );
          xpos = PFR_NEXT_INT8( p );
          ypos = PFR_NEXT_INT8( p );
          break;
    
        case 2:
          PFR_CHECK( 4 );
          xpos = PFR_NEXT_SHORT( p );
          ypos = PFR_NEXT_SHORT( p );
          break;
    
        case 3:
          PFR_CHECK( 6 );
          xpos = PFR_NEXT_LONG( p );
          ypos = PFR_NEXT_LONG( p );
          break;
    
        default:
          ;
        }
    
        flags >>= 2;
        switch ( flags & 3 )
        {
        case 0:
          /* blank image */
          xsize = 0;
          ysize = 0;
          break;
    
        case 1:
          PFR_CHECK( 1 );
          b     = PFR_NEXT_BYTE( p );
          xsize = ( b >> 4 ) & 0xF;
          ysize = b & 0xF;
          break;
    
        case 2:
          PFR_CHECK( 2 );
          xsize = PFR_NEXT_BYTE( p );
          ysize = PFR_NEXT_BYTE( p );
          break;
    
        case 3:
          PFR_CHECK( 4 );
          xsize = PFR_NEXT_USHORT( p );
          ysize = PFR_NEXT_USHORT( p );
          break;
    
        default:
          ;
        }
    
        flags >>= 2;
        switch ( flags & 3 )
        {
        case 0:
          advance = scaled_advance;
          break;
    
        case 1:
          PFR_CHECK( 1 );
          advance = PFR_NEXT_INT8( p ) << 8;
          break;
    
        case 2:
          PFR_CHECK( 2 );
          advance = PFR_NEXT_SHORT( p );
          break;
    
        case 3:
          PFR_CHECK( 3 );
          advance = PFR_NEXT_LONG( p );
          break;
    
        default:
          ;
        }
    
        *axpos    = xpos;
        *aypos    = ypos;
        *axsize   = xsize;
        *aysize   = ysize;
        *aadvance = advance;
        *aformat  = flags >> 2;
        *pdata    = p;
    
      Exit:
        return error;
    
      Too_Short:
        error = PFR_Err_Invalid_Table;
        FT_ERROR(( "pfr_load_bitmap_metrics: invalid glyph data\n" ));
        goto Exit;
      }
    
    
      static FT_Error
      pfr_load_bitmap_bits( FT_Byte*    p,
                            FT_Byte*    limit,
                            FT_UInt     format,
                            FT_Bool     decreasing,
                            FT_Bitmap*  target )
      {
        FT_Error          error = PFR_Err_Ok;
        PFR_BitWriterRec  writer;
    
    
        if ( target->rows > 0 && target->width > 0 )
        {
          pfr_bitwriter_init( &writer, target, decreasing );
    
          switch ( format )
          {
          case 0: /* packed bits */
            pfr_bitwriter_decode_bytes( &writer, p, limit );
            break;
    
          case 1: /* RLE1 */
            pfr_bitwriter_decode_rle1( &writer, p, limit );
            break;
    
          case 2: /* RLE2 */
            pfr_bitwriter_decode_rle2( &writer, p, limit );
            break;
    
          default:
            FT_ERROR(( "pfr_read_bitmap_data: invalid image type\n" ));
            error = PFR_Err_Invalid_File_Format;
          }
        }
    
        return error;
      }
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                     BITMAP LOADING                            *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
      FT_LOCAL( FT_Error )
      pfr_slot_load_bitmap( PFR_Slot  glyph,
                            PFR_Size  size,
                            FT_UInt   glyph_index )
      {
        FT_Error     error;
        PFR_Face     face   = (PFR_Face) glyph->root.face;
        FT_Stream    stream = face->root.stream;
        PFR_PhyFont  phys   = &face->phy_font;
        FT_ULong     gps_offset;
        FT_ULong     gps_size;
        PFR_Char     character;
        PFR_Strike   strike;
    
    
        character = &phys->chars[glyph_index];
    
        /* Look-up a bitmap strike corresponding to the current */
        /* character dimensions                                 */
        {
          FT_UInt  n;
    
    
          strike = phys->strikes;
          for ( n = 0; n < phys->num_strikes; n++ )
          {
            if ( strike->x_ppm == (FT_UInt)size->root.metrics.x_ppem &&
                 strike->y_ppm == (FT_UInt)size->root.metrics.y_ppem )
            {
              goto Found_Strike;
            }
    
            strike++;
          }
    
          /* couldn't find it */
          return PFR_Err_Invalid_Argument;
        }
    
      Found_Strike:
    
        /* Now lookup the glyph's position within the file */
        {
          FT_UInt  char_len;
    
    
          char_len = 4;
          if ( strike->flags & 1 ) char_len += 1;
          if ( strike->flags & 2 ) char_len += 1;
          if ( strike->flags & 4 ) char_len += 1;
    
          /* Access data directly in the frame to speed lookups */
          if ( FT_STREAM_SEEK( phys->bct_offset + strike->bct_offset ) ||
               FT_FRAME_ENTER( char_len * strike->num_bitmaps )        )
            goto Exit;
    
          pfr_lookup_bitmap_data( stream->cursor,
                                  stream->limit,
                                  strike->num_bitmaps,
                                  strike->flags,
                                  character->char_code,
                                  &gps_offset,
                                  &gps_size );
    
          FT_FRAME_EXIT();
    
          if ( gps_size == 0 )
          {
            /* Could not find a bitmap program string for this glyph */
            error = PFR_Err_Invalid_Argument;
            goto Exit;
          }
        }
    
        /* get the bitmap metrics */
        {
          FT_Long   xpos = 0, ypos = 0, advance = 0;
          FT_UInt   xsize = 0, ysize = 0, format = 0;
          FT_Byte*  p;
    
    
          /* compute linear advance */
          advance = character->advance;
          if ( phys->metrics_resolution != phys->outline_resolution )
            advance = FT_MulDiv( advance,
                                 phys->outline_resolution,
                                 phys->metrics_resolution );
    
          glyph->root.linearHoriAdvance = advance;
    
          /* compute default advance, i.e., scaled advance.  This can be */
          /* overridden in the bitmap header of certain glyphs.          */
          advance = FT_MulDiv( (FT_Fixed)size->root.metrics.x_ppem << 8,
                               character->advance,
                               phys->metrics_resolution );
    
          if ( FT_STREAM_SEEK( face->header.gps_section_offset + gps_offset ) ||
               FT_FRAME_ENTER( gps_size )                                     )
            goto Exit;
    
          p     = stream->cursor;
          error = pfr_load_bitmap_metrics( &p, stream->limit,
                                           advance,
                                           &xpos, &ypos,
                                           &xsize, &ysize,
                                           &advance, &format );
    
          /*
           * XXX: on 16bit system, we return an error for huge bitmap
           *      which causes a size truncation, because truncated
           *      size properties makes bitmap glyph broken.
           */
          if ( xpos > FT_INT_MAX || ( ypos + ysize ) > FT_INT_MAX )
          {
            FT_TRACE1(( "pfr_slot_load_bitmap:" ));
            FT_TRACE1(( "huge bitmap glyph %dx%d over FT_GlyphSlot\n",
                         xpos, ypos ));
            error = PFR_Err_Invalid_Pixel_Size;
          }
    
          if ( !error )
          {
            glyph->root.format = FT_GLYPH_FORMAT_BITMAP;
    
            /* Set up glyph bitmap and metrics */
    
            /* XXX: needs casts to fit FT_Bitmap.{width|rows|pitch} */
            glyph->root.bitmap.width      = (FT_Int)xsize;
            glyph->root.bitmap.rows       = (FT_Int)ysize;
            glyph->root.bitmap.pitch      = (FT_Int)( xsize + 7 ) >> 3;
            glyph->root.bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
    
            /* XXX: needs casts to fit FT_Glyph_Metrics.{width|height} */
            glyph->root.metrics.width        = (FT_Pos)xsize << 6;
            glyph->root.metrics.height       = (FT_Pos)ysize << 6;
            glyph->root.metrics.horiBearingX = xpos << 6;
            glyph->root.metrics.horiBearingY = ypos << 6;
            glyph->root.metrics.horiAdvance  = FT_PIX_ROUND( ( advance >> 2 ) );
            glyph->root.metrics.vertBearingX = - glyph->root.metrics.width >> 1;
            glyph->root.metrics.vertBearingY = 0;
            glyph->root.metrics.vertAdvance  = size->root.metrics.height;
    
            /* XXX: needs casts fit FT_GlyphSlotRec.bitmap_{left|top} */
            glyph->root.bitmap_left = (FT_Int)xpos;
            glyph->root.bitmap_top  = (FT_Int)(ypos + ysize);
    
            /* Allocate and read bitmap data */
            {
              FT_ULong  len = glyph->root.bitmap.pitch * ysize;
    
    
              error = ft_glyphslot_alloc_bitmap( &glyph->root, len );
              if ( !error )
              {
                error = pfr_load_bitmap_bits(
                          p,
                          stream->limit,
                          format,
                          FT_BOOL(face->header.color_flags & 2),
                          &glyph->root.bitmap );
              }
            }
          }
    
          FT_FRAME_EXIT();
        }
    
      Exit:
        return error;
      }
    
    /* END */