~ubuntu-branches/ubuntu/wily/hedgewars/wily

« back to all changes in this revision

Viewing changes to misc/libfreetype/src/pshinter/pshrec.c

  • Committer: Package Import Robot
  • Author(s): Dmitry E. Oboukhov
  • Date: 2011-09-23 10:16:55 UTC
  • mfrom: (1.2.11 upstream)
  • Revision ID: package-import@ubuntu.com-20110923101655-3977th2gc5n0a3pv
Tags: 0.9.16-1
* New upstream version.
 + Downloadable content! Simply click to install any content.
   New voices, hats, maps, themes, translations, music, scripts...
   Hedgewars is now more customisable than ever before! As time goes
   by we will be soliciting community content to feature on this page,
   so remember to check it from time to time. If you decide you want
   to go back to standard Hedgewars, just remove the Data directory
   from your Hedgewars config directory.
 + 3-D rendering! Diorama-like rendering of the game in a variety
   of 3D modes. Let us know which ones work best for you, we didn't
   really have the equipment to test them all.
 + Resizable game window.
 + New utilities! The Time Box will remove one of your hedgehogs
   from the game for a while, protecting from attack until it returns,
   somewhere else on the map. Land spray will allow you to build bridges,
   seal up holes, or just make life unpleasant for your enemies.
 + New single player: Bamboo Thicket, That Sinking Feeling, Newton and
   the Tree and multi-player: The Specialists, Space Invaders,
   Racer - scripts! And a ton more script hooks for scripters
 + New twists on old weapons. Drill strike, seduction and fire have
   been adjusted. Defective mines have been added, rope can attach to
   hogs/crates/barrels again, grenades now have variable bounce (use
   precise key + 1-5). Portal gun is now more usable in flight and
   all game actions are a lot faster.
 + New theme - Golf, dozens of new community hats and a new
   localised Default voice, Ukranian.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************/
 
2
/*                                                                         */
 
3
/*  pshrec.c                                                               */
 
4
/*                                                                         */
 
5
/*    FreeType PostScript hints recorder (body).                           */
 
6
/*                                                                         */
 
7
/*  Copyright 2001, 2002, 2003, 2004, 2007, 2009 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 <ft2build.h>
 
20
#include FT_FREETYPE_H
 
21
#include FT_INTERNAL_OBJECTS_H
 
22
#include FT_INTERNAL_DEBUG_H
 
23
#include FT_INTERNAL_CALC_H
 
24
 
 
25
#include "pshrec.h"
 
26
#include "pshalgo.h"
 
27
 
 
28
#include "pshnterr.h"
 
29
 
 
30
#undef  FT_COMPONENT
 
31
#define FT_COMPONENT  trace_pshrec
 
32
 
 
33
#ifdef DEBUG_HINTER
 
34
  PS_Hints  ps_debug_hints         = 0;
 
35
  int       ps_debug_no_horz_hints = 0;
 
36
  int       ps_debug_no_vert_hints = 0;
 
37
#endif
 
38
 
 
39
 
 
40
  /*************************************************************************/
 
41
  /*************************************************************************/
 
42
  /*****                                                               *****/
 
43
  /*****                      PS_HINT MANAGEMENT                       *****/
 
44
  /*****                                                               *****/
 
45
  /*************************************************************************/
 
46
  /*************************************************************************/
 
47
 
 
48
  /* destroy hints table */
 
49
  static void
 
50
  ps_hint_table_done( PS_Hint_Table  table,
 
51
                      FT_Memory      memory )
 
52
  {
 
53
    FT_FREE( table->hints );
 
54
    table->num_hints = 0;
 
55
    table->max_hints = 0;
 
56
  }
 
57
 
 
58
 
 
59
  /* ensure that a table can contain "count" elements */
 
60
  static FT_Error
 
61
  ps_hint_table_ensure( PS_Hint_Table  table,
 
62
                        FT_UInt        count,
 
63
                        FT_Memory      memory )
 
64
  {
 
65
    FT_UInt   old_max = table->max_hints;
 
66
    FT_UInt   new_max = count;
 
67
    FT_Error  error   = PSH_Err_Ok;
 
68
 
 
69
 
 
70
    if ( new_max > old_max )
 
71
    {
 
72
      /* try to grow the table */
 
73
      new_max = FT_PAD_CEIL( new_max, 8 );
 
74
      if ( !FT_RENEW_ARRAY( table->hints, old_max, new_max ) )
 
75
        table->max_hints = new_max;
 
76
    }
 
77
    return error;
 
78
  }
 
79
 
 
80
 
 
81
  static FT_Error
 
82
  ps_hint_table_alloc( PS_Hint_Table  table,
 
83
                       FT_Memory      memory,
 
84
                       PS_Hint       *ahint )
 
85
  {
 
86
    FT_Error  error = PSH_Err_Ok;
 
87
    FT_UInt   count;
 
88
    PS_Hint   hint = 0;
 
89
 
 
90
 
 
91
    count = table->num_hints;
 
92
    count++;
 
93
 
 
94
    if ( count >= table->max_hints )
 
95
    {
 
96
      error = ps_hint_table_ensure( table, count, memory );
 
97
      if ( error )
 
98
        goto Exit;
 
99
    }
 
100
 
 
101
    hint        = table->hints + count - 1;
 
102
    hint->pos   = 0;
 
103
    hint->len   = 0;
 
104
    hint->flags = 0;
 
105
 
 
106
    table->num_hints = count;
 
107
 
 
108
  Exit:
 
109
    *ahint = hint;
 
110
    return error;
 
111
  }
 
112
 
 
113
 
 
114
  /*************************************************************************/
 
115
  /*************************************************************************/
 
116
  /*****                                                               *****/
 
117
  /*****                      PS_MASK MANAGEMENT                       *****/
 
118
  /*****                                                               *****/
 
119
  /*************************************************************************/
 
120
  /*************************************************************************/
 
121
 
 
122
  /* destroy mask */
 
