~ubuntu-branches/ubuntu/vivid/emscripten/vivid

« back to all changes in this revision

Viewing changes to tests/freetype/src/pshinter/pshrec.c

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-02 13:11:51 UTC
  • Revision ID: package-import@ubuntu.com-20130502131151-q8dvteqr1ef2x7xz
Tags: upstream-1.4.1~20130504~adb56cb
ImportĀ upstreamĀ versionĀ 1.4.1~20130504~adb56cb

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 */