home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: SysTools / SysTools.zip / ft-beta.zip / freetype / lib / extend / ttkern.c < prev    next >
C/C++ Source or Header  |  1997-10-06  |  14KB  |  505 lines

  1. /*******************************************************************
  2.  *
  3.  *  ttkern.c                                                     1.0
  4.  *
  5.  *    Kerning support extension.            
  6.  *
  7.  *  Copyright 1996, 1997 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.  *  The kerning support is currently part of the engine extensions.
  18.  *
  19.  ******************************************************************/
  20.  
  21. #include "freetype.h"
  22.  
  23. #include "ttextend.h"
  24.  
  25. #include "tttypes.h"
  26. #include "tterror.h"
  27. #include "ttmemory.h"
  28. #include "ttfile.h"
  29. #include "ttobjs.h"
  30. #include "ttload.h"  /* For the macros */
  31. #include "tttags.h"
  32.  
  33. #include "ttkern.h"
  34.  
  35. /*******************************************************************
  36.  *
  37.  *  Function    :  SubTable_Load_0
  38.  *
  39.  *  Description :  Loads a format 0 kerning subtable data
  40.  *
  41.  *  Input  :  kern0   pointer to the kerning subtable
  42.  *
  43.  *  Output :  error code
  44.  *
  45.  *  Notes  :  - Assumes that the stream is already 'used'
  46.  *
  47.  *            - the file cursor must be set by the caller
  48.  *
  49.  *            - in case of error, the function _must_ destroy
  50.  *              the data it allocates !!
  51.  *
  52.  ******************************************************************/
  53.  
  54.   static TT_Error  Subtable_Load_0( TT_Kern_0*  kern0,
  55.                                     TT_Stream   input )
  56.   {
  57.     DEFINE_LOAD_LOCALS(input);
  58.  
  59.     int num_pairs, n;
  60.  
  61.     if ( ACCESS_Frame( 8 ) )
  62.       return error;
  63.  
  64.     num_pairs            = GET_UShort();
  65.     kern0->nPairs        = 0;
  66.     kern0->searchRange   = GET_UShort();
  67.     kern0->entrySelector = GET_UShort();
  68.     kern0->rangeShift    = GET_UShort();
  69.  
  70.     /* we only set kern0->nPairs when the subtable has been loaded */
  71.  
  72.     FORGET_Frame();
  73.  
  74.     if ( ALLOC_ARRAY( kern0->pairs, num_pairs, TT_Kern_0_Pair ) )
  75.       return error;
  76.  
  77.     if ( ACCESS_Frame( num_pairs * 2L ) )
  78.       goto Fail;
  79.  
  80.     for ( n = 0; n < num_pairs; n++ )
  81.     {
  82.       kern0->pairs[n].left  = GET_UShort();
  83.       kern0->pairs[n].right = GET_UShort();
  84.       kern0->pairs[n].value = GET_UShort();
  85.     }
  86.  
  87.     FORGET_Frame();
  88.  
  89.     /* we're ok, set the pairs count */
  90.     kern0->nPairs = num_pairs;
  91.  
  92.     return TT_Err_Ok;
  93.  
  94.     Fail:
  95.       FREE( kern0->pairs );
  96.       return error;
  97.   }
  98.  
  99. /*******************************************************************
  100.  *
  101.  *  Function    :  SubTable_Load_2
  102.  *
  103.  *  Description :  Loads a format 2 kerning subtable data
  104.  *
  105.  *  Input  :  kern2   pointer to the kerning subtable
  106.  *            length  subtable length. This is required as
  107.  *                    the subheader doesn't give any indication
  108.  *                    of the size of the 'array' table.
  109.  *
  110.  *  Output :  error code
  111.  *
  112.  *  Notes  :  - Assumes that the stream is already 'used'
  113.  *
  114.  *            - the file cursor must be set by the caller
  115.  *
  116.  *            - in case of error, the function _must_ destroy
  117.  *              the data it allocates !!
  118.  *
  119.  ******************************************************************/
  120.  
  121.   static TT_Error  Subtable_Load_2( TT_Kern_2*  kern2,
  122.                                     TT_Stream   input )
  123.   {
  124.     DEFINE_LOAD_LOCALS(input);
  125.  
  126.     long  table_base;
  127.  
  128.     int left_offset, right_offset, array_offset, array_size;
  129.     int left_max, right_max, n;
  130.  
  131.     /* record the table offset */
  132.     table_base = FILE_Pos();
  133.     
  134.     if ( ACCESS_Frame( 8 ) )
  135.       return error;
  136.  
  137.     kern2->rowWidth = GET_UShort();
  138.     left_offset     = GET_UShort();
  139.     right_offset    = GET_UShort();
  140.     array_offset    = GET_UShort();
  141.  
  142.     FORGET_Frame();
  143.  
  144.     /* first load left and right glyph classes */
  145.  
  146.     if ( FILE_Seek( table_base + left_offset ) ||
  147.          ACCESS_Frame( 4 ) )
  148.       return error;
  149.  
  150.     kern2->leftClass.firstGlyph = GET_UShort();
  151.     kern2->leftClass.nGlyphs    = GET_UShort();
  152.  
  153.     FORGET_Frame();
  154.  
  155.     if ( ALLOC_ARRAY( kern2->leftClass.classes, 
  156.                       kern2->leftClass.nGlyphs,
  157.                       Short ) )
  158.       return error;
  159.  
  160.     /* load left offsets */
  161.  
  162.     if ( ACCESS_Frame( kern2->leftClass.nGlyphs * 2 ) )
  163.       goto Fail_Left;
  164.  
  165.     for ( n = 0; n < kern2->leftClass.nGlyphs; n++ )
  166.       kern2->leftClass.classes[n] = GET_UShort();
  167.  
  168.     FORGET_Frame();
  169.  
  170.     /* right class */
  171.  
  172.     if ( FILE_Seek( table_base + right_offset ) ||
  173.          ACCESS_Frame( 4 ) )
  174.       goto Fail_Left;
  175.  
  176.     kern2->rightClass.firstGlyph = GET_UShort();
  177.     kern2->rightClass.nGlyphs    = GET_UShort();
  178.  
  179.     FORGET_Frame();
  180.  
  181.     if ( ALLOC_ARRAY( kern2->rightClass.classes,
  182.                       kern2->rightClass.nGlyphs,
  183.                       Short ) )
  184.       goto Fail_Left;
  185.  
  186.     /* load right offsets */
  187.  
  188.     if ( ACCESS_Frame( kern2->rightClass.nGlyphs*2L ) )
  189.       goto Fail_Right;
  190.  
  191.     for ( n = 0; n < kern2->rightClass.nGlyphs; n++ )
  192.       kern2->rightClass.classes[n] = GET_UShort();
  193.  
  194.     FORGET_Frame();
  195.  
  196.     /* now load the kerning array. We don't have its size, we */
  197.     /* must thus compute it from what we now..                */
  198.  
  199.     /* we thus compute the maximum left and right offsets and */
  200.     /* add them to get the array size                         */
  201.  
  202.     left_max = right_max = 0;
  203.  
  204.     for ( n = 0; n < kern2->leftClass.nGlyphs; n++ )
  205.       left_max = MAX( left_max, kern2->leftClass.classes[n] );
  206.  
  207.     for ( n = 0; n < kern2->rightClass.nGlyphs; n++ )
  208.       right_max = MAX( right_max, kern2->leftClass.classes[n] );
  209.  
  210.     array_size = left_max + right_max + 2;
  211.  
  212.     if ( ALLOC( kern2->array, array_size ) )
  213.       goto Fail_Right;
  214.  
  215.     if ( ACCESS_Frame( array_size ) )
  216.       goto Fail_Array;
  217.  
  218.     for ( n = 0; n < array_size/2; n++ )
  219.       kern2->array[n] = GET_UShort();
  220.  
  221.     FORGET_Frame();
  222.  
  223.     /* we're good now */
  224.  
  225.     return TT_Err_Ok;
  226.  
  227.   Fail_Array:
  228.     FREE( kern2->array );
  229.  
  230.   Fail_Right:
  231.     FREE( kern2->rightClass.classes );
  232.     kern2->rightClass.nGlyphs = 0;
  233.  
  234.   Fail_Left:
  235.     FREE( kern2->leftClass.classes );
  236.     kern2->leftClass.nGlyphs = 0;
  237.  
  238.     return error;
  239.   }
  240.  
  241. /*******************************************************************
  242.  *
  243.  *  Function    :  Kerning_Create
  244.  *
  245.  *  Description :  Create the kerning directory when a face is
  246.  *                 loaded. The tables however are loaded on
  247.  *                 demand to save space.
  248.  *
  249.  *  Input  :  face    pointeur to the parent face object
  250.  *            kern    pointeur to the extension's kerning field  
  251.  *
  252.  *  Output :  error code
  253.  *
  254.  *  Notes  :  as in all constructors, the memory allocated isn't
  255.  *            released in case of failure. Rather, the task is left
  256.  *            to the destructor (which is called when an error
  257.  *            occurs during the loading of a face).
  258.  *
  259.  ******************************************************************/
  260.  
  261.   TT_Error  Kerning_Create( PFace        face,
  262.                             TT_Kerning*  kern )
  263.   {
  264.     DEFINE_LOAD_LOCALS(face->stream);
  265.  
  266.     int  table, num_tables;
  267.  
  268.     TT_Kern_Subtable*  sub;
  269.  
  270.     /* by convention */
  271.     if (!kern)
  272.       return TT_Err_Ok;
  273.  
  274.     /* Now load the kerning directory. We're called from the face */
  275.     /* constructor. We thus need not using the stream             */
  276.  
  277.     kern->version = 0;
  278.     kern->nTables = 0;
  279.     kern->tables  = NULL;
  280.  
  281.     table = LookUp_TrueType_Table( face, TTAG_kern );
  282.     if (table < 0)
  283.       return TT_Err_Ok;  /* The table is optional */
  284.  
  285.     if ( FILE_Seek( face->dirTables[table].Offset ) ||
  286.          ACCESS_Frame( 4 ) )
  287.       return error;
  288.  
  289.     kern->version = GET_Short();
  290.     num_tables    = GET_Short();
  291.  
  292.     FORGET_Frame();
  293.  
  294.     /* we don't set kern->nTables until we have allocated the array */
  295.  
  296.     if ( ALLOC_ARRAY( kern->tables, num_tables, TT_Kern_Subtable ) )
  297.       return error;
  298.  
  299.     kern->nTables = num_tables;
  300.  
  301.     /* now load the directory entries, but do _not_ load the tables ! */
  302.  
  303.     sub = kern->tables;
  304.  
  305.     for ( table = 0; table < num_tables; table++ )
  306.     {
  307.       if ( ACCESS_Frame( 6 ) )
  308.         return error;
  309.  
  310.       sub->loaded   = FALSE;             /* redundant, but good to see */
  311.       sub->version  = GET_UShort();
  312.       sub->length   = GET_UShort() - 6;  /* substract header length */
  313.       sub->format   = GET_Byte();
  314.       sub->coverage = GET_Byte();
  315.  
  316.       FORGET_Frame();
  317.  
  318.       sub->offset = FILE_Pos();
  319.  
  320.       /* now skip to the next table */
  321.  
  322.       if ( FILE_Skip( sub->length ) )
  323.         return error;
  324.  
  325.       sub++;
  326.     }
  327.  
  328.     /* that's fine, leave now */
  329.  
  330.     return TT_Err_Ok;
  331.   }
  332.  
  333. /*******************************************************************
  334.  *
  335.  *  Function    :  Kerning_Destroy
  336.  *
  337.  *  Description :  Destroy all kerning information
  338.  *
  339.  *  Input  :  kern   pointer to the extension's kerning field
  340.  *
  341.  *  Output :  error code
  342.  *
  343.  *  Notes  :  This function is a destructor, it must be able
  344.  *            to destroy partially built tables.
  345.  *
  346.  ******************************************************************/
  347.  
  348.   TT_Error  Kerning_Destroy( TT_Kerning*  kern )
  349.   {
  350.     TT_Kern_Subtable*  sub;
  351.     int  n;
  352.  
  353.     /* by convention */
  354.     if (!kern)
  355.       return TT_Err_Ok;
  356.  
  357.     if (kern->nTables == 0)
  358.       return TT_Err_Ok;      /* no tables to release */
  359.  
  360.     /* scan the table directory and release loaded entries */
  361.  
  362.     sub = kern->tables;
  363.     for ( n = 0; n < kern->nTables; n++ )
  364.     {
  365.       if ( sub->loaded )
  366.       {
  367.         switch (sub->format)
  368.         {
  369.           case 0:
  370.             FREE( sub->t.kern0.pairs );
  371.             sub->t.kern0.nPairs        = 0;
  372.             sub->t.kern0.searchRange   = 0;
  373.             sub->t.kern0.entrySelector = 0;
  374.             sub->t.kern0.rangeShift    = 0;
  375.             break;
  376.  
  377.           case 2:
  378.             FREE( sub->t.kern2.leftClass.classes );
  379.             sub->t.kern2.leftClass.firstGlyph = 0;
  380.             sub->t.kern2.leftClass.nGlyphs    = 0;
  381.  
  382.             FREE( sub->t.kern2.rightClass.classes );
  383.             sub->t.kern2.rightClass.firstGlyph = 0;
  384.             sub->t.kern2.rightClass.nGlyphs    = 0;
  385.  
  386.             FREE( sub->t.kern2.array );
  387.             sub->t.kern2.rowWidth = 0;
  388.             break;
  389.  
  390.           default:
  391.             ;       /* invalid subtable format - do nothing */
  392.         }
  393.  
  394.         sub->loaded   = FALSE;
  395.         sub->version  = 0;
  396.         sub->offset   = 0;
  397.         sub->length   = 0;
  398.         sub->coverage = 0;
  399.         sub->format   = 0;
  400.       }
  401.       sub++;
  402.     }
  403.  
  404.     FREE( kern->tables );
  405.     kern->nTables = 0;
  406.  
  407.     return TT_Err_Ok;
  408.   }
  409.  
  410. /*******************************************************************
  411.  *
  412.  *  Function    :  TT_Get_Kerning_Directory
  413.  *
  414.  *  Description :  Returns a given face's kerning directory
  415.  *
  416.  *  Input  :  face       handle to the face object
  417.  *            directory  pointer to client's target directory
  418.  *
  419.  *  Output :  error code
  420.  *
  421.  *  Notes  :  The kerning table directory is loaded with the face
  422.  *            through the extension constructor. However, the kerning
  423.  *            tables themselves are only loaded on demand, as they
  424.  *            may represent a lot of data, unneeded by most uses of
  425.  *            the engine.
  426.  *
  427.  ******************************************************************/
  428.  
  429.   TT_Error  TT_Get_Kerning_Directory( TT_Face      face,
  430.                                       TT_Kerning*  directory )
  431.   {
  432.     PFace  faze = HANDLE_Face(face);
  433.  
  434.     if (!faze)
  435.       return TT_Err_Invalid_Face_Handle;
  436.  
  437.     /* copy directory header */
  438.     *directory = ((TExtension*)faze->extension)->kerning;
  439.  
  440.     return TT_Err_Ok;
  441.   }
  442.   
  443. /*******************************************************************
  444.  *
  445.  *  Function    :  TT_Load_Kerning_Table
  446.  *
  447.  *  Description :  Load a kerning table intro memory
  448.  *
  449.  *  Input  :  face          face handle
  450.  *            kern_index    index in the face's kerning directory
  451.  *
  452.  *  Output :  error code
  453.  *
  454.  *  Notes  :
  455.  *
  456.  ******************************************************************/
  457.  
  458.   TT_Error  TT_Load_Kerning_Table( TT_Face  face,
  459.                                    int      kern_index )
  460.   {
  461.     TT_Error   error;
  462.     TT_Stream  stream;
  463.  
  464.     TT_Kerning*        kern;
  465.     TT_Kern_Subtable*  sub;
  466.  
  467.     PFace  faze = HANDLE_Face(face);
  468.  
  469.     if (!faze)
  470.       return TT_Err_Invalid_Face_Handle;
  471.  
  472.     kern = &((TExtension*)faze->extension)->kerning;
  473.  
  474.     if (kern_index < 0 || kern_index >= kern->nTables)
  475.       return TT_Err_Bad_Argument;
  476.  
  477.     sub = kern->tables + kern_index;
  478.  
  479.     if (sub->format != 0 && sub->format != 2)
  480.       return TT_Err_Invalid_Kerning_Table_Format;
  481.  
  482.     /* now access stream */
  483.     if ( USE_Stream( faze->stream, stream ) )
  484.       return error;
  485.  
  486.     if ( FILE_Seek( sub->offset ) )
  487.       goto Fail;
  488.  
  489.     if (sub->format == 0)
  490.       error = Subtable_Load_0( &sub->t.kern0, stream );
  491.     else if (sub->format == 2)
  492.       error = Subtable_Load_2( &sub->t.kern2, stream );
  493.  
  494.     if (!error)
  495.       sub->loaded = TRUE;
  496.  
  497.   Fail:
  498.     /* release stream */
  499.     DONE_Stream(stream);
  500.  
  501.     return error;
  502.   }
  503.  
  504. /* END */
  505.