123
  static void
 
124
  ps_mask_done( PS_Mask    mask,
 
125
                FT_Memory  memory )
 
126
  {
 
127
    FT_FREE( mask->bytes );
 
128
    mask->num_bits  = 0;
 
129
    mask->max_bits  = 0;
 
130
    mask->end_point = 0;
 
131
  }
 
132
 
 
133
 
 
134
  /* ensure that a mask can contain "count" bits */
 
135
  static FT_Error
 
136
  ps_mask_ensure( PS_Mask    mask,
 
137
                  FT_UInt    count,
 
138
                  FT_Memory  memory )
 
139
  {
 
140
    FT_UInt   old_max = ( mask->max_bits + 7 ) >> 3;
 
141
    FT_UInt   new_max = ( count          + 7 ) >> 3;
 
142
    FT_Error  error   = PSH_Err_Ok;
 
143
 
 
144
 
 
145
    if ( new_max > old_max )
 
146
    {
 
147
      new_max = FT_PAD_CEIL( new_max, 8 );
 
148
      if ( !FT_RENEW_ARRAY( mask->bytes, old_max, new_max ) )
 
149
        mask->max_bits = new_max * 8;
 
150
    }
 
151
    return error;
 
152
  }
 
153
 
 
154
 
 
155
  /* test a bit value in a given mask */
 
156
  static FT_Int
 
157
  ps_mask_test_bit( PS_Mask  mask,
 
158
                    FT_Int   idx )
 
159
  {
 
160
    if ( (FT_UInt)idx >= mask->num_bits )
 
161
      return 0;
 
162
 
 
163
    return mask->bytes[idx >> 3] & ( 0x80 >> ( idx & 7 ) );
 
164
  }
 
165
 
 
166
 
 
167
  /* clear a given bit */
 
168
  static void
 
169
  ps_mask_clear_bit( PS_Mask  mask,
 
170
                     FT_Int   idx )
 
171
  {
 
172
    FT_Byte*  p;
 
173
 
 
174
 
 
175
    if ( (FT_UInt)idx >= mask->num_bits )
 
176
      return;
 
177
 
 
178
    p    = mask->bytes + ( idx >> 3 );
 
179
    p[0] = (FT_Byte)( p[0] & ~( 0x80 >> ( idx & 7 ) ) );
 
180
  }
 
181
 
 
182
 
 
183
  /* set a given bit, possibly grow the mask */
 
184
  static FT_Error
 
185
  ps_mask_set_bit( PS_Mask    mask,
 
186
                   FT_Int     idx,
 
187
                   FT_Memory  memory )
 
188
  {
 
189
    FT_Error  error = PSH_Err_Ok;
 
190
    FT_Byte*  p;
 
191
 
 
192
 
 
193
    if ( idx < 0 )
 
194
      goto Exit;
 
195
 
 
196
    if ( (FT_UInt)idx >= mask->num_bits )
 
197
    {
 
198
      error = ps_mask_ensure( mask, idx + 1, memory );
 
199
      if ( error )
 
200
        goto Exit;
 
201
 
 
202
      mask->num_bits = idx + 1;
 
203
    }
 
204
 
 
205
    p    = mask->bytes + ( idx >> 3 );
 
206
    p[0] = (FT_Byte)( p[0] | ( 0x80 >> ( idx & 7 ) ) );
 
207
 
 
208
  Exit:
 
209
    return error;
 
210
  }
 
211
 
 
212
 
 
213
  /* destroy mask table */
 
214
  static void
 
215
  ps_mask_table_done( PS_Mask_Table  table,
 
216
                      FT_Memory      memory )
 
217
  {
 
218
    FT_UInt  count = table->max_masks;
 
219
    PS_Mask  mask  = table->masks;
 
220
 
 
221
 
 
222
    for ( ; count > 0; count--, mask++ )
 
223
      ps_mask_done( mask, memory );
 
224
 
 
225
    FT_FREE( table->masks );
 
226
    table->num_masks = 0;
 
227
    table->max_masks = 0;
 
228
  }
 
229
 
 
230
 
 
231
  /* ensure that a mask table can contain "count" masks */
 
232
  static FT_Error
 
233
  ps_mask_table_ensure( PS_Mask_Table  table,
 
234
                        FT_UInt        count,
 
235
                        FT_Memory      memory )
 
236
  {
 
237
    FT_UInt   old_max = table->max_masks;
 
238
    FT_UInt   new_max = count;
 
239
    FT_Error  error   = PSH_Err_Ok;
 
240
 
 
241
 
 
242
    if ( new_max > old_max )
 
243
    {
 
244
      new_max = FT_PAD_CEIL( new_max, 8 );
 
245
      if ( !FT_RENEW_ARRAY( table->masks, old_max, new_max ) )
 
246
        table->max_masks = new_max;
 
247
    }
 
248
    return error;
 
249
  }
 
250
 
 
251
 
 
252
  /* allocate a new mask in a table */
 
253
  static FT_Error
 
254
  ps_mask_table_alloc( PS_Mask_Table  table,
 
255
                       FT_Memory      memory,
 
256
                       PS_Mask       *amask )
 
257
  {
 
258
    FT_UInt   count;
 
259
    FT_Error  error = PSH_Err_Ok;
 
260
    PS_Mask   mask  = 0;
 
261
 
 
262
 
 
263
    count = table->num_masks;
 
264
    count++;
 
265
 
 
266
    if ( count > table->max_masks )
 
267
    {
 
268
      error = ps_mask_table_ensure( table, count, memory );
 
269
      if ( error )
 
270
        goto Exit;
 
271
    }
 
272
 
 
273
    mask             = table->masks + count - 1;
 
274
    mask->num_bits   = 0;
 
275
    mask->end_point  = 0;
 
276
    table->num_masks = count;
 
277
 
 
278
  Exit:
 
279
    *amask = mask;
 
280
    return error;
 
281
  }
 
282
 
 
283
 
 
284
  /* return last hint mask in a table, create one if the table is empty */
 
