~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/3rdparty/freetype/src/pshinter/pshrec.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

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