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

  1. /*******************************************************************
  2.  *
  3.  *  ttcmap.c                                                    1.0
  4.  *
  5.  *    TrueType Character Mappings                      
  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.  ******************************************************************/
  18.  
  19. #include "ttobjs.h"
  20. #include "tterror.h"
  21. #include "ttfile.h"
  22. #include "ttmemory.h"
  23. #include "ttload.h"
  24. #include "ttcmap.h"
  25.  
  26. /*******************************************************************
  27.  *
  28.  *  Function    :  CharMap_Load
  29.  *
  30.  *  Description :  Load one given charmap into memory
  31.  *
  32.  *  Input  :  cmap  pointer to cmap table
  33.  *
  34.  *  Output :  error code
  35.  *
  36.  *  Notes  :  - Assumes the the stream is already used (opened)
  37.  *
  38.  *            - in case of error, releases all partially allocated
  39.  *              tables.
  40.  *
  41.  ******************************************************************/
  42.  
  43.   TT_Error  CharMap_Load( PCMapTable  cmap, TT_Stream  input )
  44.   {
  45.     DEFINE_LOAD_LOCALS(input);
  46.   
  47.     int   num_SH, num_Seg, i;
  48.  
  49.     unsigned short u, l;
  50.  
  51.     PCMap0  cmap0;
  52.     PCMap2  cmap2;
  53.     PCMap4  cmap4;
  54.     PCMap6  cmap6;
  55.  
  56.     PCMap2SubHeader cmap2sub;
  57.     PCMap4Segment   segments;
  58.  
  59.     if (cmap->loaded)
  60.       return TT_Err_Ok;
  61.  
  62.     if ( FILE_Seek( cmap->offset ) )
  63.       return error;
  64.  
  65.     switch ( cmap->format )
  66.     {
  67.     case 0:
  68.       cmap0 = &cmap->c.cmap0;
  69.  
  70.       if ( ALLOC( cmap0->glyphIdArray, 256L )  ||
  71.            FILE_Read( (void*)cmap0->glyphIdArray, 256L ) )
  72.          goto Fail;
  73.  
  74.       break;
  75.  
  76.  
  77.     case 2:
  78.       num_SH = 0;
  79.       cmap2  = &cmap->c.cmap2;
  80.  
  81.       /* allocate subheader keys */
  82.  
  83.       if ( ALLOC( cmap2->subHeaderKeys, 256 )  ||
  84.            ACCESS_Frame( 512L )                )
  85.         goto Fail;
  86.  
  87.       for ( i = 0; i < 256; i++ )
  88.       {
  89.         u = GET_UShort() / 8;
  90.         cmap2->subHeaderKeys[i] = u;
  91.  
  92.         if ( num_SH < u )
  93.           num_SH = u;
  94.       }
  95.  
  96.       FORGET_Frame();
  97.  
  98.       /* load subheaders */
  99.  
  100.       l = cmap->length -
  101.                  sizeof ( UShort ) * (256 + 3) - num_SH * 8;
  102.  
  103.       if ( ALLOC_ARRAY( cmap2->subHeaders,
  104.                         num_SH + 1, 
  105.                         TCMap2SubHeader )  ||
  106.            ACCESS_Frame( (num_SH +1 )*8L ) )
  107.  
  108.         goto Fail;
  109.  
  110.       cmap2sub = cmap2->subHeaders;
  111.       for ( i = 0; i <= num_SH; i++ )
  112.       {
  113.         cmap2sub->firstCode     = GET_UShort();
  114.         cmap2sub->entryCount    = GET_UShort();
  115.         cmap2sub->idDelta       = GET_Short();
  116.         /* we apply the location offset immediately */
  117.         cmap2sub->idRangeOffset = GET_UShort() - ( num_SH - i ) * 8 - 2;
  118.  
  119.         cmap2sub++;
  120.       }
  121.  
  122.       FORGET_Frame();
  123.  
  124.       /* load glyph ids */
  125.  
  126.       l /= 2;
  127.  
  128.       if ( ALLOC_ARRAY( cmap2->glyphIdArray, l, UShort ) ||
  129.            ACCESS_Frame( l*2L ) )
  130.         goto Fail;
  131.  
  132.       for ( i = 0; i < l; i++ )
  133.         cmap2->glyphIdArray[i] = GET_UShort();
  134.  
  135.       FORGET_Frame();
  136.       break;
  137.  
  138.  
  139.     case 4:
  140.       cmap4 = &cmap->c.cmap4;
  141.  
  142.       /* load header */
  143.  
  144.       if ( ACCESS_Frame( 8 ) )
  145.         goto Fail;
  146.  
  147.       cmap4 = &cmap->c.cmap4;
  148.  
  149.       cmap4->segCountX2    = GET_UShort();
  150.       cmap4->searchRange   = GET_UShort();
  151.       cmap4->entrySelector = GET_UShort();
  152.       cmap4->rangeShift    = GET_UShort();
  153.  
  154.       num_Seg = cmap4->segCountX2 / 2;
  155.  
  156.       FORGET_Frame();
  157.  
  158.       /* load segments */
  159.  
  160.       if ( ALLOC_ARRAY( cmap4->segments,
  161.                         num_Seg,
  162.                         TCMap4Segment )           ||
  163.            ACCESS_Frame( (num_Seg * 4 + 1) * 2L ) )
  164.  
  165.         goto Fail;
  166.  
  167.       segments = cmap4->segments;
  168.  
  169.       for ( i = 0; i < num_Seg; i++ )
  170.         segments[i].endCount      = GET_UShort();
  171.  
  172.       GET_UShort();
  173.  
  174.       for ( i = 0; i < num_Seg; i++ )
  175.         segments[i].startCount    = GET_UShort();
  176.  
  177.       for ( i = 0; i < num_Seg; i++ )
  178.         segments[i].idDelta       = GET_UShort();
  179.  
  180.       for ( i = 0; i < num_Seg; i++ )
  181.         segments[i].idRangeOffset = GET_UShort();
  182.  
  183.       FORGET_Frame();
  184.  
  185.       l = ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xffff;
  186.  
  187.       /* load ids */
  188.  
  189.       if ( ALLOC( cmap4->glyphIdArray, l ) ||
  190.            ACCESS_Frame( l ) )
  191.         goto Fail;
  192.  
  193.       for ( i = 0; i < l / 2; i++ )
  194.         cmap4->glyphIdArray[i] = GET_UShort();
  195.  
  196.       FORGET_Frame();
  197.       break;
  198.  
  199.     case 6:
  200.       cmap6 = &cmap->c.cmap6;
  201.  
  202.       if ( ACCESS_Frame( 4 ) )
  203.         goto Fail;
  204.  
  205.       cmap6->firstCode  = GET_UShort();
  206.       cmap6->entryCount = GET_UShort();
  207.  
  208.       FORGET_Frame();
  209.  
  210.       l = cmap6->entryCount;
  211.  
  212.       if ( ALLOC_ARRAY( cmap6->glyphIdArray,
  213.                         cmap6->entryCount,
  214.                         Short ) ||
  215.            ACCESS_Frame( l*2L ) )
  216.  
  217.         goto Fail;
  218.  
  219.       for ( i = 0; i < l; i++ )
  220.         cmap6->glyphIdArray[i] = GET_UShort();
  221.  
  222.       FORGET_Frame();
  223.       break;
  224.  
  225.     default:   /* corrupt character mapping table */
  226.       return TT_Err_Invalid_CharMap_Format;
  227.  
  228.     }
  229.     return TT_Err_Ok;
  230.  
  231.   Fail:
  232.     CharMap_Free( cmap );
  233.     return error;
  234.   }
  235.  
  236.  
  237. /*******************************************************************
  238.  *
  239.  *  Function    :  CharMap_Free
  240.  *
  241.  *  Description :  Releases one given charmap table
  242.  *
  243.  *  Input  :  cmap   pointer to cmap table
  244.  *
  245.  *  Output :  error code
  246.  *
  247.  ******************************************************************/
  248.  
  249.   TT_Error  CharMap_Free( PCMapTable  cmap )
  250.   {
  251.     if ( !cmap )
  252.       return TT_Err_Ok;
  253.  
  254.     switch (cmap->format)
  255.     {
  256.       case 0:
  257.         FREE( cmap->c.cmap0.glyphIdArray );
  258.         break;
  259.  
  260.       case 2:
  261.         FREE( cmap->c.cmap2.subHeaderKeys );
  262.         FREE( cmap->c.cmap2.subHeaders );
  263.         FREE( cmap->c.cmap2.glyphIdArray );
  264.         break;
  265.  
  266.       case 4:
  267.         FREE( cmap->c.cmap4.segments );
  268.         FREE( cmap->c.cmap4.glyphIdArray );
  269.         cmap->c.cmap4.segCountX2 = 0;
  270.         break;
  271.  
  272.       case 6:
  273.         FREE( cmap->c.cmap6.glyphIdArray );
  274.         cmap->c.cmap6.entryCount = 0;
  275.         break;
  276.  
  277.       default:
  278.         /* invalid table format, do nothing */
  279.         ;
  280.     }
  281.  
  282.     cmap->loaded = FALSE;
  283.     return TT_Err_Ok;
  284.   }
  285.  
  286. /*******************************************************************
  287.  *
  288.  *  Function    :  CharMap_Index
  289.  *
  290.  *  Description :  Perform charcode->glyph index translation
  291.  *
  292.  *  Input  :  cmap   pointer to cmap table
  293.  *
  294.  *  Output :  glyph index, -1 in case of failure
  295.  *
  296.  *  Notes  :
  297.  *
  298.  ******************************************************************/
  299.  
  300.   Int  code_to_index0( UShort  charCode, PCMap0  cmap0 );
  301.   Int  code_to_index2( UShort  charCode, PCMap2  cmap2 );
  302.   Int  code_to_index4( UShort  charCode, PCMap4  cmap4 );
  303.   Int  code_to_index6( UShort  charCode, PCMap6  cmap6 );
  304.  
  305.  
  306.   Int  CharMap_Index( PCMapTable  cmap,
  307.                       UShort      charcode )
  308.   {
  309.     switch (cmap->format)
  310.     {
  311.       case 0:
  312.         return code_to_index0( charcode, &cmap->c.cmap0 );
  313.       case 2:
  314.         return code_to_index2( charcode, &cmap->c.cmap2 );
  315.       case 4:
  316.         return code_to_index4( charcode, &cmap->c.cmap4 );
  317.       case 6:
  318.         return code_to_index6( charcode, &cmap->c.cmap6 );
  319.       default:
  320.         return -1;
  321.     }
  322.   }
  323.  
  324. /*******************************************************************
  325.  *
  326.  *  Function    : code_to_index0
  327.  *
  328.  *  Description : Convert the character code into a glyph index.
  329.  *                Uses format 0.
  330.  *                charCode will be masked to get a value in the range
  331.  *                0x00-0xFF.
  332.  *
  333.  *  Input  :  charCode      the wanted character code
  334.  *            cmap0         a pointer to a cmap table in format 0
  335.  *
  336.  *  Output :  Glyph index into the glyphs array.
  337.  *            0 if the glyph does not exist.
  338.  *
  339.  ******************************************************************/
  340.  
  341.   Int  code_to_index0( UShort  charCode,
  342.                        PCMap0  cmap0 )
  343.   {
  344.     if ( charCode <= 0xFF )
  345.       return cmap0->glyphIdArray[charCode];
  346.     else
  347.       return 0;
  348.   }
  349.  
  350.  
  351. /*******************************************************************
  352.  *
  353.  *  Function    : code_to_index2
  354.  *
  355.  *  Description : Convert the character code into a glyph index.
  356.  *                Uses format 2.
  357.  *
  358.  *  Input  :  charCode      the wanted character code
  359.  *            cmap2         a pointer to a cmap table in format 2
  360.  *
  361.  *  Output :  Glyph index into the glyphs array.
  362.  *            0 if the glyph does not exist.
  363.  *
  364.  ******************************************************************/
  365.  
  366.   Int  code_to_index2( UShort  charCode,
  367.                        PCMap2  cmap2 )
  368.   {
  369.     UShort           index1;
  370.     TCMap2SubHeader  sh2;
  371.  
  372.     index1 = cmap2->subHeaderKeys[charCode <= 0xFF ?
  373.                                   charCode : (charCode >> 8)];
  374.  
  375.     if ( index1 == 0 )
  376.     {
  377.       if ( charCode <= 0xFF )
  378.         return cmap2->glyphIdArray[charCode];   /* 8bit character code */
  379.       else
  380.         return 0;
  381.     }
  382.     else                                        /* 16bit character code */
  383.     {
  384.       if ( charCode <= 0xFF )
  385.         return 0;
  386.  
  387.       sh2 = cmap2->subHeaders[index1];
  388.  
  389.       if ( (charCode & 0xFF) < sh2.firstCode )
  390.         return 0;
  391.  
  392.       if ( (charCode & 0xFF) >= (sh2.firstCode + sh2.entryCount) )
  393.         return 0;
  394.  
  395.       return ( cmap2->glyphIdArray[sh2.idRangeOffset / 2 + (charCode & 0xFF) -
  396.                                    sh2.firstCode] + sh2.idDelta ) & 0xFFFF;
  397.     }
  398.   }
  399.  
  400.  
  401. /*******************************************************************
  402.  *
  403.  *  Function    : code_to_index4
  404.  *
  405.  *  Description : Convert the character code into a glyph index.
  406.  *                Uses format 4.
  407.  *
  408.  *  Input  :  charCode      the wanted character code
  409.  *            cmap4         a pointer to a cmap table in format 4
  410.  *
  411.  *  Output :  Glyph index into the glyphs array.
  412.  *            0 if the glyph does not exist.
  413.  *
  414.  ******************************************************************/
  415.  
  416.   Int  code_to_index4( UShort  charCode,
  417.                        PCMap4  cmap4 )
  418.   {
  419.     UShort         index1, segCount;
  420.     Int            i;
  421.     TCMap4Segment  seg4;
  422.  
  423.     segCount = cmap4->segCountX2 / 2;
  424.  
  425.     for ( i = 0; i < segCount; i++ )
  426.       if ( charCode <= cmap4->segments[i].endCount )
  427.         break;
  428.  
  429.     /* Safety check - even though the last endCount should be 0xFFFF */
  430.     if ( i >= segCount )
  431.       return 0;
  432.  
  433.     seg4 = cmap4->segments[i];
  434.  
  435.     if ( charCode < seg4.startCount )
  436.       return 0;
  437.  
  438.     if ( seg4.idRangeOffset == 0 )
  439.       return ( charCode + seg4.idDelta ) & 0xFFFF;
  440.     else
  441.     {
  442.       index1 = seg4.idRangeOffset / 2 + (charCode - seg4.startCount) -
  443.                (segCount - i);
  444.  
  445.       if ( cmap4->glyphIdArray[index1] == 0 )
  446.         return 0;
  447.       else
  448.         return ( cmap4->glyphIdArray[index1] + seg4.idDelta ) & 0xFFFF;
  449.     }
  450.   }
  451.  
  452.  
  453. /*******************************************************************
  454.  *
  455.  *  Function    : code_to_index6
  456.  *
  457.  *  Description : Convert the character code into a glyph index.
  458.  *                Uses format 6.
  459.  *
  460.  *  Input  :  charCode      the wanted character code
  461.  *            cmap6         a pointer to a cmap table in format 6
  462.  *
  463.  *  Output :  Glyph index into the glyphs array.
  464.  *            0 if the glyph does not exist (`missing character glyph')
  465.  *
  466.  ******************************************************************/
  467.  
  468.   Int  code_to_index6( UShort  charCode,
  469.                        PCMap6  cmap6 )
  470.   {
  471.     UShort firstCode;
  472.  
  473.     firstCode = cmap6->firstCode;
  474.  
  475.     if ( charCode < firstCode )
  476.       return 0;
  477.  
  478.     if ( charCode >= (firstCode + cmap6->entryCount) )
  479.       return 0;
  480.  
  481.     return cmap6->glyphIdArray[charCode - firstCode];
  482.   }
  483.   
  484.