285
  static FT_Error
 
286
  ps_mask_table_last( PS_Mask_Table  table,
 
287
                      FT_Memory      memory,
 
288
                      PS_Mask       *amask )
 
289
  {
 
290
    FT_Error  error = PSH_Err_Ok;
 
291
    FT_UInt   count;
 
292
    PS_Mask   mask;
 
293
 
 
294
 
 
295
    count = table->num_masks;
 
296
    if ( count == 0 )
 
297
    {
 
298
      error = ps_mask_table_alloc( table, memory, &mask );
 
299
      if ( error )
 
300
        goto Exit;
 
301
    }
 
302
    else
 
303
      mask = table->masks + count - 1;
 
304
 
 
305
  Exit:
 
306
    *amask = mask;
 
307
    return error;
 
308
  }
 
309
 
 
310
 
 
311
  /* set a new mask to a given bit range */
 
312
  static FT_Error
 
313
  ps_mask_table_set_bits( PS_Mask_Table   table,
 
314
                          const FT_Byte*  source,
 
315
                          FT_UInt         bit_pos,
 
316
                          FT_UInt         bit_count,
 
317
                          FT_Memory       memory )
 
318
  {
 
319
    FT_Error  error = PSH_Err_Ok;
 
320
    PS_Mask   mask;
 
321
 
 
322
 
 
323
    error = ps_mask_table_last( table, memory, &mask );
 
324
    if ( error )
 
325
      goto Exit;
 
326
 
 
327
    error = ps_mask_ensure( mask, bit_count, memory );
 
328
    if ( error )
 
329
      goto Exit;
 
330
 
 
331
    mask->num_bits = bit_count;
 
332
 
 
333
    /* now, copy bits */
 
334
    {
 
335
      FT_Byte*  read  = (FT_Byte*)source + ( bit_pos >> 3 );
 
336
      FT_Int    rmask = 0x80 >> ( bit_pos & 7 );
 
337
      FT_Byte*  write = mask->bytes;
 
338
      FT_Int    wmask = 0x80;
 
339
      FT_Int    val;
 
340
 
 
341
 
 
342
      for ( ; bit_count > 0; bit_count-- )
 
343
      {
 
344
        val = write[0] & ~wmask;
 
345
 
 
346
        if ( read[0] & rmask )
 
347
          val |= wmask;
 
348
 
 
349
        write[0] = (FT_Byte)val;
 
350
 
 
351
        rmask >>= 1;
 
352
        if ( rmask == 0 )
 
353
        {
 
354
          read++;
 
355
          rmask = 0x80;
 
356
        }
 
357
 
 
358
        wmask >>= 1;
 
359
        if ( wmask == 0 )
 
360
        {
 
361
          write++;
 
362
          wmask = 0x80;
 
363
        }
 
364
      }
 
365
    }
 
366
 
 
367
  Exit:
 
368
    return error;
 
369
  }
 
370
 
 
371
 
 
372
  /* test whether two masks in a table intersect */
 
373
  static FT_Int
 
374
  ps_mask_table_test_intersect( PS_Mask_Table  table,
 
375
                                FT_Int         index1,
 
376
                                FT_Int         index2 )
 
377
  {
 
378
    PS_Mask   mask1  = table->masks + index1;
 
379
    PS_Mask   mask2  = table->masks + index2;
 
380
    FT_Byte*  p1     = mask1->bytes;
 
381
    FT_Byte*  p2     = mask2->bytes;
 
382
    FT_UInt   count1 = mask1->num_bits;
 
383
    FT_UInt   count2 = mask2->num_bits;
 
384
    FT_UInt   count;
 
385
 
 
386
 
 
387
    count = ( count1 <= count2 ) ? count1 : count2;
 
388
    for ( ; count >= 8; count -= 8 )
 
389
    {
 
390
      if ( p1[0] & p2[0] )
 
391
        return 1;
 
392
 
 
393
      p1++;
 
394
      p2++;
 
395
    }
 
396
 
 
397
    if ( count == 0 )
 
398
      return 0;
 
399
 
 
400
    return ( p1[0] & p2[0] ) & ~( 0xFF >> count );
 
401
  }
 
402
 
 
403
 
 
404
  /* merge two masks, used by ps_mask_table_merge_all */
 
405
  static FT_Error
 
406
  ps_mask_table_merge( PS_Mask_Table  table,
 
407
                       FT_Int         index1,
 
408
                       FT_Int         index2,
 
409
                       FT_Memory      memory )
 
