/*******************************************************************
 *
 *  ftxwidth.c                                                  1.0
 *
 *    Glyph Widths (and Heights) fast retrieval extension
 *
 *  Copyright 1996-1999 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.
 *
 *
 *  This extension is used to parse the "glyf" table of a TrueType
 *  file in order to extract the bbox of a given range of glyphs.
 *
 *  The bbox is then used to build font unit widths and height
 *  that are returned in two parallel arrays.
 *
 *  This extension is needed by the FreeType/2 OS/2 Font Driver.
 *
 ******************************************************************/


#include "ftxwidth.h"
#include "ttdebug.h"
#include "ttobjs.h"
#include "ttfile.h"
#include "tttags.h"
#include "ttload.h"

/* Required by the tracing mode */

#undef  TT_COMPONENT
#define TT_COMPONENT  trace_any


  /******************************************************************/
  /*                                                                */
  /*  Function:  TT_Get_Face_Widths                                 */
  /*                                                                */
  /*  Description: Returns the widths and/or heights of a given     */
  /*               range of glyphs for a face.                      */
  /*                                                                */
  /*  Input:                                                        */
  /*     face        ::  face handle                                */
  /*                                                                */
  /*     first_glyph ::  first glyph in range                       */
  /*                                                                */
  /*     last_glyph  ::  last glyph in range                        */
  /*                                                                */
  /*     widths      ::  address of table receiving the widths      */
  /*                     expressed in font units (ushorts). Set     */
  /*                     this parameter to NULL if you're not       */
  /*                     interested by these values.                */
  /*                                                                */
  /*     heights     ::  address of table receiving the heights     */
  /*                     expressed in font units (ushorts).  Set    */
  /*                     this parameter to NULL if you're not       */
  /*                     interested by these values.                */
  /*                                                                */
  /*  Returns:                                                      */
  /*       Error code                                               */
  /*                                                                */
  /*                                                                */
  /******************************************************************/

  EXPORT_FUNC
  TT_Error  TT_Get_Face_Widths( TT_Face     face,
                                TT_UShort   first_glyph,
                                TT_UShort   last_glyph,
                                TT_UShort*  widths,
                                TT_UShort*  heights )
  {
    DEFINE_ALL_LOCALS;

    PFace     faze = HANDLE_Face(face);
    UShort    n;
    Long      table;

    ULong     glyf_offset;      /* offset of glyph table in file */
    UShort    zero_width  = 0;  /* width of glyph 0  */
    UShort    zero_height = 0;  /* height of glyph 0 */

    Bool      zero_loaded = 0;

#ifndef TT_HUGE_PTR
    PStorage  locations;
#else
    Storage TT_HUGE_PTR * locations;
#endif
    TT_BBox   bbox;


    if ( !faze )
      return TT_Err_Invalid_Face_Handle;

    if ( last_glyph >= faze->numGlyphs ||
         first_glyph > last_glyph      )
      return TT_Err_Invalid_Argument;

    /* find "glyf" table */
    table = TT_LookUp_Table( faze, TTAG_glyf );
    if ( table < 0 )
    {
      PERROR(( "ERROR: there is no glyph table in this font file!\n" ));
      return TT_Err_Glyf_Table_Missing;
    }
    glyf_offset = faze->dirTables[table].Offset;

    /* now access stream */
    if ( USE_Stream( faze->stream, stream ) )
      return error;

    locations = faze->glyphLocations + first_glyph;

    /* loop to load each glyph in the range */
    for ( n = first_glyph; n <= last_glyph; n++ )
    {
      if ( n + 1 < faze->numGlyphs &&
           locations[0] == locations[1] )
      {
        /* Note : Glyph 0 is always used to indicate a missing glyph   */
        /*        in a range. We must thus return its width and height */
        /*        where appropriate when we find an undefined glyph.   */
        if ( zero_loaded == 0 )
        {
          if ( FILE_Seek( glyf_offset + faze->glyphLocations[0] ) ||
               ACCESS_Frame( 10L ) )
            goto Fail;

          (void)GET_Short();   /* skip number of contours */

          bbox.xMin = GET_Short();
          bbox.yMin = GET_Short();
          bbox.xMax = GET_Short();
          bbox.yMax = GET_Short();

          FORGET_Frame();

          zero_width  = (UShort)(bbox.xMax - bbox.xMin);
          zero_height = (UShort)(bbox.yMax - bbox.yMin);
          zero_loaded = 1;
        }

        if ( widths )
          *widths++  = zero_width;

        if ( heights )
          *heights++ = zero_height;
      }
      else
      {
        /* normal glyph, read header */
        if ( FILE_Seek( glyf_offset + locations[0] ) ||
             ACCESS_Frame( 10L ) )
          goto Fail;

        (void)GET_Short();  /* skip number of contours */

        bbox.xMin = GET_Short();
        bbox.yMin = GET_Short();
        bbox.xMax = GET_Short();
        bbox.yMax = GET_Short();

        FORGET_Frame();

        if ( widths )
          *widths++  = (UShort)(bbox.xMax - bbox.xMin);

        if ( heights )
          *heights++ = (UShort)(bbox.yMax - bbox.yMin);
      }
    }

  Fail:
    DONE_Stream( stream );
    return error;
  }


/* END */
