pshrec.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  pshrec.c                                                               */
00004 /*                                                                         */
00005 /*    FreeType PostScript hints recorder (body).                           */
00006 /*                                                                         */
00007 /*  Copyright 2001, 2002, 2003, 2004, 2007, 2009 by                        */
00008 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
00015 /*                                                                         */
00016 /***************************************************************************/
00017 
00018 
00019 #include <ft2build.h>
00020 #include FT_FREETYPE_H
00021 #include FT_INTERNAL_OBJECTS_H
00022 #include FT_INTERNAL_DEBUG_H
00023 #include FT_INTERNAL_CALC_H
00024 
00025 #include "pshrec.h"
00026 #include "pshalgo.h"
00027 
00028 #include "pshnterr.h"
00029 
00030 #undef  FT_COMPONENT
00031 #define FT_COMPONENT  trace_pshrec
00032 
00033 #ifdef DEBUG_HINTER
00034   PS_Hints  ps_debug_hints         = 0;
00035   int       ps_debug_no_horz_hints = 0;
00036   int       ps_debug_no_vert_hints = 0;
00037 #endif
00038 
00039 
00040   /*************************************************************************/
00041   /*************************************************************************/
00042   /*****                                                               *****/
00043   /*****                      PS_HINT MANAGEMENT                       *****/
00044   /*****                                                               *****/
00045   /*************************************************************************/
00046   /*************************************************************************/
00047 
00048   /* destroy hints table */
00049   static void
00050   ps_hint_table_done( PS_Hint_Table  table,
00051                       FT_Memory      memory )
00052   {
00053     FT_FREE( table->hints );
00054     table->num_hints = 0;
00055     table->max_hints = 0;
00056   }
00057 
00058 
00059   /* ensure that a table can contain "count" elements */
00060   static FT_Error
00061   ps_hint_table_ensure( PS_Hint_Table  table,
00062                         FT_UInt        count,
00063                         FT_Memory      memory )
00064   {
00065     FT_UInt   old_max = table->max_hints;
00066     FT_UInt   new_max = count;
00067     FT_Error  error   = PSH_Err_Ok;
00068 
00069 
00070     if ( new_max > old_max )
00071     {
00072       /* try to grow the table */
00073       new_max = FT_PAD_CEIL( new_max, 8 );
00074       if ( !FT_RENEW_ARRAY( table->hints, old_max, new_max ) )
00075         table->max_hints = new_max;
00076     }
00077     return error;
00078   }
00079 
00080 
00081   static FT_Error
00082   ps_hint_table_alloc( PS_Hint_Table  table,
00083                        FT_Memory      memory,
00084                        PS_Hint       *ahint )
00085   {
00086     FT_Error  error = PSH_Err_Ok;
00087     FT_UInt   count;
00088     PS_Hint   hint = 0;
00089 
00090 
00091     count = table->num_hints;
00092     count++;
00093 
00094     if ( count >= table->max_hints )
00095     {
00096       error = ps_hint_table_ensure( table, count, memory );
00097       if ( error )
00098         goto Exit;
00099     }
00100 
00101     hint        = table->hints + count - 1;
00102     hint->pos   = 0;
00103     hint->len   = 0;
00104     hint->flags = 0;
00105 
00106     table->num_hints = count;
00107 
00108   Exit:
00109     *ahint = hint;
00110     return error;
00111   }
00112 
00113 
00114   /*************************************************************************/
00115   /*************************************************************************/
00116   /*****                                                               *****/
00117   /*****                      PS_MASK MANAGEMENT                       *****/
00118   /*****                                                               *****/
00119   /*************************************************************************/
00120   /*************************************************************************/
00121 
00122   /* destroy mask */
00123   static void
00124   ps_mask_done( PS_Mask    mask,
00125                 FT_Memory  memory )
00126   {
00127     FT_FREE( mask->bytes );
00128     mask->num_bits  = 0;
00129     mask->max_bits  = 0;
00130     mask->end_point = 0;
00131   }
00132 
00133 
00134   /* ensure that a mask can contain "count" bits */
00135   static FT_Error
00136   ps_mask_ensure( PS_Mask    mask,
00137                   FT_UInt    count,
00138                   FT_Memory  memory )
00139   {
00140     FT_UInt   old_max = ( mask->max_bits + 7 ) >> 3;
00141     FT_UInt   new_max = ( count          + 7 ) >> 3;
00142     FT_Error  error   = PSH_Err_Ok;
00143 
00144 
00145     if ( new_max > old_max )
00146     {
00147       new_max = FT_PAD_CEIL( new_max, 8 );
00148       if ( !FT_RENEW_ARRAY( mask->bytes, old_max, new_max ) )
00149         mask->max_bits = new_max * 8;
00150     }
00151     return error;
00152   }
00153 
00154 
00155   /* test a bit value in a given mask */
00156   static FT_Int
00157   ps_mask_test_bit( PS_Mask  mask,
00158                     FT_Int   idx )
00159   {
00160     if ( (FT_UInt)idx >= mask->num_bits )
00161       return 0;
00162 
00163     return mask->bytes[idx >> 3] & ( 0x80 >> ( idx & 7 ) );
00164   }
00165 
00166 
00167   /* clear a given bit */
00168   static void
00169   ps_mask_clear_bit( PS_Mask  mask,
00170                      FT_Int   idx )
00171   {
00172     FT_Byte*  p;
00173 
00174 
00175     if ( (FT_UInt)idx >= mask->num_bits )
00176       return;
00177 
00178     p    = mask->bytes + ( idx >> 3 );
00179     p[0] = (FT_Byte)( p[0] & ~( 0x80 >> ( idx & 7 ) ) );
00180   }
00181 
00182 
00183   /* set a given bit, possibly grow the mask */
00184   static FT_Error
00185   ps_mask_set_bit( PS_Mask    mask,
00186                    FT_Int     idx,
00187                    FT_Memory  memory )
00188   {
00189     FT_Error  error = PSH_Err_Ok;
00190     FT_Byte*  p;
00191 
00192 
00193     if ( idx < 0 )
00194       goto Exit;
00195 
00196     if ( (FT_UInt)idx >= mask->num_bits )
00197     {
00198       error = ps_mask_ensure( mask, idx + 1, memory );
00199       if ( error )
00200         goto Exit;
00201 
00202       mask->num_bits = idx + 1;
00203     }
00204 
00205     p    = mask->bytes + ( idx >> 3 );
00206     p[0] = (FT_Byte)( p[0] | ( 0x80 >> ( idx & 7 ) ) );
00207 
00208   Exit:
00209     return error;
00210   }
00211 
00212 
00213   /* destroy mask table */
00214   static void
00215   ps_mask_table_done( PS_Mask_Table  table,
00216                       FT_Memory      memory )
00217   {
00218     FT_UInt  count = table->max_masks;
00219     PS_Mask  mask  = table->masks;
00220 
00221 
00222     for ( ; count > 0; count--, mask++ )
00223       ps_mask_done( mask, memory );
00224 
00225     FT_FREE( table->masks );
00226     table->num_masks = 0;
00227     table->max_masks = 0;
00228   }
00229 
00230 
00231   /* ensure that a mask table can contain "count" masks */
00232   static FT_Error
00233   ps_mask_table_ensure( PS_Mask_Table  table,
00234                         FT_UInt        count,
00235                         FT_Memory      memory )
00236   {
00237     FT_UInt   old_max = table->max_masks;
00238     FT_UInt   new_max = count;
00239     FT_Error  error   = PSH_Err_Ok;
00240 
00241 
00242     if ( new_max > old_max )
00243     {
00244       new_max = FT_PAD_CEIL( new_max, 8 );
00245       if ( !FT_RENEW_ARRAY( table->masks, old_max, new_max ) )
00246         table->max_masks = new_max;
00247     }
00248     return error;
00249   }
00250 
00251 
00252   /* allocate a new mask in a table */
00253   static FT_Error
00254   ps_mask_table_alloc( PS_Mask_Table  table,
00255                        FT_Memory      memory,
00256                        PS_Mask       *amask )
00257   {
00258     FT_UInt   count;
00259     FT_Error  error = PSH_Err_Ok;
00260     PS_Mask   mask  = 0;
00261 
00262 
00263     count = table->num_masks;
00264     count++;
00265 
00266     if ( count > table->max_masks )
00267     {
00268       error = ps_mask_table_ensure( table, count, memory );
00269       if ( error )
00270         goto Exit;
00271     }
00272 
00273     mask             = table->masks + count - 1;
00274     mask->num_bits   = 0;
00275     mask->end_point  = 0;
00276     table->num_masks = count;
00277 
00278   Exit:
00279     *amask = mask;
00280     return error;
00281   }
00282 
00283 
00284   /* return last hint mask in a table, create one if the table is empty */
00285   static FT_Error
00286   ps_mask_table_last( PS_Mask_Table  table,
00287                       FT_Memory      memory,
00288                       PS_Mask       *amask )
00289   {
00290     FT_Error  error = PSH_Err_Ok;
00291     FT_UInt   count;
00292     PS_Mask   mask;
00293 
00294 
00295     count = table->num_masks;
00296     if ( count == 0 )
00297     {
00298       error = ps_mask_table_alloc( table, memory, &mask );
00299       if ( error )
00300         goto Exit;
00301     }
00302     else
00303       mask = table->masks + count - 1;
00304 
00305   Exit:
00306     *amask = mask;
00307     return error;
00308   }
00309 
00310 
00311   /* set a new mask to a given bit range */
00312   static FT_Error
00313   ps_mask_table_set_bits( PS_Mask_Table   table,
00314                           const FT_Byte*  source,
00315                           FT_UInt         bit_pos,
00316                           FT_UInt         bit_count,
00317                           FT_Memory       memory )
00318   {
00319     FT_Error  error = PSH_Err_Ok;
00320     PS_Mask   mask;
00321 
00322 
00323     error = ps_mask_table_last( table, memory, &mask );
00324     if ( error )
00325       goto Exit;
00326 
00327     error = ps_mask_ensure( mask, bit_count, memory );
00328     if ( error )
00329       goto Exit;
00330 
00331     mask->num_bits = bit_count;
00332 
00333     /* now, copy bits */
00334     {
00335       FT_Byte*  read  = (FT_Byte*)source + ( bit_pos >> 3 );
00336       FT_Int    rmask = 0x80 >> ( bit_pos & 7 );
00337       FT_Byte*  write = mask->bytes;
00338       FT_Int    wmask = 0x80;
00339       FT_Int    val;
00340 
00341 
00342       for ( ; bit_count > 0; bit_count-- )
00343       {
00344         val = write[0] & ~wmask;
00345 
00346         if ( read[0] & rmask )
00347           val |= wmask;
00348 
00349         write[0] = (FT_Byte)val;
00350 
00351         rmask >>= 1;
00352         if ( rmask == 0 )
00353         {
00354           read++;
00355           rmask = 0x80;
00356         }
00357 
00358         wmask >>= 1;
00359         if ( wmask == 0 )
00360         {
00361           write++;
00362           wmask = 0x80;
00363         }
00364       }
00365     }
00366 
00367   Exit:
00368     return error;
00369   }
00370 
00371 
00372   /* test whether two masks in a table intersect */
00373   static FT_Int
00374   ps_mask_table_test_intersect( PS_Mask_Table  table,
00375                                 FT_Int         index1,
00376                                 FT_Int         index2 )
00377   {
00378     PS_Mask   mask1  = table->masks + index1;
00379     PS_Mask   mask2  = table->masks + index2;
00380     FT_Byte*  p1     = mask1->bytes;
00381     FT_Byte*  p2     = mask2->bytes;
00382     FT_UInt   count1 = mask1->num_bits;
00383     FT_UInt   count2 = mask2->num_bits;
00384     FT_UInt   count;
00385 
00386 
00387     count = ( count1 <= count2 ) ? count1 : count2;
00388     for ( ; count >= 8; count -= 8 )
00389     {
00390       if ( p1[0] & p2[0] )
00391         return 1;
00392 
00393       p1++;
00394       p2++;
00395     }
00396 
00397     if ( count == 0 )
00398       return 0;
00399 
00400     return ( p1[0] & p2[0] ) & ~( 0xFF >> count );
00401   }
00402 
00403 
00404   /* merge two masks, used by ps_mask_table_merge_all */
00405   static FT_Error
00406   ps_mask_table_merge( PS_Mask_Table  table,
00407                        FT_Int         index1,
00408                        FT_Int         index2,
00409                        FT_Memory      memory )
00410   {
00411     FT_UInt   temp;
00412     FT_Error  error = PSH_Err_Ok;
00413 
00414 
00415     /* swap index1 and index2 so that index1 < index2 */
00416     if ( index1 > index2 )
00417     {
00418       temp   = index1;
00419       index1 = index2;
00420       index2 = temp;
00421     }
00422 
00423     if ( index1 < index2 && index1 >= 0 && index2 < (FT_Int)table->num_masks )
00424     {
00425       /* we need to merge the bitsets of index1 and index2 with a */
00426       /* simple union                                             */
00427       PS_Mask  mask1  = table->masks + index1;
00428       PS_Mask  mask2  = table->masks + index2;
00429       FT_UInt  count1 = mask1->num_bits;
00430       FT_UInt  count2 = mask2->num_bits;
00431       FT_Int   delta;
00432 
00433 
00434       if ( count2 > 0 )
00435       {
00436         FT_UInt   pos;
00437         FT_Byte*  read;
00438         FT_Byte*  write;
00439 
00440 
00441         /* if "count2" is greater than "count1", we need to grow the */
00442         /* first bitset, and clear the highest bits                  */
00443         if ( count2 > count1 )
00444         {
00445           error = ps_mask_ensure( mask1, count2, memory );
00446           if ( error )
00447             goto Exit;
00448 
00449           for ( pos = count1; pos < count2; pos++ )
00450             ps_mask_clear_bit( mask1, pos );
00451         }
00452 
00453         /* merge (unite) the bitsets */
00454         read  = mask2->bytes;
00455         write = mask1->bytes;
00456         pos   = (FT_UInt)( ( count2 + 7 ) >> 3 );
00457 
00458         for ( ; pos > 0; pos-- )
00459         {
00460           write[0] = (FT_Byte)( write[0] | read[0] );
00461           write++;
00462           read++;
00463         }
00464       }
00465 
00466       /* Now, remove "mask2" from the list.  We need to keep the masks */
00467       /* sorted in order of importance, so move table elements.        */
00468       mask2->num_bits  = 0;
00469       mask2->end_point = 0;
00470 
00471       delta = table->num_masks - 1 - index2; /* number of masks to move */
00472       if ( delta > 0 )
00473       {
00474         /* move to end of table for reuse */
00475         PS_MaskRec  dummy = *mask2;
00476 
00477 
00478         ft_memmove( mask2, mask2 + 1, delta * sizeof ( PS_MaskRec ) );
00479 
00480         mask2[delta] = dummy;
00481       }
00482 
00483       table->num_masks--;
00484     }
00485     else
00486       FT_TRACE0(( "ps_mask_table_merge: ignoring invalid indices (%d,%d)\n",
00487                   index1, index2 ));
00488 
00489   Exit:
00490     return error;
00491   }
00492 
00493 
00494   /* Try to merge all masks in a given table.  This is used to merge */
00495   /* all counter masks into independent counter "paths".             */
00496   /*                                                                 */
00497   static FT_Error
00498   ps_mask_table_merge_all( PS_Mask_Table  table,
00499                            FT_Memory      memory )
00500   {
00501     FT_Int    index1, index2;
00502     FT_Error  error = PSH_Err_Ok;
00503 
00504 
00505     for ( index1 = table->num_masks - 1; index1 > 0; index1-- )
00506     {
00507       for ( index2 = index1 - 1; index2 >= 0; index2-- )
00508       {
00509         if ( ps_mask_table_test_intersect( table, index1, index2 ) )
00510         {
00511           error = ps_mask_table_merge( table, index2, index1, memory );
00512           if ( error )
00513             goto Exit;
00514 
00515           break;
00516         }
00517       }
00518     }
00519 
00520   Exit:
00521     return error;
00522   }
00523 
00524 
00525   /*************************************************************************/
00526   /*************************************************************************/
00527   /*****                                                               *****/
00528   /*****                    PS_DIMENSION MANAGEMENT                    *****/
00529   /*****                                                               *****/
00530   /*************************************************************************/
00531   /*************************************************************************/
00532 
00533 
00534   /* finalize a given dimension */
00535   static void
00536   ps_dimension_done( PS_Dimension  dimension,
00537                      FT_Memory     memory )
00538   {
00539     ps_mask_table_done( &dimension->counters, memory );
00540     ps_mask_table_done( &dimension->masks,    memory );
00541     ps_hint_table_done( &dimension->hints,    memory );
00542   }
00543 
00544 
00545   /* initialize a given dimension */
00546   static void
00547   ps_dimension_init( PS_Dimension  dimension )
00548   {
00549     dimension->hints.num_hints    = 0;
00550     dimension->masks.num_masks    = 0;
00551     dimension->counters.num_masks = 0;
00552   }
00553 
00554 
00555 #if 0
00556 
00557   /* set a bit at a given index in the current hint mask */
00558   static FT_Error
00559   ps_dimension_set_mask_bit( PS_Dimension  dim,
00560                              FT_UInt       idx,
00561                              FT_Memory     memory )
00562   {
00563     PS_Mask   mask;
00564     FT_Error  error = PSH_Err_Ok;
00565 
00566 
00567     /* get last hint mask */
00568     error = ps_mask_table_last( &dim->masks, memory, &mask );
00569     if ( error )
00570       goto Exit;
00571 
00572     error = ps_mask_set_bit( mask, idx, memory );
00573 
00574   Exit:
00575     return error;
00576   }
00577 
00578 #endif
00579 
00580   /* set the end point in a mask, called from "End" & "Reset" methods */
00581   static void
00582   ps_dimension_end_mask( PS_Dimension  dim,
00583                          FT_UInt       end_point )
00584   {
00585     FT_UInt  count = dim->masks.num_masks;
00586     PS_Mask  mask;
00587 
00588 
00589     if ( count > 0 )
00590     {
00591       mask            = dim->masks.masks + count - 1;
00592       mask->end_point = end_point;
00593     }
00594   }
00595 
00596 
00597   /* set the end point in the current mask, then create a new empty one */
00598   /* (called by "Reset" method)                                         */
00599   static FT_Error
00600   ps_dimension_reset_mask( PS_Dimension  dim,
00601                            FT_UInt       end_point,
00602                            FT_Memory     memory )
00603   {
00604     PS_Mask  mask;
00605 
00606 
00607     /* end current mask */
00608     ps_dimension_end_mask( dim, end_point );
00609 
00610     /* allocate new one */
00611     return ps_mask_table_alloc( &dim->masks, memory, &mask );
00612   }
00613 
00614 
00615   /* set a new mask, called from the "T2Stem" method */
00616   static FT_Error
00617   ps_dimension_set_mask_bits( PS_Dimension    dim,
00618                               const FT_Byte*  source,
00619                               FT_UInt         source_pos,
00620                               FT_UInt         source_bits,
00621                               FT_UInt         end_point,
00622                               FT_Memory       memory )
00623   {
00624     FT_Error  error = PSH_Err_Ok;
00625 
00626 
00627     /* reset current mask, if any */
00628     error = ps_dimension_reset_mask( dim, end_point, memory );
00629     if ( error )
00630       goto Exit;
00631 
00632     /* set bits in new mask */
00633     error = ps_mask_table_set_bits( &dim->masks, source,
00634                                     source_pos, source_bits, memory );
00635 
00636   Exit:
00637     return error;
00638   }
00639 
00640 
00641   /* add a new single stem (called from "T1Stem" method) */
00642   static FT_Error
00643   ps_dimension_add_t1stem( PS_Dimension  dim,
00644                            FT_Int        pos,
00645                            FT_Int        len,
00646                            FT_Memory     memory,
00647                            FT_Int       *aindex )
00648   {
00649     FT_Error  error = PSH_Err_Ok;
00650     FT_UInt   flags = 0;
00651 
00652 
00653     /* detect ghost stem */
00654     if ( len < 0 )
00655     {
00656       flags |= PS_HINT_FLAG_GHOST;
00657       if ( len == -21 )
00658       {
00659         flags |= PS_HINT_FLAG_BOTTOM;
00660         pos   += len;
00661       }
00662       len = 0;
00663     }
00664 
00665     if ( aindex )
00666       *aindex = -1;
00667 
00668     /* now, lookup stem in the current hints table */
00669     {
00670       PS_Mask  mask;
00671       FT_UInt  idx;
00672       FT_UInt  max   = dim->hints.num_hints;
00673       PS_Hint  hint  = dim->hints.hints;
00674 
00675 
00676       for ( idx = 0; idx < max; idx++, hint++ )
00677       {
00678         if ( hint->pos == pos && hint->len == len )
00679           break;
00680       }
00681 
00682       /* we need to create a new hint in the table */
00683       if ( idx >= max )
00684       {
00685         error = ps_hint_table_alloc( &dim->hints, memory, &hint );
00686         if ( error )
00687           goto Exit;
00688 
00689         hint->pos   = pos;
00690         hint->len   = len;
00691         hint->flags = flags;
00692       }
00693 
00694       /* now, store the hint in the current mask */
00695       error = ps_mask_table_last( &dim->masks, memory, &mask );
00696       if ( error )
00697         goto Exit;
00698 
00699       error = ps_mask_set_bit( mask, idx, memory );
00700       if ( error )
00701         goto Exit;
00702 
00703       if ( aindex )
00704         *aindex = (FT_Int)idx;
00705     }
00706 
00707   Exit:
00708     return error;
00709   }
00710 
00711 
00712   /* add a "hstem3/vstem3" counter to our dimension table */
00713   static FT_Error
00714   ps_dimension_add_counter( PS_Dimension  dim,
00715                             FT_Int        hint1,
00716                             FT_Int        hint2,
00717                             FT_Int        hint3,
00718                             FT_Memory     memory )
00719   {
00720     FT_Error  error   = PSH_Err_Ok;
00721     FT_UInt   count   = dim->counters.num_masks;
00722     PS_Mask   counter = dim->counters.masks;
00723 
00724 
00725     /* try to find an existing counter mask that already uses */
00726     /* one of these stems here                                */
00727     for ( ; count > 0; count--, counter++ )
00728     {
00729       if ( ps_mask_test_bit( counter, hint1 ) ||
00730            ps_mask_test_bit( counter, hint2 ) ||
00731            ps_mask_test_bit( counter, hint3 ) )
00732         break;
00733     }
00734 
00735     /* create a new counter when needed */
00736     if ( count == 0 )
00737     {
00738       error = ps_mask_table_alloc( &dim->counters, memory, &counter );
00739       if ( error )
00740         goto Exit;
00741     }
00742 
00743     /* now, set the bits for our hints in the counter mask */
00744     error = ps_mask_set_bit( counter, hint1, memory );
00745     if ( error )
00746       goto Exit;
00747 
00748     error = ps_mask_set_bit( counter, hint2, memory );
00749     if ( error )
00750       goto Exit;
00751 
00752     error = ps_mask_set_bit( counter, hint3, memory );
00753     if ( error )
00754       goto Exit;
00755 
00756   Exit:
00757     return error;
00758   }
00759 
00760 
00761   /* end of recording session for a given dimension */
00762   static FT_Error
00763   ps_dimension_end( PS_Dimension  dim,
00764                     FT_UInt       end_point,
00765                     FT_Memory     memory )
00766   {
00767     /* end hint mask table */
00768     ps_dimension_end_mask( dim, end_point );
00769 
00770     /* merge all counter masks into independent "paths" */
00771     return ps_mask_table_merge_all( &dim->counters, memory );
00772   }
00773 
00774 
00775   /*************************************************************************/
00776   /*************************************************************************/
00777   /*****                                                               *****/
00778   /*****                    PS_RECORDER MANAGEMENT                     *****/
00779   /*****                                                               *****/
00780   /*************************************************************************/
00781   /*************************************************************************/
00782 
00783 
00784   /* destroy hints */
00785   FT_LOCAL( void )
00786   ps_hints_done( PS_Hints  hints )
00787   {
00788     FT_Memory  memory = hints->memory;
00789 
00790 
00791     ps_dimension_done( &hints->dimension[0], memory );
00792     ps_dimension_done( &hints->dimension[1], memory );
00793 
00794     hints->error  = PSH_Err_Ok;
00795     hints->memory = 0;
00796   }
00797 
00798 
00799   FT_LOCAL( FT_Error )
00800   ps_hints_init( PS_Hints   hints,
00801                  FT_Memory  memory )
00802   {
00803     FT_MEM_ZERO( hints, sizeof ( *hints ) );
00804     hints->memory = memory;
00805     return PSH_Err_Ok;
00806   }
00807 
00808 
00809   /* initialize a hints for a new session */
00810   static void
00811   ps_hints_open( PS_Hints      hints,
00812                  PS_Hint_Type  hint_type )
00813   {
00814     switch ( hint_type )
00815     {
00816     case PS_HINT_TYPE_1:
00817     case PS_HINT_TYPE_2:
00818       hints->error     = PSH_Err_Ok;
00819       hints->hint_type = hint_type;
00820 
00821       ps_dimension_init( &hints->dimension[0] );
00822       ps_dimension_init( &hints->dimension[1] );
00823       break;
00824 
00825     default:
00826       hints->error     = PSH_Err_Invalid_Argument;
00827       hints->hint_type = hint_type;
00828 
00829       FT_TRACE0(( "ps_hints_open: invalid charstring type\n" ));
00830       break;
00831     }
00832   }
00833 
00834 
00835   /* add one or more stems to the current hints table */
00836   static void
00837   ps_hints_stem( PS_Hints  hints,
00838                  FT_Int    dimension,
00839                  FT_UInt   count,
00840                  FT_Long*  stems )
00841   {
00842     if ( !hints->error )
00843     {
00844       /* limit "dimension" to 0..1 */
00845       if ( dimension < 0 || dimension > 1 )
00846       {
00847         FT_TRACE0(( "ps_hints_stem: invalid dimension (%d) used\n",
00848                     dimension ));
00849         dimension = ( dimension != 0 );
00850       }
00851 
00852       /* record the stems in the current hints/masks table */
00853       switch ( hints->hint_type )
00854       {
00855       case PS_HINT_TYPE_1:  /* Type 1 "hstem" or "vstem" operator */
00856       case PS_HINT_TYPE_2:  /* Type 2 "hstem" or "vstem" operator */
00857         {
00858           PS_Dimension  dim = &hints->dimension[dimension];
00859 
00860 
00861           for ( ; count > 0; count--, stems += 2 )
00862           {
00863             FT_Error   error;
00864             FT_Memory  memory = hints->memory;
00865 
00866 
00867             error = ps_dimension_add_t1stem(
00868                       dim, (FT_Int)stems[0], (FT_Int)stems[1],
00869                       memory, NULL );
00870             if ( error )
00871             {
00872               FT_ERROR(( "ps_hints_stem: could not add stem"
00873                          " (%d,%d) to hints table\n", stems[0], stems[1] ));
00874 
00875               hints->error = error;
00876               return;
00877             }
00878           }
00879           break;
00880         }
00881 
00882       default:
00883         FT_TRACE0(( "ps_hints_stem: called with invalid hint type (%d)\n",
00884                     hints->hint_type ));
00885         break;
00886       }
00887     }
00888   }
00889 
00890 
00891   /* add one Type1 counter stem to the current hints table */
00892   static void
00893   ps_hints_t1stem3( PS_Hints   hints,
00894                     FT_Int     dimension,
00895                     FT_Fixed*  stems )
00896   {
00897     FT_Error  error = PSH_Err_Ok;
00898 
00899 
00900     if ( !hints->error )
00901     {
00902       PS_Dimension  dim;
00903       FT_Memory     memory = hints->memory;
00904       FT_Int        count;
00905       FT_Int        idx[3];
00906 
00907 
00908       /* limit "dimension" to 0..1 */
00909       if ( dimension < 0 || dimension > 1 )
00910       {
00911         FT_TRACE0(( "ps_hints_t1stem3: invalid dimension (%d) used\n",
00912                     dimension ));
00913         dimension = ( dimension != 0 );
00914       }
00915 
00916       dim = &hints->dimension[dimension];
00917 
00918       /* there must be 6 elements in the 'stem' array */
00919       if ( hints->hint_type == PS_HINT_TYPE_1 )
00920       {
00921         /* add the three stems to our hints/masks table */
00922         for ( count = 0; count < 3; count++, stems += 2 )
00923         {
00924           error = ps_dimension_add_t1stem( dim,
00925                                            (FT_Int)FIXED_TO_INT( stems[0] ),
00926                                            (FT_Int)FIXED_TO_INT( stems[1] ),
00927                                            memory, &idx[count] );
00928           if ( error )
00929             goto Fail;
00930         }
00931 
00932         /* now, add the hints to the counters table */
00933         error = ps_dimension_add_counter( dim, idx[0], idx[1], idx[2],
00934                                           memory );
00935         if ( error )
00936           goto Fail;
00937       }
00938       else
00939       {
00940         FT_ERROR(( "ps_hints_t1stem3: called with invalid hint type\n" ));
00941         error = PSH_Err_Invalid_Argument;
00942         goto Fail;
00943       }
00944     }
00945 
00946     return;
00947 
00948   Fail:
00949     FT_ERROR(( "ps_hints_t1stem3: could not add counter stems to table\n" ));
00950     hints->error = error;
00951   }
00952 
00953 
00954   /* reset hints (only with Type 1 hints) */
00955   static void
00956   ps_hints_t1reset( PS_Hints  hints,
00957                     FT_UInt   end_point )
00958   {
00959     FT_Error  error = PSH_Err_Ok;
00960 
00961 
00962     if ( !hints->error )
00963     {
00964       FT_Memory  memory = hints->memory;
00965 
00966 
00967       if ( hints->hint_type == PS_HINT_TYPE_1 )
00968       {
00969         error = ps_dimension_reset_mask( &hints->dimension[0],
00970                                          end_point, memory );
00971         if ( error )
00972           goto Fail;
00973 
00974         error = ps_dimension_reset_mask( &hints->dimension[1],
00975                                          end_point, memory );
00976         if ( error )
00977           goto Fail;
00978       }
00979       else
00980       {
00981         /* invalid hint type */
00982         error = PSH_Err_Invalid_Argument;
00983         goto Fail;
00984       }
00985     }
00986     return;
00987 
00988   Fail:
00989     hints->error = error;
00990   }
00991 
00992 
00993   /* Type2 "hintmask" operator, add a new hintmask to each direction */
00994   static void
00995   ps_hints_t2mask( PS_Hints        hints,
00996                    FT_UInt         end_point,
00997                    FT_UInt         bit_count,
00998                    const FT_Byte*  bytes )
00999   {
01000     FT_Error  error;
01001 
01002 
01003     if ( !hints->error )
01004     {
01005       PS_Dimension  dim    = hints->dimension;
01006       FT_Memory     memory = hints->memory;
01007       FT_UInt       count1 = dim[0].hints.num_hints;
01008       FT_UInt       count2 = dim[1].hints.num_hints;
01009 
01010 
01011       /* check bit count; must be equal to current total hint count */
01012       if ( bit_count !=  count1 + count2 )
01013       {
01014         FT_TRACE0(( "ps_hints_t2mask:"
01015                     " called with invalid bitcount %d (instead of %d)\n",
01016                    bit_count, count1 + count2 ));
01017 
01018         /* simply ignore the operator */
01019         return;
01020       }
01021 
01022       /* set-up new horizontal and vertical hint mask now */
01023       error = ps_dimension_set_mask_bits( &dim[0], bytes, count2, count1,
01024                                           end_point, memory );
01025       if ( error )
01026         goto Fail;
01027 
01028       error = ps_dimension_set_mask_bits( &dim[1], bytes, 0, count2,
01029                                           end_point, memory );
01030       if ( error )
01031         goto Fail;
01032     }
01033     return;
01034 
01035   Fail:
01036     hints->error = error;
01037   }
01038 
01039 
01040   static void
01041   ps_hints_t2counter( PS_Hints        hints,
01042                       FT_UInt         bit_count,
01043                       const FT_Byte*  bytes )
01044   {
01045     FT_Error  error;
01046 
01047 
01048     if ( !hints->error )
01049     {
01050       PS_Dimension  dim    = hints->dimension;
01051       FT_Memory     memory = hints->memory;
01052       FT_UInt       count1 = dim[0].hints.num_hints;
01053       FT_UInt       count2 = dim[1].hints.num_hints;
01054 
01055 
01056       /* check bit count, must be equal to current total hint count */
01057       if ( bit_count !=  count1 + count2 )
01058       {
01059         FT_TRACE0(( "ps_hints_t2counter:"
01060                     " called with invalid bitcount %d (instead of %d)\n",
01061                    bit_count, count1 + count2 ));
01062 
01063         /* simply ignore the operator */
01064         return;
01065       }
01066 
01067       /* set-up new horizontal and vertical hint mask now */
01068       error = ps_dimension_set_mask_bits( &dim[0], bytes, 0, count1,
01069                                           0, memory );
01070       if ( error )
01071         goto Fail;
01072 
01073       error = ps_dimension_set_mask_bits( &dim[1], bytes, count1, count2,
01074                                           0, memory );
01075       if ( error )
01076         goto Fail;
01077     }
01078     return;
01079 
01080   Fail:
01081     hints->error = error;
01082   }
01083 
01084 
01085   /* end recording session */
01086   static FT_Error
01087   ps_hints_close( PS_Hints  hints,
01088                   FT_UInt   end_point )
01089   {
01090     FT_Error  error;
01091 
01092 
01093     error = hints->error;
01094     if ( !error )
01095     {
01096       FT_Memory     memory = hints->memory;
01097       PS_Dimension  dim    = hints->dimension;
01098 
01099 
01100       error = ps_dimension_end( &dim[0], end_point, memory );
01101       if ( !error )
01102       {
01103         error = ps_dimension_end( &dim[1], end_point, memory );
01104       }
01105     }
01106 
01107 #ifdef DEBUG_HINTER
01108     if ( !error )
01109       ps_debug_hints = hints;
01110 #endif
01111     return error;
01112   }
01113 
01114 
01115   /*************************************************************************/
01116   /*************************************************************************/
01117   /*****                                                               *****/
01118   /*****                TYPE 1 HINTS RECORDING INTERFACE               *****/
01119   /*****                                                               *****/
01120   /*************************************************************************/
01121   /*************************************************************************/
01122 
01123   static void
01124   t1_hints_open( T1_Hints  hints )
01125   {
01126     ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_1 );
01127   }
01128 
01129   static void
01130   t1_hints_stem( T1_Hints   hints,
01131                  FT_Int     dimension,
01132                  FT_Fixed*  coords )
01133   {
01134     FT_Pos  stems[2];
01135 
01136 
01137     stems[0] = FIXED_TO_INT( coords[0] );
01138     stems[1] = FIXED_TO_INT( coords[1] );
01139 
01140     ps_hints_stem( (PS_Hints)hints, dimension, 1, stems );
01141   }
01142 
01143 
01144   FT_LOCAL_DEF( void )
01145   t1_hints_funcs_init( T1_Hints_FuncsRec*  funcs )
01146   {
01147     FT_MEM_ZERO( (char*)funcs, sizeof ( *funcs ) );
01148 
01149     funcs->open  = (T1_Hints_OpenFunc)    t1_hints_open;
01150     funcs->close = (T1_Hints_CloseFunc)   ps_hints_close;
01151     funcs->stem  = (T1_Hints_SetStemFunc) t1_hints_stem;
01152     funcs->stem3 = (T1_Hints_SetStem3Func)ps_hints_t1stem3;
01153     funcs->reset = (T1_Hints_ResetFunc)   ps_hints_t1reset;
01154     funcs->apply = (T1_Hints_ApplyFunc)   ps_hints_apply;
01155   }
01156 
01157 
01158   /*************************************************************************/
01159   /*************************************************************************/
01160   /*****                                                               *****/
01161   /*****                TYPE 2 HINTS RECORDING INTERFACE               *****/
01162   /*****                                                               *****/
01163   /*************************************************************************/
01164   /*************************************************************************/
01165 
01166   static void
01167   t2_hints_open( T2_Hints  hints )
01168   {
01169     ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_2 );
01170   }
01171 
01172 
01173   static void
01174   t2_hints_stems( T2_Hints   hints,
01175                   FT_Int     dimension,
01176                   FT_Int     count,
01177                   FT_Fixed*  coords )
01178   {
01179     FT_Pos  stems[32], y, n;
01180     FT_Int  total = count;
01181 
01182 
01183     y = 0;
01184     while ( total > 0 )
01185     {
01186       /* determine number of stems to write */
01187       count = total;
01188       if ( count > 16 )
01189         count = 16;
01190 
01191       /* compute integer stem positions in font units */
01192       for ( n = 0; n < count * 2; n++ )
01193       {
01194         y       += coords[n];
01195         stems[n] = FIXED_TO_INT( y );
01196       }
01197 
01198       /* compute lengths */
01199       for ( n = 0; n < count * 2; n += 2 )
01200         stems[n + 1] = stems[n + 1] - stems[n];
01201 
01202       /* add them to the current dimension */
01203       ps_hints_stem( (PS_Hints)hints, dimension, count, stems );
01204 
01205       total -= count;
01206     }
01207   }
01208 
01209 
01210   FT_LOCAL_DEF( void )
01211   t2_hints_funcs_init( T2_Hints_FuncsRec*  funcs )
01212   {
01213     FT_MEM_ZERO( funcs, sizeof ( *funcs ) );
01214 
01215     funcs->open    = (T2_Hints_OpenFunc)   t2_hints_open;
01216     funcs->close   = (T2_Hints_CloseFunc)  ps_hints_close;
01217     funcs->stems   = (T2_Hints_StemsFunc)  t2_hints_stems;
01218     funcs->hintmask= (T2_Hints_MaskFunc)   ps_hints_t2mask;
01219     funcs->counter = (T2_Hints_CounterFunc)ps_hints_t2counter;
01220     funcs->apply   = (T2_Hints_ApplyFunc)  ps_hints_apply;
01221   }
01222 
01223 
01224 /* END */

Generated on Tue Jul 5 14:13:50 2011 for ROOT_528-00b_version by  doxygen 1.5.1