410
  {
 
411
    FT_UInt   temp;
 
412
    FT_Error  error = PSH_Err_Ok;
 
413
 
 
414
 
 
415
    /* swap index1 and index2 so that index1 < index2 */
 
416
    if ( index1 > index2 )
 
417
    {
 
418
      temp   = index1;
 
419
      index1 = index2;
 
420
      index2 = temp;
 
421
    }
 
422
 
 
423
    if ( index1 < index2 && index1 >= 0 && index2 < (FT_Int)table->num_masks )
 
424
    {
 
425
      /* we need to merge the bitsets of index1 and index2 with a */
 
426
      /* simple union                                             */
 
427
      PS_Mask  mask1  = table->masks + index1;
 
428
      PS_Mask  mask2  = table->masks + index2;
 
429
      FT_UInt  count1 = mask1->num_bits;
 
430
      FT_UInt  count2 = mask2->num_bits;
 
431
      FT_Int   delta;
 
432
 
 
433
 
 
434
      if ( count2 > 0 )
 
435
      {
 
436
        FT_UInt   pos;
 
437
        FT_Byte*  read;
 
438
        FT_Byte*  write;
 
439
 
 
440
 
 
441
        /* if "count2" is greater than "count1", we need to grow the */
 
442
        /* first bitset, and clear the highest bits                  */
 
443
        if ( count2 > count1 )
 
444
        {
 
445
          error = ps_mask_ensure( mask1, count2, memory );
 
446
          if ( error )
 
447
            goto Exit;
 
448
 
 
449
          for ( pos = count1; pos < count2; pos++ )
 
450
            ps_mask_clear_bit( mask1, pos );
 
451
        }
 
452
 
 
453
        /* merge (unite) the bitsets */
 
454
        read  = mask2->bytes;
 
455
        write = mask1->bytes;
 
456
        pos   = (FT_UInt)( ( count2 + 7 ) >> 3 );
 
457
 
 
458
        for ( ; pos > 0; pos-- )
 
459
        {
 
460
          write[0] = (FT_Byte)( write[0] | read[0] );
 
461
          write++;
 
462
          read++;
 
463
        }
 
464
      }
 
465
 
 
466
      /* Now, remove "mask2" from the list.  We need to keep the masks */
 
467
      /* sorted in order of importance, so move table elements.        */
 
468
      mask2->num_bits  = 0;
 
469
      mask2->end_point = 0;
 
470
 
 
471
      delta = table->num_masks - 1 - index2; /* number of masks to move */
 
472
      if ( delta > 0 )
 
473
      {
 
474
        /* move to end of table for reuse */
 
475
        PS_MaskRec  dummy = *mask2;
 
476
 
 
477
 
 
478
        ft_memmove( mask2, mask2 + 1, delta * sizeof ( PS_MaskRec ) );
 
479
 
 
480
        mask2[delta] = dummy;
 
481
      }
 
482
 
 
483
      table->num_masks--;
 
484
    }
 
485
    else
 
486
      FT_TRACE0(( "ps_mask_table_merge: ignoring invalid indices (%d,%d)\n",
 
487
                  index1, index2 ));
 
488
 
 
489
  Exit:
 
490
    return error;
 
491
  }
 
492
 
 
493
 
 
494
  /* Try to merge all masks in a given table.  This is used to merge */
 
495
  /* all counter masks into independent counter "paths".             */
 
496
  /*                                                                 */
 
497
  static FT_Error
 
498
  ps_mask_table_merge_all( PS_Mask_Table  table,
 
499
                           FT_Memory      memory )
 
500
  {
 
501
    FT_Int    index1, index2;
 
502
    FT_Error  error = PSH_Err_Ok;
 
503
 
 
504
 
 
505
    for ( index1 = table->num_masks - 1; index1 > 0; index1-- )
 
506
    {
 
507
      for ( index2 = index1 - 1; index2 >= 0; index2-- )
 
508
      {
 
509
        if ( ps_mask_table_test_intersect( table, index1, index2 ) )
 
510
        {
 
511
          error = ps_mask_table_merge( table, index2, index1, memory );
 
512
          if ( error )
 
513
            goto Exit;
 
514
 
 
515
          break;
 
516
        }
 
517
      }
 
518
    }
 
519
 
 
520
  Exit:
 
521
    return error;
 
522
  }
 
523
 
 
524
 
 
525
  /*************************************************************************/
 
526
  /*************************************************************************/
 
527
  /*****                                                               *****/
 
528
  /*****                    PS_DIMENSION MANAGEMENT                    *****/
 
529
  /*****                                                               *****/
 
530
  /*************************************************************************/
 
531
  /*************************************************************************/
 
532
 
 
533
 
 
534
  /* finalize a given dimension */
 
535
  static void
 
536
  ps_dimension_done( PS_Dimension  dimension,
 
537
                     FT_Memory     memory )
 
538
  {
 
539
    ps_mask_table_done( &dimension->counters, memory );
 
540
    ps_mask_table_done( &dimension->masks,    memory );
 
541
    ps_hint_table_done( &dimension->hints,    memory );
 
542
  }
 
543
 
 
544
 
 
545
  /* initialize a given dimension */
 
546
  static void
 
547
  ps_dimension_init( PS_Dimension  dimension )
 
548
  {
 
549
    dimension->hints.num_hints    = 0;
 
550
    dimension->masks.num_masks    = 0;
 
551
    dimension->counters.num_masks = 0;
 
552
  }
 
553
 
 
554
 
 
555
#if 0
 
556
 
 
557
  /* set a bit at a given index in the current hint mask */
 
558
  static FT_Error
 
559
  ps_dimension_set_mask_bit( PS_Dimension  dim,
 
560
                             FT_UInt       idx,
 
561
                             FT_Memory     memory )
 
562
  {
 
563
    PS_Mask   mask;
 
564
    FT_Error  error = PSH_Err_Ok;
 
565
 
 
566
 
 
567
    /* get last hint mask */
 
568
    error = ps_mask_table_last( &dim->masks, memory, &mask );
 
569
    if ( error )
 
570
      goto Exit;
 
571
 
 
572
    error = ps_mask_set_bit( mask, idx, memory );
 
573
 
 
574
  Exit:
 
575
    return error;
 
576
  }
 
577
 
 
578
#endif
 
579
 
 
580
  /* set the end point in a mask, called from "End" & "Reset" methods */
 
581
  static void
 
582
  ps_dimension_end_mask( PS_Dimension  dim,
 
583
                         FT_UInt       end_point )
 
584
  {
 
585
    FT_UInt  count = dim->masks.num_masks;
 
586
    PS_Mask  mask;
 
587
 
 
588
 
 
589
    if ( count > 0 )
 
590
    {
 
591
      mask            = dim->masks.masks + count - 1;
 
592
      mask->end_point = end_point;
 
593
    }
 
594
  }
 
595
 
 
596
 
 
597
  /* set the end point in the current mask, then create a new empty one */
 
598
  /* (called by "Reset" method)                                         */
 
599
  static FT_Error
 
600
  ps_dimension_reset_mask( PS_Dimension  dim,
 
601
                           FT_UInt       end_point,
 
602
                           FT_Memory     memory )
 
603
  {
 
604
    PS_Mask  mask;
 
605
 
 
606
 
 
607
    /* end current mask */
 
608
    ps_dimension_end_mask( dim, end_point );
 
609
 
 
610
    /* allocate new one */
 
611
    return ps_mask_table_alloc( &dim->masks, memory, &mask );
 
612
  }
 
613
 
 
614
 
 
615
  /* set a new mask, called from the "T2Stem" method */
 
616
  static FT_Error
 
617
  ps_dimension_set_mask_bits( PS_Dimension    dim,
 
618
                              const FT_Byte*  source,
 
619
                              FT_UInt         source_pos,
 
620
                              FT_UInt         source_bits,
 
621
                              FT_UInt         end_point,
 
622
                              FT_Memory       memory )
 
623
  {
 
624
    FT_Error  error = PSH_Err_Ok;
 
625
 
 
626
 
 
627
    /* reset current mask, if any */
 
628
    error = ps_dimension_reset_mask( dim, end_point, memory );
 
629
    if ( error )
 
630
      goto Exit;
 
631
 
 
632
    /* set bits in new mask */
 
633
    error = ps_mask_table_set_bits( &dim->masks, source,
 
634
                                    source_pos, source_bits, memory );
 
635
 
 
636
  Exit:
 
637
    return error;
 
638
  }
 
639
 
 
640
 
 
641
  /* add a new single stem (called from "T1Stem" method) */
 
642
  static FT_Error
 
643
  ps_dimension_add_t1stem( PS_Dimension  dim,
 
644
                           FT_Int        pos,
 
645
                           FT_Int        len,
 
646
                           FT_Memory     memory,
 
647
                           FT_Int       *aindex )
 
648
  {
 
649
    FT_Error  error = PSH_Err_Ok;
 
650
    FT_UInt   flags = 0;
 
651
 
 
652
 
 
653
    /* detect ghost stem */
 
654
    if ( len < 0 )
 
655
    {
 
656
      flags |= PS_HINT_FLAG_GHOST;
 
657
      if ( len == -21 )
 
658
      {
 
659
        flags |= PS_HINT_FLAG_BOTTOM;
 
660
        pos   += len;
 
661
      }
 
662
      len = 0;
 
663
    }
 
664
 
 
665
    if ( aindex )
 
666
      *aindex = -1;
 
667
 
 
668
    /* now, lookup stem in the current hints table */
 
669
    {
 
670
      PS_Mask  mask;
 
671
      FT_UInt  idx;
 
672
      FT_UInt  max   = dim->hints.num_hints;
 
673
      PS_Hint  hint  = dim->hints.hints;
 
674
 
 
675
 
 
676
      for ( idx = 0; idx < max; idx++, hint++ )
 
677
      {
 
678
        if ( hint->pos == pos && hint->len == len )
 
679
          break;
 
680
      }
 
681
 
 
682
      /* we need to create a new hint in the table */
 
683
      if ( idx >= max )
 
684
      {
 
685
        error = ps_hint_table_alloc( &dim->hints, memory, &hint );
 
686
        if ( error )
 
687
          goto Exit;
 
688
 
 
689
        hint->pos   = pos;
 
690
        hint->len   = len;
 
691
        hint->flags = flags;
 
692
      }
 
693
 
 
694
      /* now, store the hint in the current mask */
 
695
      error = ps_mask_table_last( &dim->masks, memory, &mask );
 
696
      if ( error )
 
697
        goto Exit;
 
698
 
 
699
      error = ps_mask_set_bit( mask, idx, memory );
 
700
      if ( error )
 
701
        goto Exit;
 
702
 
 
703
      if ( aindex )
 
704
        *aindex = (FT_Int)idx;
 
705
    }
 
706
 
 
707
  Exit:
 
708
    return error;
 
709
  }
 
710
 
 
711
 
 
712
  /* add a "hstem3/vstem3" counter to our dimension table */
 
713
  static FT_Error
 
714
  ps_dimension_add_counter( PS_Dimension  dim,
 
715
                            FT_Int        hint1,
 
716
                            FT_Int        hint2,
 
717
                            FT_Int        hint3,
 
718
                            FT_Memory     memory )
 
719
  {
 
720
    FT_Error  error   = PSH_Err_Ok;
 
721
    FT_UInt   count   = dim->counters.num_masks;
 
722
    PS_Mask   counter = dim->counters.masks;
 
723
 
 
724
 
 
725
    /* try to find an existing counter mask that already uses */
 
726
    /* one of these stems here                                */
 
727
    for ( ; count > 0; count--, counter++ )
 
728
    {
 
729
      if ( ps_mask_test_bit( counter, hint1 ) ||
 
730
           ps_mask_test_bit( counter, hint2 ) ||
 
731
           ps_mask_test_bit( counter, hint3 ) )
 
732
        break;
 
733
    }
 
734
 
 
735
    /* create a new counter when needed */
 
736
    if ( count == 0 )
 
737
    {
 
738
      error = ps_mask_table_alloc( &dim->counters, memory, &counter );
 
739
      if ( error )
 
740
        goto Exit;
 
741
    }
 
742
 
 
743
    /* now, set the bits for our hints in the counter mask */
 
744
    error = ps_mask_set_bit( counter, hint1, memory );
 
745
    if ( error )
 
746
      goto Exit;
 
747
 
 
748
    error = ps_mask_set_bit( counter, hint2, memory );
 
749
    if ( error )
 
750
      goto Exit;
 
751
 
 
752
    error = ps_mask_set_bit( counter, hint3, memory );
 
753
    if ( error )
 
754
      goto Exit;
 
755
 
 
756
  Exit:
 
757
    return error;
 
758
  }
 
759
 
 
760
 
 
761
  /* end of recording session for a given dimension */
 
762
  static FT_Error
 
763
  ps_dimension_end( PS_Dimension  dim,
 
764
                    FT_UInt       end_point,
 
765
                    FT_Memory     memory )
 
766
  {
 
767
    /* end hint mask table */
 
768
    ps_dimension_end_mask( dim, end_point );
 
769
 
 
770
    /* merge all counter masks into independent "paths" */
 
771
    return ps_mask_table_merge_all( &dim->counters, memory );
 
772
  }
 
773
 
 
774
 
 
775
  /*************************************************************************/
 
776
  /*************************************************************************/
 
777
  /*****                                                               *****/
 
778
  /*****                    PS_RECORDER MANAGEMENT                     *****/
 
779
  /*****                                                               *****/
 
780
  /*************************************************************************/
 
781
  /*************************************************************************/
 
782
 
 
783
 
 
784
  /* destroy hints */
 
785
  FT_LOCAL( void )
 
786
  ps_hints_done( PS_Hints  hints )
 
787
  {
 
788
    FT_Memory  memory = hints->memory;
 
789
 
 
790
 
 
791
    ps_dimension_done( &hints->dimension[0], memory );
 
792
    ps_dimension_done( &hints->dimension[1], memory );
 
793
 
 
794
    hints->error  = PSH_Err_Ok;
 
795
    hints->memory = 0;
 
796
  }
 
797
 
 
798
 
 
799
  FT_LOCAL( FT_Error )
 
800
  ps_hints_init( PS_Hints   hints,
 
801
                 FT_Memory  memory )
 
802
  {
 
803
    FT_MEM_ZERO( hints, sizeof ( *hints ) );
 
804
    hints->memory = memory;
 
805
    return PSH_Err_Ok;
 
806
  }
 
807
 
 
808
 
 
809
  /* initialize a hints for a new session */
 
810
  static void
 
811
  ps_hints_open( PS_Hints      hints,
 
812
                 PS_Hint_Type  hint_type )
 
813
  {
 
814
    switch ( hint_type )
 
815
    {
 
816
    case PS_HINT_TYPE_1:
 
817
    case PS_HINT_TYPE_2:
 
818
      hints->error     = PSH_Err_Ok;
 
819
      hints->hint_type = hint_type;
 
820
 
 
821
      ps_dimension_init( &hints->dimension[0] );
 
822
      ps_dimension_init( &hints->dimension[1] );
 
823
      break;
 
824
 
 
825
    default:
 
826
      hints->error     = PSH_Err_Invalid_Argument;
 
827
      hints->hint_type = hint_type;
 
828
 
 
829
      FT_TRACE0(( "ps_hints_open: invalid charstring type\n" ));
 
830
      break;
 
831
    }
 
832
  }
 
833
 
 
834
 
 
835
  /* add one or more stems to the current hints table */
 
836
  static void
 
837
  ps_hints_stem( PS_Hints  hints,
 
838
                 FT_Int    dimension,
 
839
                 FT_UInt   count,
 
840
                 FT_Long*  stems )
 
841
  {
 
842
    if ( !hints->error )
 
843
    {
 
844
      /* limit "dimension" to 0..1 */
 
845
      if ( dimension < 0 || dimension > 1 )
 
846
      {
 
847
        FT_TRACE0(( "ps_hints_stem: invalid dimension (%d) used\n",
 
848
                    dimension ));
 
849
        dimension = ( dimension != 0 );
 
850
      }
 
851
 
 
852
      /* record the stems in the current hints/masks table */
 
853
      switch ( hints->hint_type )
 
854
      {
 
855
      case PS_HINT_TYPE_1:  /* Type 1 "hstem" or "vstem" operator */
 
856
      case PS_HINT_TYPE_2:  /* Type 2 "hstem" or "vstem" operator */
 
857
        {
 
858
          PS_Dimension  dim = &hints->dimension[dimension];
 
859
 
 
860
 
 
861
          for ( ; count > 0; count--, stems += 2 )
 
862
          {
 
863
            FT_Error   error;
 
864
            FT_Memory  memory = hints->memory;
 
865
 
 
866
 
 
867
            error = ps_dimension_add_t1stem(
 
868
                      dim, (FT_Int)stems[0], (FT_Int)stems[1],
 
869
                      memory, NULL );
 
870
            if ( error )
 
871
            {
 
872
              FT_ERROR(( "ps_hints_stem: could not add stem"
 
873
                         " (%d,%d) to hints table\n", stems[0], stems[1] ));
 
874
 
 
875
              hints->error = error;
 
876
              return;
 
877
            }
 
878
          }
 
879
          break;
 
880
        }
 
881
 
 
882
      default:
 
883
        FT_TRACE0(( "ps_hints_stem: called with invalid hint type (%d)\n",
 
884
                    hints->hint_type ));
 
885
        break;
 
886
      }
 
887
    }
 
888
  }
 
889
 
 
890
 
 
891
  /* add one Type1 counter stem to the current hints table */
 
892
  static void
 
893
  ps_hints_t1stem3( PS_Hints   hints,
 
894
                    FT_Int     dimension,
 
895
                    FT_Fixed*  stems )
 
896
  {
 
897
    FT_Error  error = PSH_Err_Ok;
 
898
 
 
899
 
 
900
    if ( !hints->error )
 
901
    {
 
902
      PS_Dimension  dim;
 
903
      FT_Memory     memory = hints->memory;
 
904
      FT_Int        count;
 
905
      FT_Int        idx[3];
 
906
 
 
907
 
 
908
      /* limit "dimension" to 0..1 */
 
909
      if ( dimension < 0 || dimension > 1 )
 
910
      {
 
911
        FT_TRACE0(( "ps_hints_t1stem3: invalid dimension (%d) used\n",
 
912
                    dimension ));
 
913
        dimension = ( dimension != 0 );
 
914
      }
 
915
 
 
916
      dim = &hints->dimension[dimension];
 
917
 
 
918
      /* there must be 6 elements in the 'stem' array */
 
919
      if ( hints->hint_type == PS_HINT_TYPE_1 )
 
920
      {
 
921
        /* add the three stems to our hints/masks table */
 
922
        for ( count = 0; count < 3; count++, stems += 2 )
 
923
        {
 
924
          error = ps_dimension_add_t1stem( dim,
 
925
                                           (FT_Int)FIXED_TO_INT( stems[0] ),
 
926
                                           (FT_Int)FIXED_TO_INT( stems[1] ),
 
927
                                           memory, &idx[count] );
 
928
          if ( error )
 
929
            goto Fail;
 
930
        }
 
931
 
 
932
        /* now, add the hints to the counters table */
 
933
        error = ps_dimension_add_counter( dim, idx[0], idx[1], idx[2],
 
934
                                          memory );
 
935
        if ( error )
 
936
          goto Fail;
 
937
      }
 
938
      else
 
939
      {
 
940
        FT_ERROR(( "ps_hints_t1stem3: called with invalid hint type\n" ));
 
941
        error = PSH_Err_Invalid_Argument;
 
942
        goto Fail;
 
943
      }
 
944
    }
 
945
 
 
946
    return;
 
947
 
 
948
  Fail:
 
949
    FT_ERROR(( "ps_hints_t1stem3: could not add counter stems to table\n" ));
 
950
    hints->error = error;
 
951
  }
 
952
 
 
953
 
 
954
  /* reset hints (only with Type 1 hints) */
 
955
  static void
 
956
  ps_hints_t1reset( PS_Hints  hints,
 
957
                    FT_UInt   end_point )
 
958
  {
 
959
    FT_Error  error = PSH_Err_Ok;
 
960
 
 
961
 
 
962
    if ( !hints->error )
 
963
    {
 
964
      FT_Memory  memory = hints->memory;
 
965
 
 
966
 
 
967
      if ( hints->hint_type == PS_HINT_TYPE_1 )
 
968
      {
 
969
        error = ps_dimension_reset_mask( &hints->dimension[0],
 
970
                                         end_point, memory );
 
971
        if ( error )
 
972
          goto Fail;
 
973
 
 
974
        error = ps_dimension_reset_mask( &hints->dimension[1],
 
975
                                         end_point, memory );
 
976
        if ( error )
 
977
          goto Fail;
 
978
      }
 
979
      else
 
980
      {
 
981
        /* invalid hint type */
 
982
        error = PSH_Err_Invalid_Argument;
 
983
        goto Fail;
 
984
      }
 
985
    }
 
986
    return;
 
987
 
 
988
  Fail:
 
989
    hints->error = error;
 
990
  }
 
991
 
 
992
 
 
993
  /* Type2 "hintmask" operator, add a new hintmask to each direction */
 
994
  static void
 
995
  ps_hints_t2mask( PS_Hints        hints,
 
996
                   FT_UInt         end_point,
 
997
                   FT_UInt         bit_count,
 
998
                   const FT_Byte*  bytes )
 
999
  {
 
1000
    FT_Error  error;
 
1001
 
 
1002
 
 
1003
    if ( !hints->error )
 
1004
    {
 
1005
      PS_Dimension  dim    = hints->dimension;
 
1006
      FT_Memory     memory = hints->memory;
 
1007
      FT_UInt       count1 = dim[0].hints.num_hints;
 
1008
      FT_UInt       count2 = dim[1].hints.num_hints;
 
1009
 
 
1010
 
 
1011
      /* check bit count; must be equal to current total hint count */
 
1012
      if ( bit_count !=  count1 + count2 )
 
1013
      {
 
1014
        FT_TRACE0(( "ps_hints_t2mask:"
 
1015
                    " called with invalid bitcount %d (instead of %d)\n",
 
1016
                   bit_count, count1 + count2 ));
 
1017
 
 
1018
        /* simply ignore the operator */
 
1019
        return;
 
1020
      }
 
1021
 
 
1022
      /* set-up new horizontal and vertical hint mask now */
 
1023
      error = ps_dimension_set_mask_bits( &dim[0], bytes, count2, count1,
 
1024
                                          end_point, memory );
 
1025
      if ( error )
 
1026
        goto Fail;
 
1027
 
 
1028
      error = ps_dimension_set_mask_bits( &dim[1], bytes, 0, count2,
 
1029
                                          end_point, memory );
 
1030
      if ( error )
 
1031
        goto Fail;
 
1032
    }
 
1033
    return;
 
1034
 
 
1035
  Fail:
 
1036
    hints->error = error;
 
1037
  }
 
1038
 
 
1039
 
 
1040
  static void
 
1041
  ps_hints_t2counter( PS_Hints        hints,
 
1042
                      FT_UInt         bit_count,
 
1043
                      const FT_Byte*  bytes )
 
1044
  {
 
1045
    FT_Error  error;
 
1046
 
 
1047
 
 
1048
    if ( !hints->error )
 
1049
    {
 
1050
      PS_Dimension  dim    = hints->dimension;
 
1051
      FT_Memory     memory = hints->memory;
 
1052
      FT_UInt       count1 = dim[0].hints.num_hints;
 
1053
      FT_UInt       count2 = dim[1].hints.num_hints;
 
1054
 
 
1055
 
 
1056
      /* check bit count, must be equal to current total hint count */
 
1057
      if ( bit_count !=  count1 + count2 )
 
1058
      {
 
1059
        FT_TRACE0(( "ps_hints_t2counter:"
 
1060
                    " called with invalid bitcount %d (instead of %d)\n",
 
1061
                   bit_count, count1 + count2 ));
 
1062
 
 
1063
        /* simply ignore the operator */
 
1064
        return;
 
1065
      }
 
1066
 
 
1067
      /* set-up new horizontal and vertical hint mask now */
 
1068
      error = ps_dimension_set_mask_bits( &dim[0], bytes, 0, count1,
 
1069
                                          0, memory );
 
1070
      if ( error )
 
1071
        goto Fail;
 
1072
 
 
1073
      error = ps_dimension_set_mask_bits( &dim[1], bytes, count1, count2,
 
1074
                                          0, memory );
 
1075
      if ( error )
 
1076
        goto Fail;
 
1077
    }
 
1078
    return;
 
1079
 
 
1080
  Fail:
 
1081
    hints->error = error;
 
1082
  }
 
1083
 
 
1084
 
 
1085
  /* end recording session */
 
1086
  static FT_Error
 
1087
  ps_hints_close( PS_Hints  hints,
 
1088
                  FT_UInt   end_point )
 
1089
  {
 
1090
    FT_Error  error;
 
1091
 
 
1092
 
 
1093
    error = hints->error;
 
1094
    if ( !error )
 
1095
    {
 
1096
      FT_Memory     memory = hints->memory;
 
1097
      PS_Dimension  dim    = hints->dimension;
 
1098
 
 
1099
 
 
1100
      error = ps_dimension_end( &dim[0], end_point, memory );
 
1101
      if ( !error )
 
1102
      {
 
1103
        error = ps_dimension_end( &dim[1], end_point, memory );
 
1104
      }
 
1105
    }
 
1106
 
 
1107
#ifdef DEBUG_HINTER
 
1108
    if ( !error )
 
1109
      ps_debug_hints = hints;
 
1110
#endif
 
1111
    return error;
 
1112
  }
 
1113
 
 
1114
 
 
1115
  /*************************************************************************/
 
1116
  /*************************************************************************/
 
1117
  /*****                                                               *****/
 
1118
  /*****                TYPE 1 HINTS RECORDING INTERFACE               *****/
 
1119
  /*****                                                               *****/
 
1120
  /*************************************************************************/
 
1121
  /*************************************************************************/
 
1122
 
 
1123
  static void
 
1124
  t1_hints_open( T1_Hints  hints )
 
1125
  {
 
1126
    ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_1 );
 
1127
  }
 
1128
 
 
1129
  static void
 
1130
  t1_hints_stem( T1_Hints   hints,
 
1131
                 FT_Int     dimension,
 
1132
                 FT_Fixed*  coords )
 
1133
  {
 
1134
    FT_Pos  stems[2];
 
1135
 
 
1136
 
 
1137
    stems[0] = FIXED_TO_INT( coords[0] );
 
1138
    stems[1] = FIXED_TO_INT( coords[1] );
 
1139
 
 
1140
    ps_hints_stem( (PS_Hints)hints, dimension, 1, stems );
 
1141
  }
 
1142
 
 
1143
 
 
1144
  FT_LOCAL_DEF( void )
 
1145
  t1_hints_funcs_init( T1_Hints_FuncsRec*  funcs )
 
1146
  {
 
1147
    FT_MEM_ZERO( (char*)funcs, sizeof ( *funcs ) );
 
1148
 
 
1149
    funcs->open  = (T1_Hints_OpenFunc)    t1_hints_open;
 
1150
    funcs->close = (T1_Hints_CloseFunc)   ps_hints_close;
 
1151
    funcs->stem  = (T1_Hints_SetStemFunc) t1_hints_stem;
 
1152
    funcs->stem3 = (T1_Hints_SetStem3Func)ps_hints_t1stem3;
 
1153
    funcs->reset = (T1_Hints_ResetFunc)   ps_hints_t1reset;
 
1154
    funcs->apply = (T1_Hints_ApplyFunc)   ps_hints_apply;
 
1155
  }
 
1156
 
 
1157
 
 
1158
  /*************************************************************************/
 
1159
  /*************************************************************************/
 
1160
  /*****                                                               *****/
 
1161
  /*****                TYPE 2 HINTS RECORDING INTERFACE               *****/
 
1162
  /*****                                                               *****/
 
1163
  /*************************************************************************/
 
1164
  /*************************************************************************/
 
1165
 
 
1166
  static void
 
1167
  t2_hints_open( T2_Hints  hints )
 
1168
  {
 
1169
    ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_2 );
 
1170
  }
 
1171
 
 
1172
 
 
1173
  static void
 
1174
  t2_hints_stems( T2_Hints   hints,
 
1175
                  FT_Int     dimension,
 
1176
                  FT_Int     count,
 
1177
                  FT_Fixed*  coords )
 
1178
  {
 
1179
    FT_Pos  stems[32], y, n;
 
1180
    FT_Int  total = count;
 
1181
 
 
1182
 
 
1183
    y = 0;
 
1184
    while ( total > 0 )
 
1185
    {
 
1186
      /* determine number of stems to write */
 
1187
      count = total;
 
1188
      if ( count > 16 )
 
1189
        count = 16;
 
1190
 
 
1191
      /* compute integer stem positions in font units */
 
1192
      for ( n = 0; n < count * 2; n++ )
 
1193
      {
 
1194
        y       += coords[n];
 
1195
        stems[n] = FIXED_TO_INT( y );
 
1196
      }
 
1197
 
 
1198
      /* compute lengths */
 
1199
      for ( n = 0; n < count * 2; n += 2 )
 
1200
        stems[n + 1] = stems[n + 1] - stems[n];
 
1201
 
 
1202
      /* add them to the current dimension */
 
1203
      ps_hints_stem( (PS_Hints)hints, dimension, count, stems );
 
1204
 
 
1205
      total -= count;
 
1206
    }
 
1207
  }
 
1208
 
 
1209
 
 
1210
  FT_LOCAL_DEF( void )
 
1211
  t2_hints_funcs_init( T2_Hints_FuncsRec*  funcs )
 
1212
  {
 
1213
    FT_MEM_ZERO( funcs, sizeof ( *funcs ) );
 
1214
 
 
1215
    funcs->open    = (T2_Hints_OpenFunc)   t2_hints_open;
 
1216
    funcs->close   = (T2_Hints_CloseFunc)  ps_hints_close;
 
1217
    funcs->stems   = (T2_Hints_StemsFunc)  t2_hints_stems;
 
1218
    funcs->hintmask= (T2_Hints_MaskFunc)   ps_hints_t2mask;
 
1219
    funcs->counter = (T2_Hints_CounterFunc)ps_hints_t2counter;
 
1220
    funcs->apply   = (T2_Hints_ApplyFunc)  ps_hints_apply;
 
1221
  }
 
1222
 
 
1223
 
 
1224
/* END */