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

« back to all changes in this revision

Viewing changes to src/3rdparty/opentype/ftxgpos.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
 *  ftxgpos.c
 
4
 *
 
5
 *    TrueType Open GPOS table support.
 
6
 *
 
7
 *  Copyright 1996-2000 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
/* XXX There is *a lot* of duplicated code (cf. formats 7 and 8), but
 
19
       I don't care currently.  I believe that it would be possible to
 
20
       save about 50% of TTO code by carefully designing the structures,
 
21
       sharing as much as possible with extensive use of macros.  This
 
22
       is something for a volunteer :-)                                  */
 
23
 
 
24
#define TTAG_GPOS  FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
 
25
 
 
26
#include <freetype/tttags.h>
 
27
 
 
28
#include <freetype/internal/ftstream.h>
 
29
#include <freetype/internal/ftmemory.h>
 
30
#include <freetype/internal/tttypes.h>
 
31
 
 
32
#include "fterrcompat.h"
 
33
 
 
34
#include "ftxopen.h"
 
35
#include "ftxgsub.h"
 
36
#include "ftxopenf.h"
 
37
 
 
38
 
 
39
  struct  GPOS_Instance_
 
40
  {
 
41
    TTO_GPOSHeader*  gpos;
 
42
    FT_Face          face;
 
43
    FT_Bool          dvi;
 
44
    FT_UShort        load_flags;  /* how the glyph should be loaded */
 
45
    FT_Bool          r2l;
 
46
 
 
47
    FT_UShort        first;       /* the first glyph in a chain of
 
48
                                     cursive connections           */
 
49
    FT_UShort        last;        /* the last valid glyph -- used
 
50
                                     with cursive positioning     */
 
51
    FT_Pos           anchor_x;    /* the coordinates of the anchor point */
 
52
    FT_Pos           anchor_y;    /* of the last valid glyph             */
 
53
  };
 
54
 
 
55
  typedef struct GPOS_Instance_  GPOS_Instance;
 
56
 
 
57
 
 
58
  static FT_Error  GPos_Do_Glyph_Lookup( GPOS_Instance*    gpi,
 
59
                                    FT_UShort         lookup_index,
 
60
                                    TTO_GSUB_String*  in,
 
61
                                    TTO_GPOS_Data*    out,
 
62
                                    FT_UShort         context_length,
 
63
                                    int               nesting_level );
 
64
 
 
65
 
 
66
  /* the client application must replace this with something more
 
67
     meaningful if multiple master fonts are to be supported.     */
 
68
static FT_Error  default_mmfunc( FT_Face      face,
 
69
                                 FT_UShort    metric_id,
 
70
                                 FT_Pos*      metric_value,
 
71
                                 void*        data )
 
72
{
 
73
    (void)face;
 
74
    (void)metric_id;
 
75
    (void)metric_value;
 
76
    (void)data;
 
77
    return TTO_Err_No_MM_Interpreter;
 
78
}
 
79
 
 
80
 
 
81
#if 0
 
82
#define GPOS_ID  Build_Extension_ID( 'G', 'P', 'O', 'S' )
 
83
 
 
84
  /**********************
 
85
   * Extension Functions
 
86
   **********************/
 
87
 
 
88
  static FT_Error  GPOS_Create( void*      ext,
 
89
                                FT_Stream stream )
 
90
  {
 
91
    FT_Error  error;
 
92
    FT_Memory memory = stream->memory;
 
93
 
 
94
    TTO_GPOSHeader*  gpos = (TTO_GPOSHeader*)ext;
 
95
    FT_Long          table;
 
96
 
 
97
 
 
98
    /* by convention */
 
99
 
 
100
    if ( !gpos )
 
101
      return TT_Err_Ok;
 
102
 
 
103
    /* a null offset indicates that there is no GPOS table */
 
104
 
 
105
    gpos->offset = 0;
 
106
 
 
107
    /* we store the start offset and the size of the subtable */
 
108
 
 
109
    table = face->lookup_table ( face, TTAG_GPOS );
 
110
    if ( table < 0 )
 
111
      return TT_Err_Ok;             /* The table is optional */
 
112
 
 
113
    if ( FILE_Seek( face->dirTables[table].Offset ) ||
 
114
         ACCESS_Frame( 4L ) )
 
115
      return error;
 
116
 
 
117
    gpos->offset  = FILE_Pos() - 4L;    /* undo ACCESS_Frame() */
 
118
    gpos->Version = GET_ULong();
 
119
 
 
120
    FORGET_Frame();
 
121
 
 
122
    /* a default mmfunc() handler which just returns an error */
 
123
 
 
124
    gpos->mmfunc = default_mmfunc;
 
125
 
 
126
    /* the default glyph function is TT_Load_Glyph() */
 
127
 
 
128
    gpos->gfunc = FT_Load_Glyph;
 
129
 
 
130
    gpos->loaded = FALSE;
 
131
 
 
132
    return TT_Err_Ok;
 
133
  }
 
134
 
 
135
 
 
136
  static FT_Error  GPOS_Destroy( void*  ext,
 
137
                                 PFace  face )
 
138
  {
 
139
    TTO_GPOSHeader*  gpos = (TTO_GPOSHeader*)ext;
 
140
 
 
141
 
 
142
    /* by convention */
 
143
 
 
144
    if ( !gpos )
 
145
      return TT_Err_Ok;
 
146
 
 
147
    if ( gpos->loaded )
 
148
    {
 
149
      Free_LookupList( &gpos->LookupList, GPOS );
 
150
      Free_FeatureList( &gpos->FeatureList );
 
151
      Free_ScriptList( &gpos->ScriptList );
 
152
    }
 
153
 
 
154
    return TT_Err_Ok;
 
155
  }
 
156
 
 
157
 
 
158
  EXPORT_FUNC
 
159
  FT_Error  TT_Init_GPOS_Extension( TT_Engine  engine )
 
160
  {
 
161
    PEngine_Instance  _engine = HANDLE_Engine( engine );
 
162
 
 
163
 
 
164
    if ( !_engine )
 
165
      return TT_Err_Invalid_Engine;
 
166
 
 
167
    return  TT_Register_Extension( _engine,
 
168
                                   GPOS_ID,
 
169
                                   sizeof ( TTO_GPOSHeader ),
 
170
                                   GPOS_Create,
 
171
                                   GPOS_Destroy );
 
172
  }
 
173
#endif
 
174
 
 
175
  EXPORT_FUNC
 
176
  FT_Error  TT_Load_GPOS_Table( FT_Face          face,
 
177
                                TTO_GPOSHeader** retptr,
 
178
                                TTO_GDEFHeader*  gdef )
 
179
  {
 
180
    FT_ULong         cur_offset, new_offset, base_offset;
 
181
 
 
182
    /*    FT_UShort        i, num_lookups; */
 
183
    TTO_GPOSHeader*  gpos;
 
184
    /*    TTO_Lookup*      lo; */
 
185
    TT_Face          tt_face = (TT_Face)face;
 
186
 
 
187
    FT_Stream  stream = face->stream;
 
188
    FT_Error   error;
 
189
    FT_Memory  memory = face->memory;
 
190
 
 
191
 
 
192
    if ( !retptr )
 
193
      return TT_Err_Invalid_Argument;
 
194
 
 
195
    if ( !stream )
 
196
      return TT_Err_Invalid_Face_Handle;
 
197
 
 
198
    if (( error = tt_face->goto_table( tt_face, TTAG_GPOS, stream, 0 ) ))
 
199
      return error;
 
200
 
 
201
    base_offset = FILE_Pos();
 
202
 
 
203
    if ( ALLOC ( gpos, sizeof( *gpos ) ) )
 
204
      return error;
 
205
 
 
206
    gpos->memory = memory;
 
207
    gpos->gfunc = FT_Load_Glyph;
 
208
    gpos->mmfunc = default_mmfunc;
 
209
 
 
210
    /* skip version */
 
211
 
 
212
    if ( FILE_Seek( base_offset + 4L ) ||
 
213
         ACCESS_Frame( 2L ) )
 
214
      goto Fail4;
 
215
 
 
216
    new_offset = GET_UShort() + base_offset;
 
217
 
 
218
    FORGET_Frame();
 
219
 
 
220
    cur_offset = FILE_Pos();
 
221
    if ( FILE_Seek( new_offset ) ||
 
222
         ( error = Load_ScriptList( &gpos->ScriptList,
 
223
                                    stream ) ) != TT_Err_Ok )
 
224
      goto Fail4;
 
225
    (void)FILE_Seek( cur_offset );
 
226
 
 
227
    if ( ACCESS_Frame( 2L ) )
 
228
      goto Fail3;
 
229
 
 
230
    new_offset = GET_UShort() + base_offset;
 
231
 
 
232
    FORGET_Frame();
 
233
 
 
234
    cur_offset = FILE_Pos();
 
235
    if ( FILE_Seek( new_offset ) ||
 
236
         ( error = Load_FeatureList( &gpos->FeatureList,
 
237
                                     stream ) ) != TT_Err_Ok )
 
238
      goto Fail3;
 
239
    (void)FILE_Seek( cur_offset );
 
240
 
 
241
    if ( ACCESS_Frame( 2L ) )
 
242
      goto Fail2;
 
243
 
 
244
    new_offset = GET_UShort() + base_offset;
 
245
 
 
246
    FORGET_Frame();
 
247
 
 
248
    cur_offset = FILE_Pos();
 
249
    if ( FILE_Seek( new_offset ) ||
 
250
         ( error = Load_LookupList( &gpos->LookupList,
 
251
                                    stream, GPOS ) ) != TT_Err_Ok )
 
252
      goto Fail2;
 
253
 
 
254
    gpos->gdef = gdef;      /* can be NULL */
 
255
 
 
256
    /* We now check the LookupFlags for values larger than 0xFF to find
 
257
       out whether we need to load the `MarkAttachClassDef' field of the
 
258
       GDEF table -- this hack is necessary for OpenType 1.2 tables since
 
259
       the version field of the GDEF table hasn't been incremented.
 
260
 
 
261
       For constructed GDEF tables, we only load it if
 
262
       `MarkAttachClassDef_offset' is not zero (nevertheless, a build of
 
263
       a constructed mark attach table is not supported currently).       */
 
264
 
 
265
#if 0
 
266
    if ( gdef &&
 
267
         gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded )
 
268
    {
 
269
      lo          = gpos->LookupList.Lookup;
 
270
      num_lookups = gpos->LookupList.LookupCount;
 
271
 
 
272
      for ( i = 0; i < num_lookups; i++ )
 
273
      {
 
274
        if ( lo[i].LookupFlag & IGNORE_SPECIAL_MARKS )
 
275
        {
 
276
          if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) ||
 
277
               ACCESS_Frame( 2L ) )
 
278
            goto Fail1;
 
279
 
 
280
          new_offset = GET_UShort();
 
281
 
 
282
          FORGET_Frame();
 
283
 
 
284
          if ( !new_offset )
 
285
            return TTO_Err_Invalid_GDEF_SubTable;
 
286
 
 
287
          new_offset += base_offset;
 
288
 
 
289
          if ( FILE_Seek( new_offset ) ||
 
290
               ( error = Load_ClassDefinition( &gdef->MarkAttachClassDef,
 
291
                                               256, stream ) ) != TT_Err_Ok )
 
292
            goto Fail1;
 
293
 
 
294
          break;
 
295
        }
 
296
      }
 
297
    }
 
298
#endif
 
299
    *retptr = gpos;
 
300
 
 
301
    return TT_Err_Ok;
 
302
 
 
303
#if 0
 
304
  Fail1:
 
305
    Free_LookupList( &gpos->LookupList, GPOS, memory );
 
306
#endif
 
307
 
 
308
  Fail2:
 
309
    Free_FeatureList( &gpos->FeatureList, memory );
 
310
 
 
311
  Fail3:
 
312
    Free_ScriptList( &gpos->ScriptList, memory );
 
313
 
 
314
  Fail4:
 
315
    FREE( gpos );
 
316
 
 
317
    return error;
 
318
  }
 
319
 
 
320
  EXPORT_FUNC
 
321
  FT_Error  TT_Done_GPOS_Table( TTO_GPOSHeader* gpos )
 
322
  {
 
323
    FT_Memory memory = gpos->memory;
 
324
 
 
325
    Free_LookupList( &gpos->LookupList, GPOS, memory );
 
326
    Free_FeatureList( &gpos->FeatureList, memory );
 
327
    Free_ScriptList( &gpos->ScriptList, memory );
 
328
 
 
329
    return FT_Err_Ok;
 
330
  }
 
331
 
 
332
 
 
333
  /*****************************
 
334
   * SubTable related functions
 
335
   *****************************/
 
336
 
 
337
  /* shared tables */
 
338
 
 
339
  /* ValueRecord */
 
340
 
 
341
  /* There is a subtle difference in the specs between a `table' and a
 
342
     `record' -- offsets for device tables in ValueRecords are taken from
 
343
     the parent table and not the parent record.                          */
 
344
 
 
345
  static FT_Error  Load_ValueRecord( TTO_ValueRecord*  vr,
 
346
                                     FT_UShort         format,
 
347
                                     FT_ULong          base_offset,
 
348
                                     FT_Stream         stream )
 
349
  {
 
350
    FT_Error  error;
 
351
    FT_Memory memory = stream->memory;
 
352
 
 
353
    FT_ULong cur_offset, new_offset;
 
354
 
 
355
 
 
356
    if ( format & HAVE_X_PLACEMENT )
 
357
    {
 
358
      if ( ACCESS_Frame( 2L ) )
 
359
        return error;
 
360
 
 
361
      vr->XPlacement = GET_Short();
 
362
 
 
363
      FORGET_Frame();
 
364
    }
 
365
    else
 
366
      vr->XPlacement = 0;
 
367
 
 
368
    if ( format & HAVE_Y_PLACEMENT )
 
369
    {
 
370
      if ( ACCESS_Frame( 2L ) )
 
371
        return error;
 
372
 
 
373
      vr->YPlacement = GET_Short();
 
374
 
 
375
      FORGET_Frame();
 
376
    }
 
377
    else
 
378
      vr->YPlacement = 0;
 
379
 
 
380
    if ( format & HAVE_X_ADVANCE )
 
381
    {
 
382
      if ( ACCESS_Frame( 2L ) )
 
383
        return error;
 
384
 
 
385
      vr->XAdvance = GET_Short();
 
386
 
 
387
      FORGET_Frame();
 
388
    }
 
389
    else
 
390
      vr->XAdvance = 0;
 
391
 
 
392
    if ( format & HAVE_Y_ADVANCE )
 
393
    {
 
394
      if ( ACCESS_Frame( 2L ) )
 
395
        return error;
 
396
 
 
397
      vr->YAdvance = GET_Short();
 
398
 
 
399
      FORGET_Frame();
 
400
    }
 
401
    else
 
402
      vr->YAdvance = 0;
 
403
 
 
404
    if ( format & HAVE_X_PLACEMENT_DEVICE )
 
405
    {
 
406
      if ( ACCESS_Frame( 2L ) )
 
407
        return error;
 
408
 
 
409
      new_offset = GET_UShort();
 
410
 
 
411
      FORGET_Frame();
 
412
 
 
413
      if ( new_offset )
 
414
      {
 
415
        new_offset += base_offset;
 
416
 
 
417
        cur_offset = FILE_Pos();
 
418
        if ( FILE_Seek( new_offset ) ||
 
419
             ( error = Load_Device( &vr->XPlacementDevice,
 
420
                                    stream ) ) != TT_Err_Ok )
 
421
          return error;
 
422
        (void)FILE_Seek( cur_offset );
 
423
      }
 
424
      else
 
425
        goto empty1;
 
426
    }
 
427
    else
 
428
    {
 
429
    empty1:
 
430
      vr->XPlacementDevice.StartSize  = 0;
 
431
      vr->XPlacementDevice.EndSize    = 0;
 
432
      vr->XPlacementDevice.DeltaValue = NULL;
 
433
    }
 
434
 
 
435
    if ( format & HAVE_Y_PLACEMENT_DEVICE )
 
436
    {
 
437
      if ( ACCESS_Frame( 2L ) )
 
438
        goto Fail3;
 
439
 
 
440
      new_offset = GET_UShort();
 
441
 
 
442
      FORGET_Frame();
 
443
 
 
444
      if ( new_offset )
 
445
      {
 
446
        new_offset += base_offset;
 
447
 
 
448
        cur_offset = FILE_Pos();
 
449
        if ( FILE_Seek( new_offset ) ||
 
450
             ( error = Load_Device( &vr->YPlacementDevice,
 
451
                                    stream ) ) != TT_Err_Ok )
 
452
          goto Fail3;
 
453
        (void)FILE_Seek( cur_offset );
 
454
      }
 
455
      else
 
456
        goto empty2;
 
457
    }
 
458
    else
 
459
    {
 
460
    empty2:
 
461
      vr->YPlacementDevice.StartSize  = 0;
 
462
      vr->YPlacementDevice.EndSize    = 0;
 
463
      vr->YPlacementDevice.DeltaValue = NULL;
 
464
    }
 
465
 
 
466
    if ( format & HAVE_X_ADVANCE_DEVICE )
 
467
    {
 
468
      if ( ACCESS_Frame( 2L ) )
 
469
        goto Fail2;
 
470
 
 
471
      new_offset = GET_UShort();
 
472
 
 
473
      FORGET_Frame();
 
474
 
 
475
      if ( new_offset )
 
476
      {
 
477
        new_offset += base_offset;
 
478
 
 
479
        cur_offset = FILE_Pos();
 
480
        if ( FILE_Seek( new_offset ) ||
 
481
             ( error = Load_Device( &vr->XAdvanceDevice,
 
482
                                    stream ) ) != TT_Err_Ok )
 
483
          goto Fail2;
 
484
        (void)FILE_Seek( cur_offset );
 
485
      }
 
486
      else
 
487
        goto empty3;
 
488
    }
 
489
    else
 
490
    {
 
491
    empty3:
 
492
      vr->XAdvanceDevice.StartSize  = 0;
 
493
      vr->XAdvanceDevice.EndSize    = 0;
 
494
      vr->XAdvanceDevice.DeltaValue = NULL;
 
495
    }
 
496
 
 
497
    if ( format & HAVE_Y_ADVANCE_DEVICE )
 
498
    {
 
499
      if ( ACCESS_Frame( 2L ) )
 
500
        goto Fail1;
 
501
 
 
502
      new_offset = GET_UShort();
 
503
 
 
504
      FORGET_Frame();
 
505
 
 
506
      if ( new_offset )
 
507
      {
 
508
        new_offset += base_offset;
 
509
 
 
510
        cur_offset = FILE_Pos();
 
511
        if ( FILE_Seek( new_offset ) ||
 
512
             ( error = Load_Device( &vr->YAdvanceDevice,
 
513
                                    stream ) ) != TT_Err_Ok )
 
514
          goto Fail1;
 
515
        (void)FILE_Seek( cur_offset );
 
516
      }
 
517
      else
 
518
        goto empty4;
 
519
    }
 
520
    else
 
521
    {
 
522
    empty4:
 
523
      vr->YAdvanceDevice.StartSize  = 0;
 
524
      vr->YAdvanceDevice.EndSize    = 0;
 
525
      vr->YAdvanceDevice.DeltaValue = NULL;
 
526
    }
 
527
 
 
528
    if ( format & HAVE_X_ID_PLACEMENT )
 
529
    {
 
530
      if ( ACCESS_Frame( 2L ) )
 
531
        goto Fail1;
 
532
 
 
533
      vr->XIdPlacement = GET_UShort();
 
534
 
 
535
      FORGET_Frame();
 
536
    }
 
537
    else
 
538
      vr->XIdPlacement = 0;
 
539
 
 
540
    if ( format & HAVE_Y_ID_PLACEMENT )
 
541
    {
 
542
      if ( ACCESS_Frame( 2L ) )
 
543
        goto Fail1;
 
544
 
 
545
      vr->YIdPlacement = GET_UShort();
 
546
 
 
547
      FORGET_Frame();
 
548
    }
 
549
    else
 
550
      vr->YIdPlacement = 0;
 
551
 
 
552
    if ( format & HAVE_X_ID_ADVANCE )
 
553
    {
 
554
      if ( ACCESS_Frame( 2L ) )
 
555
        goto Fail1;
 
556
 
 
557
      vr->XIdAdvance = GET_UShort();
 
558
 
 
559
      FORGET_Frame();
 
560
    }
 
561
    else
 
562
      vr->XIdAdvance = 0;
 
563
 
 
564
    if ( format & HAVE_Y_ID_ADVANCE )
 
565
    {
 
566
      if ( ACCESS_Frame( 2L ) )
 
567
        goto Fail1;
 
568
 
 
569
      vr->YIdAdvance = GET_UShort();
 
570
 
 
571
      FORGET_Frame();
 
572
    }
 
573
    else
 
574
      vr->YIdAdvance = 0;
 
575
 
 
576
    return TT_Err_Ok;
 
577
 
 
578
  Fail1:
 
579
    Free_Device( &vr->YAdvanceDevice, memory );
 
580
 
 
581
  Fail2:
 
582
    Free_Device( &vr->XAdvanceDevice, memory );
 
583
 
 
584
  Fail3:
 
585
    Free_Device( &vr->YPlacementDevice, memory );
 
586
    return error;
 
587
  }
 
588
 
 
589
 
 
590
  static void  Free_ValueRecord( TTO_ValueRecord*  vr,
 
591
                                 FT_UShort         format,
 
592
                                 FT_Memory         memory )
 
593
  {
 
594
    if ( format & HAVE_Y_ADVANCE_DEVICE )
 
595
      Free_Device( &vr->YAdvanceDevice, memory );
 
596
    if ( format & HAVE_X_ADVANCE_DEVICE )
 
597
      Free_Device( &vr->XAdvanceDevice, memory );
 
598
    if ( format & HAVE_Y_PLACEMENT_DEVICE )
 
599
      Free_Device( &vr->YPlacementDevice, memory );
 
600
    if ( format & HAVE_X_PLACEMENT_DEVICE )
 
601
      Free_Device( &vr->XPlacementDevice, memory );
 
602
  }
 
603
 
 
604
 
 
605
  static FT_Error  Get_ValueRecord( GPOS_Instance*    gpi,
 
606
                                    TTO_ValueRecord*  vr,
 
607
                                    FT_UShort         format,
 
608
                                    TTO_GPOS_Data*    gd )
 
609
  {
 
610
    FT_Pos           value;
 
611
    FT_Short         pixel_value;
 
612
    FT_Error         error = TT_Err_Ok;
 
613
    TTO_GPOSHeader*  gpos = gpi->gpos;
 
614
 
 
615
    FT_UShort  x_ppem, y_ppem;
 
616
    FT_Fixed   x_scale, y_scale;
 
617
 
 
618
 
 
619
    if ( !format )
 
620
      return TT_Err_Ok;
 
621
 
 
622
    x_ppem  = gpi->face->size->metrics.x_ppem;
 
623
    y_ppem  = gpi->face->size->metrics.y_ppem;
 
624
    x_scale = gpi->face->size->metrics.x_scale;
 
625
    y_scale = gpi->face->size->metrics.y_scale;
 
626
 
 
627
    /* design units -> fractional pixel */
 
628
 
 
629
    if ( format & HAVE_X_PLACEMENT )
 
630
      gd->x_pos += x_scale * vr->XPlacement / 0x10000;
 
631
    if ( format & HAVE_Y_PLACEMENT )
 
632
      gd->y_pos += y_scale * vr->YPlacement / 0x10000;
 
633
    if ( format & HAVE_X_ADVANCE )
 
634
      gd->x_advance += x_scale * vr->XAdvance / 0x10000;
 
635
    if ( format & HAVE_Y_ADVANCE )
 
636
      gd->y_advance += y_scale * vr->YAdvance / 0x10000;
 
637
 
 
638
    if ( !gpi->dvi )
 
639
    {
 
640
      /* pixel -> fractional pixel */
 
641
 
 
642
      if ( format & HAVE_X_PLACEMENT_DEVICE )
 
643
      {
 
644
        Get_Device( &vr->XPlacementDevice, x_ppem, &pixel_value );
 
645
        gd->x_pos += pixel_value << 6;
 
646
      }
 
647
      if ( format & HAVE_Y_PLACEMENT_DEVICE )
 
648
      {
 
649
        Get_Device( &vr->YPlacementDevice, y_ppem, &pixel_value );
 
650
        gd->y_pos += pixel_value << 6;
 
651
      }
 
652
      if ( format & HAVE_X_ADVANCE_DEVICE )
 
653
      {
 
654
        Get_Device( &vr->XAdvanceDevice, x_ppem, &pixel_value );
 
655
        gd->x_advance += pixel_value << 6;
 
656
      }
 
657
      if ( format & HAVE_Y_ADVANCE_DEVICE )
 
658
      {
 
659
        Get_Device( &vr->YAdvanceDevice, y_ppem, &pixel_value );
 
660
        gd->y_advance += pixel_value << 6;
 
661
      }
 
662
    }
 
663
 
 
664
    /* values returned from mmfunc() are already in fractional pixels */
 
665
 
 
666
    if ( format & HAVE_X_ID_PLACEMENT )
 
667
    {
 
668
      error = (gpos->mmfunc)( gpi->face, vr->XIdPlacement,
 
669
                              &value, gpos->data );
 
670
      if ( error )
 
671
        return error;
 
672
      gd->x_pos += value;
 
673
    }
 
674
    if ( format & HAVE_Y_ID_PLACEMENT )
 
675
    {
 
676
      error = (gpos->mmfunc)( gpi->face, vr->YIdPlacement,
 
677
                              &value, gpos->data );
 
678
      if ( error )
 
679
        return error;
 
680
      gd->y_pos += value;
 
681
    }
 
682
    if ( format & HAVE_X_ID_ADVANCE )
 
683
    {
 
684
      error = (gpos->mmfunc)( gpi->face, vr->XIdAdvance,
 
685
                              &value, gpos->data );
 
686
      if ( error )
 
687
        return error;
 
688
      gd->x_advance += value;
 
689
    }
 
690
    if ( format & HAVE_Y_ID_ADVANCE )
 
691
    {
 
692
      error = (gpos->mmfunc)( gpi->face, vr->YIdAdvance,
 
693
                              &value, gpos->data );
 
694
      if ( error )
 
695
        return error;
 
696
      gd->y_advance += value;
 
697
    }
 
698
 
 
699
    return error;
 
700
  }
 
701
 
 
702
 
 
703
  /* AnchorFormat1 */
 
704
  /* AnchorFormat2 */
 
705
  /* AnchorFormat3 */
 
706
  /* AnchorFormat4 */
 
707
 
 
708
  static FT_Error  Load_Anchor( TTO_Anchor*  an,
 
709
                                FT_Stream    stream )
 
710
  {
 
711
    FT_Error  error;
 
712
    FT_Memory memory = stream->memory;
 
713
 
 
714
    FT_ULong cur_offset, new_offset, base_offset;
 
715
 
 
716
 
 
717
    base_offset = FILE_Pos();
 
718
 
 
719
    if ( ACCESS_Frame( 2L ) )
 
720
      return error;
 
721
 
 
722
    an->PosFormat = GET_UShort();
 
723
 
 
724
    FORGET_Frame();
 
725
 
 
726
    switch ( an->PosFormat )
 
727
    {
 
728
    case 1:
 
729
      if ( ACCESS_Frame( 4L ) )
 
730
        return error;
 
731
 
 
732
      an->af.af1.XCoordinate = GET_Short();
 
733
      an->af.af1.YCoordinate = GET_Short();
 
734
 
 
735
      FORGET_Frame();
 
736
      break;
 
737
 
 
738
    case 2:
 
739
      if ( ACCESS_Frame( 6L ) )
 
740
        return error;
 
741
 
 
742
      an->af.af2.XCoordinate = GET_Short();
 
743
      an->af.af2.YCoordinate = GET_Short();
 
744
      an->af.af2.AnchorPoint = GET_UShort();
 
745
 
 
746
      FORGET_Frame();
 
747
      break;
 
748
 
 
749
    case 3:
 
750
      if ( ACCESS_Frame( 6L ) )
 
751
        return error;
 
752
 
 
753
      an->af.af3.XCoordinate = GET_Short();
 
754
      an->af.af3.YCoordinate = GET_Short();
 
755
 
 
756
      new_offset = GET_UShort();
 
757
 
 
758
      FORGET_Frame();
 
759
 
 
760
      if ( new_offset )
 
761
      {
 
762
        new_offset += base_offset;
 
763
 
 
764
        cur_offset = FILE_Pos();
 
765
        if ( FILE_Seek( new_offset ) ||
 
766
             ( error = Load_Device( &an->af.af3.XDeviceTable,
 
767
                                    stream ) ) != TT_Err_Ok )
 
768
          return error;
 
769
        (void)FILE_Seek( cur_offset );
 
770
      }
 
771
      else
 
772
      {
 
773
        an->af.af3.XDeviceTable.StartSize  = 0;
 
774
        an->af.af3.XDeviceTable.EndSize    = 0;
 
775
        an->af.af3.XDeviceTable.DeltaValue = 0;
 
776
      }
 
777
 
 
778
      if ( ACCESS_Frame( 2L ) )
 
779
        goto Fail;
 
780
 
 
781
      new_offset = GET_UShort();
 
782
 
 
783
      FORGET_Frame();
 
784
 
 
785
      if ( new_offset )
 
786
      {
 
787
        new_offset += base_offset;
 
788
 
 
789
        cur_offset = FILE_Pos();
 
790
        if ( FILE_Seek( new_offset ) ||
 
791
             ( error = Load_Device( &an->af.af3.YDeviceTable,
 
792
                                    stream ) ) != TT_Err_Ok )
 
793
          goto Fail;
 
794
        (void)FILE_Seek( cur_offset );
 
795
      }
 
796
      else
 
797
      {
 
798
        an->af.af3.YDeviceTable.StartSize  = 0;
 
799
        an->af.af3.YDeviceTable.EndSize    = 0;
 
800
        an->af.af3.YDeviceTable.DeltaValue = 0;
 
801
      }
 
802
      break;
 
803
 
 
804
    case 4:
 
805
      if ( ACCESS_Frame( 4L ) )
 
806
        return error;
 
807
 
 
808
      an->af.af4.XIdAnchor = GET_UShort();
 
809
      an->af.af4.YIdAnchor = GET_UShort();
 
810
 
 
811
      FORGET_Frame();
 
812
      break;
 
813
 
 
814
    default:
 
815
      return TTO_Err_Invalid_GPOS_SubTable_Format;
 
816
    }
 
817
 
 
818
    return TT_Err_Ok;
 
819
 
 
820
  Fail:
 
821
    Free_Device( &an->af.af3.XDeviceTable, memory );
 
822
    return error;
 
823
  }
 
824
 
 
825
 
 
826
  static void  Free_Anchor( TTO_Anchor*  an,
 
827
                            FT_Memory    memory)
 
828
  {
 
829
    if ( an->PosFormat == 3 )
 
830
    {
 
831
      Free_Device( &an->af.af3.YDeviceTable, memory );
 
832
      Free_Device( &an->af.af3.XDeviceTable, memory );
 
833
    }
 
834
  }
 
835
 
 
836
 
 
837
  static FT_Error  Get_Anchor( GPOS_Instance*   gpi,
 
838
                               TTO_Anchor*      an,
 
839
                               FT_UShort        glyph_index,
 
840
                               FT_Pos*          x_value,
 
841
                               FT_Pos*          y_value )
 
842
  {
 
843
    FT_Error  error = TT_Err_Ok;
 
844
 
 
845
    FT_Outline       outline;
 
846
    TTO_GPOSHeader*  gpos = gpi->gpos;
 
847
    FT_UShort        ap;
 
848
 
 
849
    FT_Short         pixel_value;
 
850
    FT_UShort        load_flags;
 
851
 
 
852
    FT_UShort        x_ppem, y_ppem;
 
853
    FT_Fixed         x_scale, y_scale;
 
854
 
 
855
 
 
856
    x_ppem  = gpi->face->size->metrics.x_ppem;
 
857
    y_ppem  = gpi->face->size->metrics.y_ppem;
 
858
    x_scale = gpi->face->size->metrics.x_scale;
 
859
    y_scale = gpi->face->size->metrics.y_scale;
 
860
 
 
861
    switch ( an->PosFormat )
 
862
    {
 
863
    case 0:
 
864
      /* The special case of an empty AnchorTable */
 
865
 
 
866
      return TTO_Err_Not_Covered;
 
867
 
 
868
    case 1:
 
869
      *x_value = x_scale * an->af.af1.XCoordinate / 0x10000;
 
870
      *y_value = y_scale * an->af.af1.YCoordinate / 0x10000;
 
871
      break;
 
872
 
 
873
    case 2:
 
874
      /* glyphs must be scaled */
 
875
 
 
876
      load_flags = gpi->load_flags & ~FT_LOAD_NO_SCALE;
 
877
 
 
878
      if ( !gpi->dvi )
 
879
      {
 
880
        error = (gpos->gfunc)( gpi->face, glyph_index, load_flags );
 
881
        if ( error )
 
882
          return error;
 
883
 
 
884
        if ( gpi->face->glyph->format != ft_glyph_format_outline )
 
885
          return TTO_Err_Invalid_GPOS_SubTable;
 
886
 
 
887
        ap = an->af.af2.AnchorPoint;
 
888
 
 
889
        outline = gpi->face->glyph->outline;
 
890
 
 
891
        /* if outline.n_points is set to zero by gfunc(), we use the
 
892
           design coordinate value pair.  This can happen e.g. for
 
893
           sbit glyphs                                               */
 
894
 
 
895
        if ( !outline.n_points )
 
896
          goto no_contour_point;
 
897
 
 
898
        if ( ap >= outline.n_points )
 
899
          return TTO_Err_Invalid_GPOS_SubTable;
 
900
 
 
901
        *x_value = outline.points[ap].x;
 
902
        *y_value = outline.points[ap].y;
 
903
      }
 
904
      else
 
905
      {
 
906
      no_contour_point:
 
907
        *x_value = x_scale * an->af.af3.XCoordinate / 0x10000;
 
908
        *y_value = y_scale * an->af.af3.YCoordinate / 0x10000;
 
909
      }
 
910
      break;
 
911
 
 
912
    case 3:
 
913
      if ( !gpi->dvi )
 
914
      {
 
915
        Get_Device( &an->af.af3.XDeviceTable, x_ppem, &pixel_value );
 
916
        *x_value = pixel_value << 6;
 
917
        Get_Device( &an->af.af3.YDeviceTable, y_ppem, &pixel_value );
 
918
        *y_value = pixel_value << 6;
 
919
      }
 
920
      else
 
921
        *x_value = *y_value = 0;
 
922
 
 
923
      *x_value += x_scale * an->af.af3.XCoordinate / 0x10000;
 
924
      *y_value += y_scale * an->af.af3.YCoordinate / 0x10000;
 
925
      break;
 
926
 
 
927
    case 4:
 
928
      error = (gpos->mmfunc)( gpi->face, an->af.af4.XIdAnchor,
 
929
                              x_value, gpos->data );
 
930
      if ( error )
 
931
        return error;
 
932
 
 
933
      error = (gpos->mmfunc)( gpi->face, an->af.af4.YIdAnchor,
 
934
                              y_value, gpos->data );
 
935
      if ( error )
 
936
        return error;
 
937
      break;
 
938
    }
 
939
 
 
940
    return error;
 
941
  }
 
942
 
 
943
 
 
944
  /* MarkArray */
 
945
 
 
946
  static FT_Error  Load_MarkArray ( TTO_MarkArray*  ma,
 
947
                                    FT_Stream       stream )
 
948
  {
 
949
    FT_Error  error;
 
950
    FT_Memory memory = stream->memory;
 
951
 
 
952
    FT_UShort        n, m, count;
 
953
    FT_ULong         cur_offset, new_offset, base_offset;
 
954
 
 
955
    TTO_MarkRecord*  mr;
 
956
 
 
957
 
 
958
    base_offset = FILE_Pos();
 
959
 
 
960
    if ( ACCESS_Frame( 2L ) )
 
961
      return error;
 
962
 
 
963
    count = ma->MarkCount = GET_UShort();
 
964
 
 
965
    FORGET_Frame();
 
966
 
 
967
    ma->MarkRecord = NULL;
 
968
 
 
969
    if ( ALLOC_ARRAY( ma->MarkRecord, count, TTO_MarkRecord ) )
 
970
      return error;
 
971
 
 
972
    mr = ma->MarkRecord;
 
973
 
 
974
    for ( n = 0; n < count; n++ )
 
975
    {
 
976
      if ( ACCESS_Frame( 4L ) )
 
977
        goto Fail;
 
978
 
 
979
      mr[n].Class = GET_UShort();
 
980
      new_offset  = GET_UShort() + base_offset;
 
981
 
 
982
      FORGET_Frame();
 
983
 
 
984
      cur_offset = FILE_Pos();
 
985
      if ( FILE_Seek( new_offset ) ||
 
986
           ( error = Load_Anchor( &mr[n].MarkAnchor, stream ) ) != TT_Err_Ok )
 
987
        goto Fail;
 
988
      (void)FILE_Seek( cur_offset );
 
989
    }
 
990
 
 
991
    return TT_Err_Ok;
 
992
 
 
993
  Fail:
 
994
    for ( m = 0; m < n; m++ )
 
995
      Free_Anchor( &mr[m].MarkAnchor, memory );
 
996
 
 
997
    FREE( mr );
 
998
    return error;
 
999
  }
 
1000
 
 
1001
 
 
1002
  static void  Free_MarkArray( TTO_MarkArray*  ma,
 
1003
                               FT_Memory       memory )
 
1004
  {
 
1005
    FT_UShort        n, count;
 
1006
 
 
1007
    TTO_MarkRecord*  mr;
 
1008
 
 
1009
 
 
1010
    if ( ma->MarkRecord )
 
1011
    {
 
1012
      count = ma->MarkCount;
 
1013
      mr    = ma->MarkRecord;
 
1014
 
 
1015
      for ( n = 0; n < count; n++ )
 
1016
        Free_Anchor( &mr[n].MarkAnchor, memory );
 
1017
 
 
1018
      FREE( mr );
 
1019
    }
 
1020
  }
 
1021
 
 
1022
 
 
1023
  /* LookupType 1 */
 
1024
 
 
1025
  /* SinglePosFormat1 */
 
1026
  /* SinglePosFormat2 */
 
1027
 
 
1028
  FT_Error  Load_SinglePos( TTO_SinglePos*  sp,
 
1029
                            FT_Stream       stream )
 
1030
  {
 
1031
    FT_Error  error;
 
1032
    FT_Memory memory = stream->memory;
 
1033
 
 
1034
    FT_UShort         n, m, count, format;
 
1035
    FT_ULong          cur_offset, new_offset, base_offset;
 
1036
 
 
1037
    TTO_ValueRecord*  vr;
 
1038
 
 
1039
 
 
1040
    base_offset = FILE_Pos();
 
1041
 
 
1042
    if ( ACCESS_Frame( 6L ) )
 
1043
      return error;
 
1044
 
 
1045
    sp->PosFormat = GET_UShort();
 
1046
    new_offset    = GET_UShort() + base_offset;
 
1047
 
 
1048
    format = sp->ValueFormat = GET_UShort();
 
1049
 
 
1050
    FORGET_Frame();
 
1051
 
 
1052
    if ( !format )
 
1053
      return TTO_Err_Invalid_GPOS_SubTable;
 
1054
 
 
1055
    cur_offset = FILE_Pos();
 
1056
    if ( FILE_Seek( new_offset ) ||
 
1057
         ( error = Load_Coverage( &sp->Coverage, stream ) ) != TT_Err_Ok )
 
1058
      return error;
 
1059
    (void)FILE_Seek( cur_offset );
 
1060
 
 
1061
    switch ( sp->PosFormat )
 
1062
    {
 
1063
    case 1:
 
1064
      error = Load_ValueRecord( &sp->spf.spf1.Value, format,
 
1065
                                base_offset, stream );
 
1066
      if ( error )
 
1067
        goto Fail2;
 
1068
      break;
 
1069
 
 
1070
    case 2:
 
1071
      if ( ACCESS_Frame( 2L ) )
 
1072
        goto Fail2;
 
1073
 
 
1074
      count = sp->spf.spf2.ValueCount = GET_UShort();
 
1075
 
 
1076
      FORGET_Frame();
 
1077
 
 
1078
      sp->spf.spf2.Value = NULL;
 
1079
 
 
1080
      if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, TTO_ValueRecord ) )
 
1081
        goto Fail2;
 
1082
 
 
1083
      vr = sp->spf.spf2.Value;
 
1084
 
 
1085
      for ( n = 0; n < count; n++ )
 
1086
      {
 
1087
        error = Load_ValueRecord( &vr[n], format, base_offset, stream );
 
1088
        if ( error )
 
1089
          goto Fail1;
 
1090
      }
 
1091
      break;
 
1092
 
 
1093
    default:
 
1094
      return TTO_Err_Invalid_GPOS_SubTable_Format;
 
1095
    }
 
1096
 
 
1097
    return TT_Err_Ok;
 
1098
 
 
1099
  Fail1:
 
1100
    for ( m = 0; m < n; m++ )
 
1101
      Free_ValueRecord( &vr[m], format, memory );
 
1102
 
 
1103
    FREE( vr );
 
1104
 
 
1105
  Fail2:
 
1106
    Free_Coverage( &sp->Coverage, memory );
 
1107
    return error;
 
1108
  }
 
1109
 
 
1110
 
 
1111
  void  Free_SinglePos( TTO_SinglePos*  sp,
 
1112
                        FT_Memory       memory )
 
1113
  {
 
1114
    FT_UShort         n, count, format;
 
1115
 
 
1116
    TTO_ValueRecord*  v;
 
1117
 
 
1118
 
 
1119
    format = sp->ValueFormat;
 
1120
 
 
1121
    switch ( sp->PosFormat )
 
1122
    {
 
1123
    case 1:
 
1124
      Free_ValueRecord( &sp->spf.spf1.Value, format, memory );
 
1125
      break;
 
1126
 
 
1127
    case 2:
 
1128
      if ( sp->spf.spf2.Value )
 
1129
      {
 
1130
        count = sp->spf.spf2.ValueCount;
 
1131
        v     = sp->spf.spf2.Value;
 
1132
 
 
1133
        for ( n = 0; n < count; n++ )
 
1134
          Free_ValueRecord( &v[n], format, memory );
 
1135
 
 
1136
        FREE( v );
 
1137
      }
 
1138
      break;
 
1139
    }
 
1140
 
 
1141
    Free_Coverage( &sp->Coverage, memory );
 
1142
  }
 
1143
 
 
1144
 
 
1145
  static FT_Error  Lookup_SinglePos( GPOS_Instance*    gpi,
 
1146
                                     TTO_SinglePos*    sp,
 
1147
                                     TTO_GSUB_String*  in,
 
1148
                                     TTO_GPOS_Data*    out,
 
1149
                                     FT_UShort         flags,
 
1150
                                     FT_UShort         context_length )
 
1151
  {
 
1152
    FT_UShort        index, property;
 
1153
    FT_Error         error;
 
1154
    TTO_GPOSHeader*  gpos = gpi->gpos;
 
1155
 
 
1156
 
 
1157
    if ( context_length != 0xFFFF && context_length < 1 )
 
1158
      return TTO_Err_Not_Covered;
 
1159
 
 
1160
    if ( CHECK_Property( gpos->gdef, in->string[in->pos], flags, &property ) )
 
1161
      return error;
 
1162
 
 
1163
    error = Coverage_Index( &sp->Coverage, in->string[in->pos], &index );
 
1164
    if ( error )
 
1165
      return error;
 
1166
 
 
1167
    switch ( sp->PosFormat )
 
1168
    {
 
1169
    case 1:
 
1170
      error = Get_ValueRecord( gpi, &sp->spf.spf1.Value,
 
1171
                               sp->ValueFormat, &out[in->pos] );
 
1172
      if ( error )
 
1173
        return error;
 
1174
      break;
 
1175
 
 
1176
    case 2:
 
1177
      if ( index >= sp->spf.spf2.ValueCount )
 
1178
        return TTO_Err_Invalid_GPOS_SubTable;
 
1179
      error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index],
 
1180
                               sp->ValueFormat, &out[in->pos] );
 
1181
      if ( error )
 
1182
        return error;
 
1183
      break;
 
1184
 
 
1185
    default:
 
1186
      return TTO_Err_Invalid_GPOS_SubTable;
 
1187
    }
 
1188
 
 
1189
    (in->pos)++;
 
1190
 
 
1191
    return TT_Err_Ok;
 
1192
  }
 
1193
 
 
1194
 
 
1195
  /* LookupType 2 */
 
1196
 
 
1197
  /* PairSet */
 
1198
 
 
1199
  static FT_Error  Load_PairSet ( TTO_PairSet*  ps,
 
1200
                                  FT_UShort     format1,
 
1201
                                  FT_UShort     format2,
 
1202
                                  FT_Stream     stream )
 
1203
  {
 
1204
    FT_Error  error;
 
1205
    FT_Memory memory = stream->memory;
 
1206
 
 
1207
    FT_UShort             n, m, count;
 
1208
    FT_ULong              base_offset;
 
1209
 
 
1210
    TTO_PairValueRecord*  pvr;
 
1211
 
 
1212
 
 
1213
    base_offset = FILE_Pos();
 
1214
 
 
1215
    if ( ACCESS_Frame( 2L ) )
 
1216
      return error;
 
1217
 
 
1218
    count = ps->PairValueCount = GET_UShort();
 
1219
 
 
1220
    FORGET_Frame();
 
1221
 
 
1222
    ps->PairValueRecord = NULL;
 
1223
 
 
1224
    if ( ALLOC_ARRAY( ps->PairValueRecord, count, TTO_PairValueRecord ) )
 
1225
      return error;
 
1226
 
 
1227
    pvr = ps->PairValueRecord;
 
1228
 
 
1229
    for ( n = 0; n < count; n++ )
 
1230
    {
 
1231
      if ( ACCESS_Frame( 2L ) )
 
1232
        goto Fail;
 
1233
 
 
1234
      pvr[n].SecondGlyph = GET_UShort();
 
1235
 
 
1236
      FORGET_Frame();
 
1237
 
 
1238
      if ( format1 )
 
1239
      {
 
1240
        error = Load_ValueRecord( &pvr[n].Value1, format1,
 
1241
                                  base_offset, stream );
 
1242
        if ( error )
 
1243
          goto Fail;
 
1244
      }
 
1245
      if ( format2 )
 
1246
      {
 
1247
        error = Load_ValueRecord( &pvr[n].Value2, format2,
 
1248
                                  base_offset, stream );
 
1249
        if ( error )
 
1250
        {
 
1251
          if ( format1 )
 
1252
            Free_ValueRecord( &pvr[n].Value1, format1, memory );
 
1253
          goto Fail;
 
1254
        }
 
1255
      }
 
1256
    }
 
1257
 
 
1258
    return TT_Err_Ok;
 
1259
 
 
1260
  Fail:
 
1261
    for ( m = 0; m < n; m++ )
 
1262
    {
 
1263
      if ( format1 )
 
1264
        Free_ValueRecord( &pvr[m].Value1, format1, memory );
 
1265
      if ( format2 )
 
1266
        Free_ValueRecord( &pvr[m].Value2, format2, memory );
 
1267
    }
 
1268
 
 
1269
    FREE( pvr );
 
1270
    return error;
 
1271
  }
 
1272
 
 
1273
 
 
1274
  static void  Free_PairSet( TTO_PairSet*  ps,
 
1275
                             FT_UShort     format1,
 
1276
                             FT_UShort     format2,
 
1277
                             FT_Memory     memory )
 
1278
  {
 
1279
    FT_UShort             n, count;
 
1280
 
 
1281
    TTO_PairValueRecord*  pvr;
 
1282
 
 
1283
 
 
1284
    if ( ps->PairValueRecord )
 
1285
    {
 
1286
      count = ps->PairValueCount;
 
1287
      pvr   = ps->PairValueRecord;
 
1288
 
 
1289
      for ( n = 0; n < count; n++ )
 
1290
      {
 
1291
        if ( format1 )
 
1292
          Free_ValueRecord( &pvr[n].Value1, format1, memory );
 
1293
        if ( format2 )
 
1294
          Free_ValueRecord( &pvr[n].Value2, format2, memory );
 
1295
      }
 
1296
 
 
1297
      FREE( pvr );
 
1298
    }
 
1299
  }
 
1300
 
 
1301
 
 
1302
  /* PairPosFormat1 */
 
1303
 
 
1304
  static FT_Error  Load_PairPos1( TTO_PairPosFormat1*  ppf1,
 
1305
                                  FT_UShort            format1,
 
1306
                                  FT_UShort            format2,
 
1307
                                  FT_Stream            stream )
 
1308
  {
 
1309
    FT_Error  error;
 
1310
    FT_Memory memory = stream->memory;
 
1311
 
 
1312
    FT_UShort     n, m, count;
 
1313
    FT_ULong      cur_offset, new_offset, base_offset;
 
1314
 
 
1315
    TTO_PairSet*  ps;
 
1316
 
 
1317
 
 
1318
    base_offset = FILE_Pos() - 8L;
 
1319
 
 
1320
    if ( ACCESS_Frame( 2L ) )
 
1321
      return error;
 
1322
 
 
1323
    count = ppf1->PairSetCount = GET_UShort();
 
1324
 
 
1325
    FORGET_Frame();
 
1326
 
 
1327
    ppf1->PairSet = NULL;
 
1328
 
 
1329
    if ( ALLOC_ARRAY( ppf1->PairSet, count, TTO_PairSet ) )
 
1330
      return error;
 
1331
 
 
1332
    ps = ppf1->PairSet;
 
1333
 
 
1334
    for ( n = 0; n < count; n++ )
 
1335
    {
 
1336
      if ( ACCESS_Frame( 2L ) )
 
1337
        goto Fail;
 
1338
 
 
1339
      new_offset = GET_UShort() + base_offset;
 
1340
 
 
1341
      FORGET_Frame();
 
1342
 
 
1343
      cur_offset = FILE_Pos();
 
1344
      if ( FILE_Seek( new_offset ) ||
 
1345
           ( error = Load_PairSet( &ps[n], format1,
 
1346
                                   format2, stream ) ) != TT_Err_Ok )
 
1347
        goto Fail;
 
1348
      (void)FILE_Seek( cur_offset );
 
1349
    }
 
1350
 
 
1351
    return TT_Err_Ok;
 
1352
 
 
1353
  Fail:
 
1354
    for ( m = 0; m < n; m++ )
 
1355
      Free_PairSet( &ps[m], format1, format2, memory );
 
1356
 
 
1357
    FREE( ps );
 
1358
    return error;
 
1359
  }
 
1360
 
 
1361
 
 
1362
  static void  Free_PairPos1( TTO_PairPosFormat1*  ppf1,
 
1363
                              FT_UShort            format1,
 
1364
                              FT_UShort            format2,
 
1365
                              FT_Memory            memory )
 
1366
  {
 
1367
    FT_UShort     n, count;
 
1368
 
 
1369
    TTO_PairSet*  ps;
 
1370
 
 
1371
 
 
1372
    if ( ppf1->PairSet )
 
1373
    {
 
1374
      count = ppf1->PairSetCount;
 
1375
      ps    = ppf1->PairSet;
 
1376
 
 
1377
      for ( n = 0; n < count; n++ )
 
1378
        Free_PairSet( &ps[n], format1, format2, memory );
 
1379
 
 
1380
      FREE( ps );
 
1381
    }
 
1382
  }
 
1383
 
 
1384
 
 
1385
  /* PairPosFormat2 */
 
1386
 
 
1387
  static FT_Error  Load_PairPos2( TTO_PairPosFormat2*  ppf2,
 
1388
                                  FT_UShort            format1,
 
1389
                                  FT_UShort            format2,
 
1390
                                  FT_Stream            stream )
 
1391
  {
 
1392
    FT_Error  error;
 
1393
    FT_Memory memory = stream->memory;
 
1394
 
 
1395
    FT_UShort          m, n, k, count1, count2;
 
1396
    FT_ULong           cur_offset, new_offset1, new_offset2, base_offset;
 
1397
 
 
1398
    TTO_Class1Record*  c1r;
 
1399
    TTO_Class2Record*  c2r;
 
1400
 
 
1401
 
 
1402
    base_offset = FILE_Pos() - 8L;
 
1403
 
 
1404
    if ( ACCESS_Frame( 8L ) )
 
1405
      return error;
 
1406
 
 
1407
    new_offset1 = GET_UShort() + base_offset;
 
1408
    new_offset2 = GET_UShort() + base_offset;
 
1409
 
 
1410
    /* `Class1Count' and `Class2Count' are the upper limits for class
 
1411
       values, thus we read it now to make additional safety checks.  */
 
1412
 
 
1413
    count1 = ppf2->Class1Count = GET_UShort();
 
1414
    count2 = ppf2->Class2Count = GET_UShort();
 
1415
 
 
1416
    FORGET_Frame();
 
1417
 
 
1418
    cur_offset = FILE_Pos();
 
1419
    if ( FILE_Seek( new_offset1 ) ||
 
1420
         ( error = Load_ClassDefinition( &ppf2->ClassDef1, count1,
 
1421
                                         stream ) ) != TT_Err_Ok )
 
1422
      return error;
 
1423
    if ( FILE_Seek( new_offset2 ) ||
 
1424
         ( error = Load_ClassDefinition( &ppf2->ClassDef2, count2,
 
1425
                                         stream ) ) != TT_Err_Ok )
 
1426
      goto Fail3;
 
1427
    (void)FILE_Seek( cur_offset );
 
1428
 
 
1429
    ppf2->Class1Record = NULL;
 
1430
 
 
1431
    if ( ALLOC_ARRAY( ppf2->Class1Record, count1, TTO_Class1Record ) )
 
1432
      goto Fail2;
 
1433
 
 
1434
    c1r = ppf2->Class1Record;
 
1435
 
 
1436
    for ( m = 0; m < count1; m++ )
 
1437
    {
 
1438
      c1r[m].Class2Record = NULL;
 
1439
 
 
1440
      if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, TTO_Class2Record ) )
 
1441
        goto Fail1;
 
1442
 
 
1443
      c2r = c1r[m].Class2Record;
 
1444
 
 
1445
      for ( n = 0; n < count2; n++ )
 
1446
      {
 
1447
        if ( format1 )
 
1448
        {
 
1449
          error = Load_ValueRecord( &c2r[n].Value1, format1,
 
1450
                                    base_offset, stream );
 
1451
          if ( error )
 
1452
            goto Fail0;
 
1453
        }
 
1454
        if ( format2 )
 
1455
        {
 
1456
          error = Load_ValueRecord( &c2r[n].Value2, format2,
 
1457
                                    base_offset, stream );
 
1458
          if ( error )
 
1459
          {
 
1460
            if ( format1 )
 
1461
              Free_ValueRecord( &c2r[n].Value1, format1, memory );
 
1462
            goto Fail0;
 
1463
          }
 
1464
        }
 
1465
      }
 
1466
 
 
1467
      continue;
 
1468
 
 
1469
    Fail0:
 
1470
      for ( k = 0; k < n; k++ )
 
1471
      {
 
1472
        if ( format1 )
 
1473
          Free_ValueRecord( &c2r[k].Value1, format1, memory );
 
1474
        if ( format2 )
 
1475
          Free_ValueRecord( &c2r[k].Value2, format2, memory );
 
1476
      }
 
1477
      goto Fail1;
 
1478
    }
 
1479
 
 
1480
    return TT_Err_Ok;
 
1481
 
 
1482
  Fail1:
 
1483
    for ( k = 0; k < m; k++ )
 
1484
    {
 
1485
      c2r = c1r[k].Class2Record;
 
1486
 
 
1487
      for ( n = 0; n < count2; n++ )
 
1488
      {
 
1489
        if ( format1 )
 
1490
          Free_ValueRecord( &c2r[n].Value1, format1, memory );
 
1491
        if ( format2 )
 
1492
          Free_ValueRecord( &c2r[n].Value2, format2, memory );
 
1493
      }
 
1494
 
 
1495
      FREE( c2r );
 
1496
    }
 
1497
 
 
1498
    FREE( c1r );
 
1499
  Fail2:
 
1500
 
 
1501
    Free_ClassDefinition( &ppf2->ClassDef2, memory );
 
1502
 
 
1503
  Fail3:
 
1504
    Free_ClassDefinition( &ppf2->ClassDef1, memory );
 
1505
    return error;
 
1506
  }
 
1507
 
 
1508
 
 
1509
  static void  Free_PairPos2( TTO_PairPosFormat2*  ppf2,
 
1510
                              FT_UShort            format1,
 
1511
                              FT_UShort            format2,
 
1512
                              FT_Memory            memory )
 
1513
  {
 
1514
    FT_UShort          m, n, count1, count2;
 
1515
 
 
1516
    TTO_Class1Record*  c1r;
 
1517
    TTO_Class2Record*  c2r;
 
1518
 
 
1519
 
 
1520
    if ( ppf2->Class1Record )
 
1521
    {
 
1522
      c1r    = ppf2->Class1Record;
 
1523
      count1 = ppf2->Class1Count;
 
1524
      count2 = ppf2->Class2Count;
 
1525
 
 
1526
      for ( m = 0; m < count1; m++ )
 
1527
      {
 
1528
        c2r = c1r[m].Class2Record;
 
1529
 
 
1530
        for ( n = 0; n < count2; n++ )
 
1531
        {
 
1532
          if ( format1 )
 
1533
            Free_ValueRecord( &c2r[n].Value1, format1, memory );
 
1534
          if ( format2 )
 
1535
            Free_ValueRecord( &c2r[n].Value2, format2, memory );
 
1536
        }
 
1537
 
 
1538
        FREE( c2r );
 
1539
      }
 
1540
 
 
1541
      FREE( c1r );
 
1542
 
 
1543
      Free_ClassDefinition( &ppf2->ClassDef2, memory );
 
1544
      Free_ClassDefinition( &ppf2->ClassDef1, memory );
 
1545
    }
 
1546
  }
 
1547
 
 
1548
 
 
1549
  FT_Error  Load_PairPos( TTO_PairPos*  pp,
 
1550
                          FT_Stream     stream )
 
1551
  {
 
1552
    FT_Error  error;
 
1553
    FT_Memory memory = stream->memory;
 
1554
 
 
1555
    FT_UShort         format1, format2;
 
1556
    FT_ULong          cur_offset, new_offset, base_offset;
 
1557
 
 
1558
 
 
1559
    base_offset = FILE_Pos();
 
1560
 
 
1561
    if ( ACCESS_Frame( 8L ) )
 
1562
      return error;
 
1563
 
 
1564
    pp->PosFormat = GET_UShort();
 
1565
    new_offset    = GET_UShort() + base_offset;
 
1566
 
 
1567
    format1 = pp->ValueFormat1 = GET_UShort();
 
1568
    format2 = pp->ValueFormat2 = GET_UShort();
 
1569
 
 
1570
    FORGET_Frame();
 
1571
 
 
1572
    cur_offset = FILE_Pos();
 
1573
    if ( FILE_Seek( new_offset ) ||
 
1574
         ( error = Load_Coverage( &pp->Coverage, stream ) ) != TT_Err_Ok )
 
1575
      return error;
 
1576
    (void)FILE_Seek( cur_offset );
 
1577
 
 
1578
    switch ( pp->PosFormat )
 
1579
    {
 
1580
    case 1:
 
1581
      error = Load_PairPos1( &pp->ppf.ppf1, format1, format2, stream );
 
1582
      if ( error )
 
1583
        goto Fail;
 
1584
      break;
 
1585
 
 
1586
    case 2:
 
1587
      error = Load_PairPos2( &pp->ppf.ppf2, format1, format2, stream );
 
1588
      if ( error )
 
1589
        goto Fail;
 
1590
      break;
 
1591
 
 
1592
    default:
 
1593
      return TTO_Err_Invalid_GPOS_SubTable_Format;
 
1594
    }
 
1595
 
 
1596
    return TT_Err_Ok;
 
1597
 
 
1598
  Fail:
 
1599
    Free_Coverage( &pp->Coverage, memory );
 
1600
    return error;
 
1601
  }
 
1602
 
 
1603
 
 
1604
  void  Free_PairPos( TTO_PairPos*  pp,
 
1605
                      FT_Memory     memory )
 
1606
  {
 
1607
    FT_UShort  format1, format2;
 
1608
 
 
1609
 
 
1610
    format1 = pp->ValueFormat1;
 
1611
    format2 = pp->ValueFormat2;
 
1612
 
 
1613
    switch ( pp->PosFormat )
 
1614
    {
 
1615
    case 1:
 
1616
      Free_PairPos1( &pp->ppf.ppf1, format1, format2, memory );
 
1617
      break;
 
1618
 
 
1619
    case 2:
 
1620
      Free_PairPos2( &pp->ppf.ppf2, format1, format2, memory );
 
1621
      break;
 
1622
    }
 
1623
 
 
1624
    Free_Coverage( &pp->Coverage, memory );
 
1625
  }
 
1626
 
 
1627
 
 
1628
  static FT_Error  Lookup_PairPos1( GPOS_Instance*       gpi,
 
1629
                                    TTO_PairPosFormat1*  ppf1,
 
1630
                                    TTO_GSUB_String*     in,
 
1631
                                    TTO_GPOS_Data*       out,
 
1632
                                    FT_UShort            first_pos,
 
1633
                                    FT_UShort            index,
 
1634
                                    FT_UShort            format1,
 
1635
                                    FT_UShort            format2 )
 
1636
  {
 
1637
    FT_Error              error;
 
1638
    FT_UShort             numpvr, glyph2;
 
1639
 
 
1640
    TTO_PairValueRecord*  pvr;
 
1641
 
 
1642
 
 
1643
    if ( index >= ppf1->PairSetCount )
 
1644
       return TTO_Err_Invalid_GPOS_SubTable;
 
1645
 
 
1646
    pvr = ppf1->PairSet[index].PairValueRecord;
 
1647
    if ( !pvr )
 
1648
      return TTO_Err_Invalid_GPOS_SubTable;
 
1649
 
 
1650
    glyph2 = in->string[in->pos];
 
1651
 
 
1652
    for ( numpvr = ppf1->PairSet[index].PairValueCount;
 
1653
          numpvr;
 
1654
          numpvr--, pvr++ )
 
1655
    {
 
1656
      if ( glyph2 == pvr->SecondGlyph )
 
1657
      {
 
1658
        error = Get_ValueRecord( gpi, &pvr->Value1, format1,
 
1659
                                 &out[first_pos] );
 
1660
        if ( error )
 
1661
          return error;
 
1662
        return Get_ValueRecord( gpi, &pvr->Value2, format2,
 
1663
                                &out[in->pos] );
 
1664
      }
 
1665
    }
 
1666
 
 
1667
    return TTO_Err_Not_Covered;
 
1668
  }
 
1669
 
 
1670
 
 
1671
  static FT_Error  Lookup_PairPos2( GPOS_Instance*       gpi,
 
1672
                                    TTO_PairPosFormat2*  ppf2,
 
1673
                                    TTO_GSUB_String*     in,
 
1674
                                    TTO_GPOS_Data*       out,
 
1675
                                    FT_UShort            first_pos,
 
1676
                                    FT_UShort            format1,
 
1677
                                    FT_UShort            format2 )
 
1678
  {
 
1679
    FT_Error           error;
 
1680
    FT_UShort          cl1, cl2;
 
1681
 
 
1682
    TTO_Class1Record*  c1r;
 
1683
    TTO_Class2Record*  c2r;
 
1684
 
 
1685
 
 
1686
    error = Get_Class( &ppf2->ClassDef1, in->string[first_pos],
 
1687
                       &cl1, NULL );
 
1688
    if ( error && error != TTO_Err_Not_Covered )
 
1689
      return error;
 
1690
    error = Get_Class( &ppf2->ClassDef2, in->string[in->pos],
 
1691
                       &cl2, NULL );
 
1692
    if ( error && error != TTO_Err_Not_Covered )
 
1693
      return error;
 
1694
 
 
1695
    c1r = &ppf2->Class1Record[cl1];
 
1696
    if ( !c1r )
 
1697
      return TTO_Err_Invalid_GPOS_SubTable;
 
1698
    c2r = &c1r->Class2Record[cl2];
 
1699
 
 
1700
    error = Get_ValueRecord( gpi, &c2r->Value1, format1, &out[first_pos] );
 
1701
    if ( error )
 
1702
      return error;
 
1703
    return Get_ValueRecord( gpi, &c2r->Value2, format2, &out[in->pos] );
 
1704
  }
 
1705
 
 
1706
 
 
1707
  static FT_Error  Lookup_PairPos( GPOS_Instance*    gpi,
 
1708
                                   TTO_PairPos*      pp,
 
1709
                                   TTO_GSUB_String*  in,
 
1710
                                   TTO_GPOS_Data*    out,
 
1711
                                   FT_UShort         flags,
 
1712
                                   FT_UShort         context_length )
 
1713
  {
 
1714
    FT_Error         error;
 
1715
    FT_UShort        index, property, first_pos;
 
1716
    TTO_GPOSHeader*  gpos = gpi->gpos;
 
1717
 
 
1718
 
 
1719
    if ( in->pos >= in->length - 1 )
 
1720
      return TTO_Err_Not_Covered;           /* Not enough glyphs in stream */
 
1721
 
 
1722
    if ( context_length != 0xFFFF && context_length < 2 )
 
1723
      return TTO_Err_Not_Covered;
 
1724
 
 
1725
    error = Coverage_Index( &pp->Coverage, in->string[in->pos], &index );
 
1726
    if ( error )
 
1727
      return error;
 
1728
 
 
1729
    if ( CHECK_Property( gpos->gdef, in->string[in->pos], flags, &property ) )
 
1730
      return error;
 
1731
 
 
1732
    /* second glyph */
 
1733
 
 
1734
    first_pos = in->pos;
 
1735
    (in->pos)++;
 
1736
 
 
1737
    while ( CHECK_Property( gpos->gdef, in->string[in->pos],
 
1738
                            flags, &property ) )
 
1739
    {
 
1740
      if ( error && error != TTO_Err_Not_Covered )
 
1741
        return error;
 
1742
 
 
1743
      if ( in->pos < in->length )
 
1744
        (in->pos)++;
 
1745
      else
 
1746
        break;
 
1747
    }
 
1748
 
 
1749
    if ( pp->PosFormat == 1 )
 
1750
      error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, in, out,
 
1751
                               first_pos, index,
 
1752
                               pp->ValueFormat1, pp->ValueFormat2 );
 
1753
    else if ( pp->PosFormat == 2 )
 
1754
      error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, in, out, first_pos,
 
1755
                               pp->ValueFormat1, pp->ValueFormat2 );
 
1756
    else
 
1757
      return TTO_Err_Invalid_GPOS_SubTable_Format;
 
1758
 
 
1759
    /* adjusting the `next' glyph */
 
1760
 
 
1761
    if ( pp->ValueFormat2 )
 
1762
      (in->pos)++;
 
1763
 
 
1764
    return error;
 
1765
  }
 
1766
 
 
1767
 
 
1768
  /* LookupType 3 */
 
1769
 
 
1770
  /* CursivePosFormat1 */
 
1771
 
 
1772
  FT_Error  Load_CursivePos( TTO_CursivePos*  cp,
 
1773
                             FT_Stream        stream )
 
1774
  {
 
1775
    FT_Error  error;
 
1776
    FT_Memory memory = stream->memory;
 
1777
 
 
1778
    FT_UShort             n, m, count;
 
1779
    FT_ULong              cur_offset, new_offset, base_offset;
 
1780
 
 
1781
    TTO_EntryExitRecord*  eer;
 
1782
 
 
1783
 
 
1784
    base_offset = FILE_Pos();
 
1785
 
 
1786
    if ( ACCESS_Frame( 4L ) )
 
1787
      return error;
 
1788
 
 
1789
    cp->PosFormat = GET_UShort();
 
1790
    new_offset    = GET_UShort() + base_offset;
 
1791
 
 
1792
    FORGET_Frame();
 
1793
 
 
1794
    cur_offset = FILE_Pos();
 
1795
    if ( FILE_Seek( new_offset ) ||
 
1796
         ( error = Load_Coverage( &cp->Coverage, stream ) ) != TT_Err_Ok )
 
1797
      return error;
 
1798
    (void)FILE_Seek( cur_offset );
 
1799
 
 
1800
    if ( ACCESS_Frame( 2L ) )
 
1801
      goto Fail2;
 
1802
 
 
1803
    count = cp->EntryExitCount = GET_UShort();
 
1804
 
 
1805
    FORGET_Frame();
 
1806
 
 
1807
    cp->EntryExitRecord = NULL;
 
1808
 
 
1809
    if ( ALLOC_ARRAY( cp->EntryExitRecord, count, TTO_EntryExitRecord ) )
 
1810
      goto Fail2;
 
1811
 
 
1812
    eer = cp->EntryExitRecord;
 
1813
 
 
1814
    for ( n = 0; n < count; n++ )
 
1815
    {
 
1816
      FT_ULong entry_offset;
 
1817
 
 
1818
      if ( ACCESS_Frame( 2L ) )
 
1819
        return error;
 
1820
 
 
1821
      entry_offset = new_offset = GET_UShort();
 
1822
 
 
1823
      FORGET_Frame();
 
1824
 
 
1825
      if ( new_offset )
 
1826
      {
 
1827
        new_offset += base_offset;
 
1828
 
 
1829
        cur_offset = FILE_Pos();
 
1830
        if ( FILE_Seek( new_offset ) ||
 
1831
             ( error = Load_Anchor( &eer[n].EntryAnchor,
 
1832
                                    stream ) ) != TT_Err_Ok )
 
1833
          goto Fail1;
 
1834
        (void)FILE_Seek( cur_offset );
 
1835
      }
 
1836
      else
 
1837
        eer[n].EntryAnchor.PosFormat   = 0;
 
1838
 
 
1839
      if ( ACCESS_Frame( 2L ) )
 
1840
        return error;
 
1841
 
 
1842
      new_offset = GET_UShort();
 
1843
 
 
1844
      FORGET_Frame();
 
1845
 
 
1846
      if ( new_offset )
 
1847
      {
 
1848
        new_offset += base_offset;
 
1849
 
 
1850
        cur_offset = FILE_Pos();
 
1851
        if ( FILE_Seek( new_offset ) ||
 
1852
             ( error = Load_Anchor( &eer[n].ExitAnchor,
 
1853
                                    stream ) ) != TT_Err_Ok )
 
1854
        {
 
1855
          if ( entry_offset )
 
1856
            Free_Anchor( &eer[n].EntryAnchor, memory );
 
1857
          goto Fail1;
 
1858
        }
 
1859
        (void)FILE_Seek( cur_offset );
 
1860
      }
 
1861
      else
 
1862
        eer[n].ExitAnchor.PosFormat   = 0;
 
1863
    }
 
1864
 
 
1865
    return TT_Err_Ok;
 
1866
 
 
1867
  Fail1:
 
1868
    for ( m = 0; m < n; m++ )
 
1869
    {
 
1870
      Free_Anchor( &eer[m].EntryAnchor, memory );
 
1871
      Free_Anchor( &eer[m].ExitAnchor, memory );
 
1872
    }
 
1873
 
 
1874
    FREE( eer );
 
1875
 
 
1876
  Fail2:
 
1877
    Free_Coverage( &cp->Coverage, memory );
 
1878
    return error;
 
1879
  }
 
1880
 
 
1881
 
 
1882
  void  Free_CursivePos( TTO_CursivePos*  cp,
 
1883
                         FT_Memory        memory )
 
1884
  {
 
1885
    FT_UShort             n, count;
 
1886
 
 
1887
    TTO_EntryExitRecord*  eer;
 
1888
 
 
1889
 
 
1890
    if ( cp->EntryExitRecord )
 
1891
    {
 
1892
      count = cp->EntryExitCount;
 
1893
      eer   = cp->EntryExitRecord;
 
1894
 
 
1895
      for ( n = 0; n < count; n++ )
 
1896
      {
 
1897
        Free_Anchor( &eer[n].EntryAnchor, memory );
 
1898
        Free_Anchor( &eer[n].ExitAnchor, memory );
 
1899
      }
 
1900
 
 
1901
      FREE( eer );
 
1902
    }
 
1903
 
 
1904
    Free_Coverage( &cp->Coverage, memory );
 
1905
  }
 
1906
 
 
1907
 
 
1908
  static FT_Error  Lookup_CursivePos( GPOS_Instance*    gpi,
 
1909
                                      TTO_CursivePos*   cp,
 
1910
                                      TTO_GSUB_String*  in,
 
1911
                                      TTO_GPOS_Data*    out,
 
1912
                                      FT_UShort         flags,
 
1913
                                      FT_UShort         context_length )
 
1914
  {
 
1915
    FT_UShort        index, property;
 
1916
    FT_Error         error;
 
1917
    TTO_GPOSHeader*  gpos = gpi->gpos;
 
1918
 
 
1919
    TTO_EntryExitRecord*  eer;
 
1920
    FT_Pos                entry_x, entry_y;
 
1921
    FT_Pos                exit_x, exit_y;
 
1922
 
 
1923
 
 
1924
    if ( context_length != 0xFFFF && context_length < 1 )
 
1925
    {
 
1926
      gpi->last = 0xFFFF;
 
1927
      return TTO_Err_Not_Covered;
 
1928
    }
 
1929
 
 
1930
    error = Coverage_Index( &cp->Coverage, in->string[in->pos], &index );
 
1931
    if ( error )
 
1932
    {
 
1933
      gpi->last = 0xFFFF;
 
1934
      return error;
 
1935
    }
 
1936
 
 
1937
    if ( index >= cp->EntryExitCount )
 
1938
      return TTO_Err_Invalid_GPOS_SubTable;
 
1939
 
 
1940
    /* Glyphs not having the right GDEF properties will be ignored, i.e.,
 
1941
       gpi->last won't be reset (contrary to user defined properties). */
 
1942
 
 
1943
    if ( CHECK_Property( gpos->gdef, in->string[in->pos], flags, &property ) )
 
1944
      return error;
 
1945
 
 
1946
    /* We don't handle mark glyphs here.  According to Andrei, this isn't
 
1947
       possible, but who knows...                                         */
 
1948
 
 
1949
    if ( property == MARK_GLYPH )
 
1950
    {
 
1951
      gpi->last = 0xFFFF;
 
1952
      return TTO_Err_Not_Covered;
 
1953
    }
 
1954
 
 
1955
 
 
1956
    eer = &cp->EntryExitRecord[index];
 
1957
 
 
1958
    /* Now comes the messiest part of the whole OpenType
 
1959
       specification.  At first glance, cursive connections seem easy
 
1960
       to understand, but there are pitfalls!  The reason is that
 
1961
       the specs don't mention how to compute the advance values
 
1962
       resp. glyph offsets.  I was told it would be an omission, to
 
1963
       be fixed in the next OpenType version...  Again many thanks to
 
1964
       Andrei Burago <andreib@microsoft.com> for clarifications.
 
1965
 
 
1966
       Consider the following example:
 
1967
 
 
1968
                        |  xadv1    |
 
1969
                         +---------+
 
1970
                         |         |
 
1971
                   +-----+--+ 1    |
 
1972
                   |     | .|      |
 
1973
                   |    0+--+------+
 
1974
                   |   2    |
 
1975
                   |        |
 
1976
                  0+--------+
 
1977
                  |  xadv2   |
 
1978
 
 
1979
         glyph1: advance width = 12
 
1980
                 anchor point = (3,1)
 
1981
 
 
1982
         glyph2: advance width = 11
 
1983
                 anchor point = (9,4)
 
1984
 
 
1985
         LSB is 1 for both glyphs (so the boxes drawn above are glyph
 
1986
         bboxes).  Writing direction is R2L; `0' denotes the glyph's
 
1987
         coordinate origin.
 
1988
 
 
1989
       Now the surprising part: The advance width of the *left* glyph
 
1990
       (resp. of the *bottom* glyph) will be modified, no matter
 
1991
       whether the writing direction is L2R or R2L (resp. T2B or
 
1992
       B2T)!  This assymetry is caused by the fact that the glyph's
 
1993
       coordinate origin is always the lower left corner for all
 
1994
       writing directions.
 
1995
 
 
1996
       Continuing the above example, we can compute the new
 
1997
       (horizontal) advance width of glyph2 as
 
1998
 
 
1999
         9 - 3 = 6  ,
 
2000
 
 
2001
       and the new vertical offset of glyph2 as
 
2002
 
 
2003
         1 - 4 = -3  .
 
2004
 
 
2005
 
 
2006
       Vertical writing direction is far more complicated:
 
2007
 
 
2008
       a) Assuming that we recompute the advance height of the lower glyph:
 
2009
 
 
2010
                                    --
 
2011
                         +---------+
 
2012
                --       |         |
 
2013
                   +-----+--+ 1    | yadv1
 
2014
                   |     | .|      |
 
2015
             yadv2 |    0+--+------+        -- BSB1  --
 
2016
                   |   2    |       --      --        y_offset
 
2017
                   |        |
 
2018
     BSB2 --      0+--------+                        --
 
2019
          --    --
 
2020
 
 
2021
         glyph1: advance height = 6
 
2022
                 anchor point = (3,1)
 
2023
 
 
2024
         glyph2: advance height = 7
 
2025
                 anchor point = (9,4)
 
2026
 
 
2027
         TSB is 1 for both glyphs; writing direction is T2B.
 
2028
 
 
2029
 
 
2030
           BSB1     = yadv1 - (TSB1 + ymax1)
 
2031
           BSB2     = yadv2 - (TSB2 + ymax2)
 
2032
           y_offset = y2 - y1
 
2033
 
 
2034
         vertical advance width of glyph2
 
2035
           = y_offset + BSB2 - BSB1
 
2036
           = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
 
2037
           = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
 
2038
           = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
 
2039
 
 
2040
 
 
2041
       b) Assuming that we recompute the advance height of the upper glyph:
 
2042
 
 
2043
                                    --      --
 
2044
                         +---------+        -- TSB1
 
2045
          --    --       |         |
 
2046
     TSB2 --       +-----+--+ 1    | yadv1   ymax1
 
2047
                   |     | .|      |
 
2048
             yadv2 |    0+--+------+        --       --
 
2049
      ymax2        |   2    |       --                y_offset
 
2050
                   |        |
 
2051
          --      0+--------+                        --
 
2052
                --
 
2053
 
 
2054
         glyph1: advance height = 6
 
2055
                 anchor point = (3,1)
 
2056
 
 
2057
         glyph2: advance height = 7
 
2058
                 anchor point = (9,4)
 
2059
 
 
2060
         TSB is 1 for both glyphs; writing direction is T2B.
 
2061
 
 
2062
         y_offset = y2 - y1
 
2063
 
 
2064
         vertical advance width of glyph2
 
2065
           = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
 
2066
           = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
 
2067
 
 
2068
 
 
2069
       Comparing a) with b) shows that b) is easier to compute.  I'll wait
 
2070
       for a reply from Andrei to see what should really be implemented...
 
2071
 
 
2072
       Since horizontal advance widths or vertical advance heights
 
2073
       can be used alone but not together, no ambiguity occurs.        */
 
2074
 
 
2075
    if ( gpi->last == 0xFFFF )
 
2076
      goto end;
 
2077
 
 
2078
    /* Get_Anchor() returns TTO_Err_Not_Covered if there is no anchor
 
2079
       table.                                                         */
 
2080
 
 
2081
    error = Get_Anchor( gpi, &eer->EntryAnchor, in->string[in->pos],
 
2082
                        &entry_x, &entry_y );
 
2083
    if ( error == TTO_Err_Not_Covered )
 
2084
      goto end;
 
2085
    if ( error )
 
2086
      return error;
 
2087
 
 
2088
    if ( gpi->r2l )
 
2089
    {
 
2090
      out[in->pos].x_advance   = entry_x - gpi->anchor_x;
 
2091
      out[in->pos].new_advance = TRUE;
 
2092
    }
 
2093
    else
 
2094
    {
 
2095
      out[gpi->last].x_advance   = gpi->anchor_x - entry_x;
 
2096
      out[gpi->last].new_advance = TRUE;
 
2097
    }
 
2098
 
 
2099
    out[in->pos].y_pos = gpi->anchor_y - entry_y + out[gpi->last].y_pos;
 
2100
 
 
2101
  end:
 
2102
    error = Get_Anchor( gpi, &eer->ExitAnchor, in->string[in->pos],
 
2103
                        &exit_x, &exit_y );
 
2104
    if ( error == TTO_Err_Not_Covered )
 
2105
      gpi->last = 0xFFFF;
 
2106
    else
 
2107
    {
 
2108
      if ( gpi->first == 0xFFFF )
 
2109
        gpi->first  = in->pos;
 
2110
      gpi->last     = in->pos;
 
2111
      gpi->anchor_x = exit_x;
 
2112
      gpi->anchor_y = exit_y;
 
2113
    }
 
2114
    if ( error )
 
2115
      return error;
 
2116
 
 
2117
    (in->pos)++;
 
2118
 
 
2119
    return TT_Err_Ok;
 
2120
  }
 
2121
 
 
2122
 
 
2123
  /* LookupType 4 */
 
2124
 
 
2125
  /* BaseArray */
 
2126
 
 
2127
  static FT_Error  Load_BaseArray( TTO_BaseArray*  ba,
 
2128
                                   FT_UShort       num_classes,
 
2129
                                   FT_Stream       stream )
 
2130
  {
 
2131
    FT_Error  error;
 
2132
    FT_Memory memory = stream->memory;
 
2133
 
 
2134
    FT_UShort        m, n, k, count;
 
2135
    FT_ULong         cur_offset, new_offset, base_offset;
 
2136
 
 
2137
    TTO_BaseRecord*  br;
 
2138
    TTO_Anchor*      ban;
 
2139
 
 
2140
 
 
2141
    base_offset = FILE_Pos();
 
2142
 
 
2143
    if ( ACCESS_Frame( 2L ) )
 
2144
      return error;
 
2145
 
 
2146
    count = ba->BaseCount = GET_UShort();
 
2147
 
 
2148
    FORGET_Frame();
 
2149
 
 
2150
    ba->BaseRecord = NULL;
 
2151
 
 
2152
    if ( ALLOC_ARRAY( ba->BaseRecord, count, TTO_BaseRecord ) )
 
2153
      return error;
 
2154
 
 
2155
    br = ba->BaseRecord;
 
2156
 
 
2157
    for ( m = 0; m < count; m++ )
 
2158
    {
 
2159
      br[m].BaseAnchor = NULL;
 
2160
 
 
2161
      if ( ALLOC_ARRAY( br[m].BaseAnchor, num_classes, TTO_Anchor ) )
 
2162
        goto Fail;
 
2163
 
 
2164
      ban = br[m].BaseAnchor;
 
2165
 
 
2166
      for ( n = 0; n < num_classes; n++ )
 
2167
      {
 
2168
        if ( ACCESS_Frame( 2L ) )
 
2169
          goto Fail0;
 
2170
 
 
2171
        new_offset = GET_UShort() + base_offset;
 
2172
 
 
2173
        FORGET_Frame();
 
2174
 
 
2175
        cur_offset = FILE_Pos();
 
2176
        if ( FILE_Seek( new_offset ) ||
 
2177
             ( error = Load_Anchor( &ban[n], stream ) ) != TT_Err_Ok )
 
2178
          goto Fail0;
 
2179
        (void)FILE_Seek( cur_offset );
 
2180
      }
 
2181
 
 
2182
      continue;
 
2183
    Fail0:
 
2184
      for ( k = 0; k < n; k++ )
 
2185
        Free_Anchor( &ban[k], memory );
 
2186
      goto Fail;
 
2187
    }
 
2188
 
 
2189
    return TT_Err_Ok;
 
2190
 
 
2191
  Fail:
 
2192
    for ( k = 0; k < m; k++ )
 
2193
    {
 
2194
      ban = br[k].BaseAnchor;
 
2195
 
 
2196
      for ( n = 0; n < num_classes; n++ )
 
2197
        Free_Anchor( &ban[n], memory );
 
2198
 
 
2199
      FREE( ban );
 
2200
    }
 
2201
 
 
2202
    FREE( br );
 
2203
    return error;
 
2204
  }
 
2205
 
 
2206
 
 
2207
  static void  Free_BaseArray( TTO_BaseArray*  ba,
 
2208
                               FT_UShort       num_classes,
 
2209
                               FT_Memory       memory )
 
2210
  {
 
2211
    FT_UShort        m, n, count;
 
2212
 
 
2213
    TTO_BaseRecord*  br;
 
2214
    TTO_Anchor*      ban;
 
2215
 
 
2216
 
 
2217
    if ( ba->BaseRecord )
 
2218
    {
 
2219
      count = ba->BaseCount;
 
2220
      br    = ba->BaseRecord;
 
2221
 
 
2222
      for ( m = 0; m < count; m++ )
 
2223
      {
 
2224
        ban = br[m].BaseAnchor;
 
2225
 
 
2226
        for ( n = 0; n < num_classes; n++ )
 
2227
          Free_Anchor( &ban[n], memory );
 
2228
 
 
2229
        FREE( ban );
 
2230
      }
 
2231
 
 
2232
      FREE( br );
 
2233
    }
 
2234
  }
 
2235
 
 
2236
 
 
2237
  /* MarkBasePosFormat1 */
 
2238
 
 
2239
  FT_Error  Load_MarkBasePos( TTO_MarkBasePos*  mbp,
 
2240
                              FT_Stream         stream )
 
2241
  {
 
2242
    FT_Error  error;
 
2243
    FT_Memory memory = stream->memory;
 
2244
 
 
2245
    FT_ULong  cur_offset, new_offset, base_offset;
 
2246
 
 
2247
 
 
2248
    base_offset = FILE_Pos();
 
2249
 
 
2250
    if ( ACCESS_Frame( 4L ) )
 
2251
      return error;
 
2252
 
 
2253
    mbp->PosFormat = GET_UShort();
 
2254
    new_offset     = GET_UShort() + base_offset;
 
2255
 
 
2256
    FORGET_Frame();
 
2257
 
 
2258
    cur_offset = FILE_Pos();
 
2259
    if ( FILE_Seek( new_offset ) ||
 
2260
         ( error = Load_Coverage( &mbp->MarkCoverage, stream ) ) != TT_Err_Ok )
 
2261
      return error;
 
2262
    (void)FILE_Seek( cur_offset );
 
2263
 
 
2264
    if ( ACCESS_Frame( 2L ) )
 
2265
      goto Fail3;
 
2266
 
 
2267
    new_offset = GET_UShort() + base_offset;
 
2268
 
 
2269
    FORGET_Frame();
 
2270
 
 
2271
    cur_offset = FILE_Pos();
 
2272
    if ( FILE_Seek( new_offset ) ||
 
2273
         ( error = Load_Coverage( &mbp->BaseCoverage, stream ) ) != TT_Err_Ok )
 
2274
      goto Fail3;
 
2275
    (void)FILE_Seek( cur_offset );
 
2276
 
 
2277
    if ( ACCESS_Frame( 4L ) )
 
2278
      goto Fail2;
 
2279
 
 
2280
    mbp->ClassCount = GET_UShort();
 
2281
    new_offset      = GET_UShort() + base_offset;
 
2282
 
 
2283
    FORGET_Frame();
 
2284
 
 
2285
    cur_offset = FILE_Pos();
 
2286
    if ( FILE_Seek( new_offset ) ||
 
2287
         ( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != TT_Err_Ok )
 
2288
      goto Fail2;
 
2289
    (void)FILE_Seek( cur_offset );
 
2290
 
 
2291
    if ( ACCESS_Frame( 2L ) )
 
2292
      goto Fail1;
 
2293
 
 
2294
    new_offset = GET_UShort() + base_offset;
 
2295
 
 
2296
    FORGET_Frame();
 
2297
 
 
2298
    cur_offset = FILE_Pos();
 
2299
    if ( FILE_Seek( new_offset ) ||
 
2300
         ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount,
 
2301
                                   stream ) ) != TT_Err_Ok )
 
2302
      goto Fail1;
 
2303
 
 
2304
    return TT_Err_Ok;
 
2305
 
 
2306
  Fail1:
 
2307
    Free_MarkArray( &mbp->MarkArray, memory );
 
2308
 
 
2309
  Fail2:
 
2310
    Free_Coverage( &mbp->BaseCoverage, memory );
 
2311
 
 
2312
  Fail3:
 
2313
    Free_Coverage( &mbp->MarkCoverage, memory );
 
2314
    return error;
 
2315
  }
 
2316
 
 
2317
 
 
2318
  void  Free_MarkBasePos( TTO_MarkBasePos*  mbp,
 
2319
                          FT_Memory         memory )
 
2320
  {
 
2321
    Free_BaseArray( &mbp->BaseArray, mbp->ClassCount, memory );
 
2322
    Free_MarkArray( &mbp->MarkArray, memory );
 
2323
    Free_Coverage( &mbp->BaseCoverage, memory );
 
2324
    Free_Coverage( &mbp->MarkCoverage, memory );
 
2325
  }
 
2326
 
 
2327
 
 
2328
  static FT_Error  Lookup_MarkBasePos( GPOS_Instance*    gpi,
 
2329
                                       TTO_MarkBasePos*  mbp,
 
2330
                                       TTO_GSUB_String*  in,
 
2331
                                       TTO_GPOS_Data*    out,
 
2332
                                       FT_UShort         flags,
 
2333
                                       FT_UShort         context_length )
 
2334
  {
 
2335
    FT_UShort        i, j, mark_index, base_index, property, klass;
 
2336
    FT_Pos           x_mark_value, y_mark_value, x_base_value, y_base_value;
 
2337
    FT_Error         error;
 
2338
    TTO_GPOSHeader*  gpos = gpi->gpos;
 
2339
 
 
2340
    TTO_MarkArray*   ma;
 
2341
    TTO_BaseArray*   ba;
 
2342
    TTO_BaseRecord*  br;
 
2343
    TTO_Anchor*      mark_anchor;
 
2344
    TTO_Anchor*      base_anchor;
 
2345
 
 
2346
    TTO_GPOS_Data*   o;
 
2347
 
 
2348
 
 
2349
    if ( context_length != 0xFFFF && context_length < 1 )
 
2350
      return TTO_Err_Not_Covered;
 
2351
 
 
2352
    if ( flags & IGNORE_BASE_GLYPHS )
 
2353
      return TTO_Err_Not_Covered;
 
2354
 
 
2355
    error = Coverage_Index( &mbp->MarkCoverage, in->string[in->pos],
 
2356
                            &mark_index );
 
2357
    if ( error )
 
2358
      return error;
 
2359
 
 
2360
    if ( CHECK_Property( gpos->gdef, in->string[in->pos],
 
2361
                         flags, &property ) )
 
2362
      return error;
 
2363
 
 
2364
    /* now we search backwards for a non-mark glyph */
 
2365
 
 
2366
    i = 1;
 
2367
    j = in->pos - 1;
 
2368
 
 
2369
    while ( i <= in->pos )
 
2370
    {
 
2371
      error = TT_GDEF_Get_Glyph_Property( gpos->gdef, in->string[j],
 
2372
                                          &property );
 
2373
      if ( error )
 
2374
        return error;
 
2375
 
 
2376
      if ( !( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS ) )
 
2377
        break;
 
2378
 
 
2379
      i++;
 
2380
      j--;
 
2381
    }
 
2382
 
 
2383
    /* The following assertion is too strong -- at least for mangal.ttf. */
 
2384
#if 0
 
2385
    if ( property != TTO_BASE_GLYPH )
 
2386
      return TTO_Err_Not_Covered;
 
2387
#endif
 
2388
 
 
2389
    if ( i > in->pos )
 
2390
      return TTO_Err_Not_Covered;
 
2391
 
 
2392
    error = Coverage_Index( &mbp->BaseCoverage, in->string[j],
 
2393
                            &base_index );
 
2394
    if ( error )
 
2395
      return error;
 
2396
 
 
2397
    ma = &mbp->MarkArray;
 
2398
 
 
2399
    if ( mark_index >= ma->MarkCount )
 
2400
      return TTO_Err_Invalid_GPOS_SubTable;
 
2401
 
 
2402
    klass       = ma->MarkRecord[mark_index].Class;
 
2403
    mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
 
2404
 
 
2405
    if ( klass >= mbp->ClassCount )
 
2406
      return TTO_Err_Invalid_GPOS_SubTable;
 
2407
 
 
2408
    ba = &mbp->BaseArray;
 
2409
 
 
2410
    if ( base_index >= ba->BaseCount )
 
2411
      return TTO_Err_Invalid_GPOS_SubTable;
 
2412
 
 
2413
    br          = &ba->BaseRecord[base_index];
 
2414
    base_anchor = &br->BaseAnchor[klass];
 
2415
 
 
2416
    error = Get_Anchor( gpi, mark_anchor, in->string[in->pos],
 
2417
                        &x_mark_value, &y_mark_value );
 
2418
    if ( error )
 
2419
      return error;
 
2420
    error = Get_Anchor( gpi, base_anchor, in->string[j],
 
2421
                        &x_base_value, &y_base_value );
 
2422
    if ( error )
 
2423
      return error;
 
2424
 
 
2425
    /* anchor points are not cumulative */
 
2426
 
 
2427
    o = &out[in->pos];
 
2428
 
 
2429
    o->x_pos     = x_base_value - x_mark_value;
 
2430
    o->y_pos     = y_base_value - y_mark_value;
 
2431
    o->x_advance = 0;
 
2432
    o->y_advance = 0;
 
2433
    o->back      = i;
 
2434
 
 
2435
    (in->pos)++;
 
2436
 
 
2437
    return TT_Err_Ok;
 
2438
  }
 
2439
 
 
2440
 
 
2441
  /* LookupType 5 */
 
2442
 
 
2443
  /* LigatureAttach */
 
2444
 
 
2445
  static FT_Error  Load_LigatureAttach( TTO_LigatureAttach*  lat,
 
2446
                                        FT_UShort            num_classes,
 
2447
                                        FT_Stream            stream )
 
2448
  {
 
2449
    FT_Error  error;
 
2450
    FT_Memory memory = stream->memory;
 
2451
 
 
2452
    FT_UShort             m, n, k, count;
 
2453
    FT_ULong              cur_offset, new_offset, base_offset;
 
2454
 
 
2455
    TTO_ComponentRecord*  cr;
 
2456
    TTO_Anchor*           lan;
 
2457
 
 
2458
 
 
2459
    base_offset = FILE_Pos();
 
2460
 
 
2461
    if ( ACCESS_Frame( 2L ) )
 
2462
      return error;
 
2463
 
 
2464
    count = lat->ComponentCount = GET_UShort();
 
2465
 
 
2466
    FORGET_Frame();
 
2467
 
 
2468
    lat->ComponentRecord = NULL;
 
2469
 
 
2470
    if ( ALLOC_ARRAY( lat->ComponentRecord, count, TTO_ComponentRecord ) )
 
2471
      return error;
 
2472
 
 
2473
    cr = lat->ComponentRecord;
 
2474
 
 
2475
    for ( m = 0; m < count; m++ )
 
2476
    {
 
2477
      cr[m].LigatureAnchor = NULL;
 
2478
 
 
2479
      if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, TTO_Anchor ) )
 
2480
        goto Fail;
 
2481
 
 
2482
      lan = cr[m].LigatureAnchor;
 
2483
 
 
2484
      for ( n = 0; n < num_classes; n++ )
 
2485
      {
 
2486
        if ( ACCESS_Frame( 2L ) )
 
2487
          goto Fail0;
 
2488
 
 
2489
        new_offset = GET_UShort();
 
2490
 
 
2491
        FORGET_Frame();
 
2492
 
 
2493
        if ( new_offset )
 
2494
        {
 
2495
          new_offset += base_offset;
 
2496
 
 
2497
          cur_offset = FILE_Pos();
 
2498
          if ( FILE_Seek( new_offset ) ||
 
2499
               ( error = Load_Anchor( &lan[n], stream ) ) != TT_Err_Ok )
 
2500
            goto Fail0;
 
2501
          (void)FILE_Seek( cur_offset );
 
2502
        }
 
2503
        else
 
2504
          lan[n].PosFormat = 0;
 
2505
      }
 
2506
 
 
2507
      continue;
 
2508
    Fail0:
 
2509
      for ( k = 0; k < n; k++ )
 
2510
        Free_Anchor( &lan[k], memory );
 
2511
      goto Fail;
 
2512
    }
 
2513
 
 
2514
    return TT_Err_Ok;
 
2515
 
 
2516
  Fail:
 
2517
    for ( k = 0; k < m; k++ )
 
2518
    {
 
2519
      lan = cr[k].LigatureAnchor;
 
2520
 
 
2521
      for ( n = 0; n < num_classes; n++ )
 
2522
        Free_Anchor( &lan[n], memory );
 
2523
 
 
2524
      FREE( lan );
 
2525
    }
 
2526
 
 
2527
    FREE( cr );
 
2528
    return error;
 
2529
  }
 
2530
 
 
2531
 
 
2532
  static void  Free_LigatureAttach( TTO_LigatureAttach*  lat,
 
2533
                                    FT_UShort            num_classes,
 
2534
                                    FT_Memory            memory )
 
2535
  {
 
2536
    FT_UShort        m, n, count;
 
2537
 
 
2538
    TTO_ComponentRecord*  cr;
 
2539
    TTO_Anchor*           lan;
 
2540
 
 
2541
 
 
2542
    if ( lat->ComponentRecord )
 
2543
    {
 
2544
      count = lat->ComponentCount;
 
2545
      cr    = lat->ComponentRecord;
 
2546
 
 
2547
      for ( m = 0; m < count; m++ )
 
2548
      {
 
2549
        lan = cr[m].LigatureAnchor;
 
2550
 
 
2551
        for ( n = 0; n < num_classes; n++ )
 
2552
          Free_Anchor( &lan[n], memory );
 
2553
 
 
2554
        FREE( lan );
 
2555
      }
 
2556
 
 
2557
      FREE( cr );
 
2558
    }
 
2559
  }
 
2560
 
 
2561
 
 
2562
  /* LigatureArray */
 
2563
 
 
2564
  static FT_Error  Load_LigatureArray( TTO_LigatureArray*  la,
 
2565
                                       FT_UShort           num_classes,
 
2566
                                       FT_Stream           stream )
 
2567
  {
 
2568
    FT_Error  error;
 
2569
    FT_Memory memory = stream->memory;
 
2570
 
 
2571
    FT_UShort            n, m, count;
 
2572
    FT_ULong             cur_offset, new_offset, base_offset;
 
2573
 
 
2574
    TTO_LigatureAttach*  lat;
 
2575
 
 
2576
 
 
2577
    base_offset = FILE_Pos();
 
2578
 
 
2579
    if ( ACCESS_Frame( 2L ) )
 
2580
      return error;
 
2581
 
 
2582
    count = la->LigatureCount = GET_UShort();
 
2583
 
 
2584
    FORGET_Frame();
 
2585
 
 
2586
    la->LigatureAttach = NULL;
 
2587
 
 
2588
    if ( ALLOC_ARRAY( la->LigatureAttach, count, TTO_LigatureAttach ) )
 
2589
      return error;
 
2590
 
 
2591
    lat = la->LigatureAttach;
 
2592
 
 
2593
    for ( n = 0; n < count; n++ )
 
2594
    {
 
2595
      if ( ACCESS_Frame( 2L ) )
 
2596
        goto Fail;
 
2597
 
 
2598
      new_offset = GET_UShort() + base_offset;
 
2599
 
 
2600
      FORGET_Frame();
 
2601
 
 
2602
      cur_offset = FILE_Pos();
 
2603
      if ( FILE_Seek( new_offset ) ||
 
2604
           ( error = Load_LigatureAttach( &lat[n], num_classes,
 
2605
                                          stream ) ) != TT_Err_Ok )
 
2606
        goto Fail;
 
2607
      (void)FILE_Seek( cur_offset );
 
2608
    }
 
2609
 
 
2610
    return TT_Err_Ok;
 
2611
 
 
2612
  Fail:
 
2613
    for ( m = 0; m < n; m++ )
 
2614
      Free_LigatureAttach( &lat[m], num_classes, memory );
 
2615
 
 
2616
    FREE( lat );
 
2617
    return error;
 
2618
  }
 
2619
 
 
2620
 
 
2621
  static void  Free_LigatureArray( TTO_LigatureArray*  la,
 
2622
                                   FT_UShort           num_classes,
 
2623
                                   FT_Memory           memory )
 
2624
  {
 
2625
    FT_UShort            n, count;
 
2626
 
 
2627
    TTO_LigatureAttach*  lat;
 
2628
 
 
2629
 
 
2630
    if ( la->LigatureAttach )
 
2631
    {
 
2632
      count = la->LigatureCount;
 
2633
      lat   = la->LigatureAttach;
 
2634
 
 
2635
      for ( n = 0; n < count; n++ )
 
2636
        Free_LigatureAttach( &lat[n], num_classes, memory );
 
2637
 
 
2638
      FREE( lat );
 
2639
    }
 
2640
  }
 
2641
 
 
2642
 
 
2643
  /* MarkLigPosFormat1 */
 
2644
 
 
2645
  FT_Error  Load_MarkLigPos( TTO_MarkLigPos*  mlp,
 
2646
                             FT_Stream        stream )
 
2647
  {
 
2648
    FT_Error  error;
 
2649
    FT_Memory memory = stream->memory;
 
2650
 
 
2651
    FT_ULong  cur_offset, new_offset, base_offset;
 
2652
 
 
2653
 
 
2654
    base_offset = FILE_Pos();
 
2655
 
 
2656
    if ( ACCESS_Frame( 4L ) )
 
2657
      return error;
 
2658
 
 
2659
    mlp->PosFormat = GET_UShort();
 
2660
    new_offset     = GET_UShort() + base_offset;
 
2661
 
 
2662
    FORGET_Frame();
 
2663
 
 
2664
    cur_offset = FILE_Pos();
 
2665
    if ( FILE_Seek( new_offset ) ||
 
2666
         ( error = Load_Coverage( &mlp->MarkCoverage, stream ) ) != TT_Err_Ok )
 
2667
      return error;
 
2668
    (void)FILE_Seek( cur_offset );
 
2669
 
 
2670
    if ( ACCESS_Frame( 2L ) )
 
2671
      goto Fail3;
 
2672
 
 
2673
    new_offset = GET_UShort() + base_offset;
 
2674
 
 
2675
    FORGET_Frame();
 
2676
 
 
2677
    cur_offset = FILE_Pos();
 
2678
    if ( FILE_Seek( new_offset ) ||
 
2679
         ( error = Load_Coverage( &mlp->LigatureCoverage,
 
2680
                                  stream ) ) != TT_Err_Ok )
 
2681
      goto Fail3;
 
2682
    (void)FILE_Seek( cur_offset );
 
2683
 
 
2684
    if ( ACCESS_Frame( 4L ) )
 
2685
      goto Fail2;
 
2686
 
 
2687
    mlp->ClassCount = GET_UShort();
 
2688
    new_offset      = GET_UShort() + base_offset;
 
2689
 
 
2690
    FORGET_Frame();
 
2691
 
 
2692
    cur_offset = FILE_Pos();
 
2693
    if ( FILE_Seek( new_offset ) ||
 
2694
         ( error = Load_MarkArray( &mlp->MarkArray, stream ) ) != TT_Err_Ok )
 
2695
      goto Fail2;
 
2696
    (void)FILE_Seek( cur_offset );
 
2697
 
 
2698
    if ( ACCESS_Frame( 2L ) )
 
2699
      goto Fail1;
 
2700
 
 
2701
    new_offset = GET_UShort() + base_offset;
 
2702
 
 
2703
    FORGET_Frame();
 
2704
 
 
2705
    cur_offset = FILE_Pos();
 
2706
    if ( FILE_Seek( new_offset ) ||
 
2707
         ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount,
 
2708
                                       stream ) ) != TT_Err_Ok )
 
2709
      goto Fail1;
 
2710
 
 
2711
    return TT_Err_Ok;
 
2712
 
 
2713
  Fail1:
 
2714
    Free_MarkArray( &mlp->MarkArray, memory );
 
2715
 
 
2716
  Fail2:
 
2717
    Free_Coverage( &mlp->LigatureCoverage, memory );
 
2718
 
 
2719
  Fail3:
 
2720
    Free_Coverage( &mlp->MarkCoverage, memory );
 
2721
    return error;
 
2722
  }
 
2723
 
 
2724
 
 
2725
  void  Free_MarkLigPos( TTO_MarkLigPos*  mlp,
 
2726
                         FT_Memory        memory)
 
2727
  {
 
2728
    Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount, memory );
 
2729
    Free_MarkArray( &mlp->MarkArray, memory );
 
2730
    Free_Coverage( &mlp->LigatureCoverage, memory );
 
2731
    Free_Coverage( &mlp->MarkCoverage, memory );
 
2732
  }
 
2733
 
 
2734
 
 
2735
  static FT_Error  Lookup_MarkLigPos( GPOS_Instance*    gpi,
 
2736
                                      TTO_MarkLigPos*   mlp,
 
2737
                                      TTO_GSUB_String*  in,
 
2738
                                      TTO_GPOS_Data*    out,
 
2739
                                      FT_UShort         flags,
 
2740
                                      FT_UShort         context_length )
 
2741
  {
 
2742
    FT_UShort        i, j, mark_index, lig_index, property, klass;
 
2743
    FT_UShort        mark_glyph;
 
2744
    FT_Pos           x_mark_value, y_mark_value, x_lig_value, y_lig_value;
 
2745
    FT_Error         error;
 
2746
    TTO_GPOSHeader*  gpos = gpi->gpos;
 
2747
 
 
2748
    TTO_MarkArray*        ma;
 
2749
    TTO_LigatureArray*    la;
 
2750
    TTO_LigatureAttach*   lat;
 
2751
    TTO_ComponentRecord*  cr;
 
2752
    FT_UShort             comp_index;
 
2753
    TTO_Anchor*           mark_anchor;
 
2754
    TTO_Anchor*           lig_anchor;
 
2755
 
 
2756
    TTO_GPOS_Data*  o;
 
2757
 
 
2758
 
 
2759
    if ( context_length != 0xFFFF && context_length < 1 )
 
2760
      return TTO_Err_Not_Covered;
 
2761
 
 
2762
    if ( flags & IGNORE_LIGATURES )
 
2763
      return TTO_Err_Not_Covered;
 
2764
 
 
2765
    mark_glyph = in->string[in->pos];
 
2766
 
 
2767
    error = Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index );
 
2768
    if ( error )
 
2769
      return error;
 
2770
 
 
2771
    if ( CHECK_Property( gpos->gdef, mark_glyph, flags, &property ) )
 
2772
      return error;
 
2773
 
 
2774
    /* now we search backwards for a non-mark glyph */
 
2775
 
 
2776
    i = 1;
 
2777
    j = in->pos - 1;
 
2778
 
 
2779
    while ( i <= in->pos )
 
2780
    {
 
2781
      error = TT_GDEF_Get_Glyph_Property( gpos->gdef, in->string[j],
 
2782
                                          &property );
 
2783
      if ( error )
 
2784
        return error;
 
2785
 
 
2786
      if ( !( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS ) )
 
2787
        break;
 
2788
 
 
2789
      i++;
 
2790
      j--;
 
2791
    }
 
2792
 
 
2793
    /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is
 
2794
       too strong, thus it is commented out.                             */
 
2795
#if 0
 
2796
    if ( property != TTO_LIGATURE )
 
2797
      return TTO_Err_Not_Covered;
 
2798
#endif
 
2799
 
 
2800
    if ( i > in->pos )
 
2801
      return TTO_Err_Not_Covered;
 
2802
 
 
2803
    error = Coverage_Index( &mlp->LigatureCoverage, in->string[j],
 
2804
                            &lig_index );
 
2805
    if ( error )
 
2806
      return error;
 
2807
 
 
2808
    ma = &mlp->MarkArray;
 
2809
 
 
2810
    if ( mark_index >= ma->MarkCount )
 
2811
      return TTO_Err_Invalid_GPOS_SubTable;
 
2812
 
 
2813
    klass       = ma->MarkRecord[mark_index].Class;
 
2814
    mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
 
2815
 
 
2816
    if ( klass >= mlp->ClassCount )
 
2817
      return TTO_Err_Invalid_GPOS_SubTable;
 
2818
 
 
2819
    la = &mlp->LigatureArray;
 
2820
 
 
2821
    if ( lig_index >= la->LigatureCount )
 
2822
      return TTO_Err_Invalid_GPOS_SubTable;
 
2823
 
 
2824
    lat = &la->LigatureAttach[lig_index];
 
2825
 
 
2826
    /* Use the component id if defined. If not we simply attach the
 
2827
       mark glyph to the last component of the ligature */
 
2828
 
 
2829
    comp_index = in->glyph_properties[in->pos].component;
 
2830
 
 
2831
    /* ###### why the hell doesn't this compile?
 
2832
     if (comp_index == MAX_COMPONENT_INDEX)
 
2833
        comp_index = lat->ComponentCount - 1; */
 
2834
    if ( comp_index >= lat->ComponentCount )
 
2835
        return TTO_Err_Not_Covered;
 
2836
 
 
2837
    cr         = &lat->ComponentRecord[comp_index];
 
2838
    lig_anchor = &cr->LigatureAnchor[klass];
 
2839
 
 
2840
    error = Get_Anchor( gpi, mark_anchor, in->string[in->pos],
 
2841
                        &x_mark_value, &y_mark_value );
 
2842
    if ( error )
 
2843
      return error;
 
2844
    error = Get_Anchor( gpi, lig_anchor, in->string[j],
 
2845
                        &x_lig_value, &y_lig_value );
 
2846
    if ( error )
 
2847
      return error;
 
2848
 
 
2849
    /* anchor points are not cumulative */
 
2850
 
 
2851
    o = &out[in->pos];
 
2852
 
 
2853
    o->x_pos     = x_lig_value - x_mark_value;
 
2854
    o->y_pos     = y_lig_value - y_mark_value;
 
2855
    o->x_advance = 0;
 
2856
    o->y_advance = 0;
 
2857
    o->back      = i;
 
2858
 
 
2859
    (in->pos)++;
 
2860
 
 
2861
    return TT_Err_Ok;
 
2862
  }
 
2863
 
 
2864
 
 
2865
  /* LookupType 6 */
 
2866
 
 
2867
  /* Mark2Array */
 
2868
 
 
2869
  static FT_Error  Load_Mark2Array( TTO_Mark2Array*  m2a,
 
2870
                                    FT_UShort        num_classes,
 
2871
                                    FT_Stream        stream )
 
2872
  {
 
2873
    FT_Error  error;
 
2874
    FT_Memory memory = stream->memory;
 
2875
 
 
2876
    FT_UShort         k, m, n, count;
 
2877
    FT_ULong          cur_offset, new_offset, base_offset;
 
2878
 
 
2879
    TTO_Mark2Record*  m2r;
 
2880
    TTO_Anchor*       m2an;
 
2881
 
 
2882
 
 
2883
    base_offset = FILE_Pos();
 
2884
 
 
2885
    if ( ACCESS_Frame( 2L ) )
 
2886
      return error;
 
2887
 
 
2888
    count = m2a->Mark2Count = GET_UShort();
 
2889
 
 
2890
    FORGET_Frame();
 
2891
 
 
2892
    m2a->Mark2Record = NULL;
 
2893
 
 
2894
    if ( ALLOC_ARRAY( m2a->Mark2Record, count, TTO_Mark2Record ) )
 
2895
      return error;
 
2896
 
 
2897
    m2r = m2a->Mark2Record;
 
2898
 
 
2899
    for ( m = 0; m < count; m++ )
 
2900
    {
 
2901
      m2r[m].Mark2Anchor = NULL;
 
2902
 
 
2903
      if ( ALLOC_ARRAY( m2r[m].Mark2Anchor, num_classes, TTO_Anchor ) )
 
2904
        goto Fail;
 
2905
 
 
2906
      m2an = m2r[m].Mark2Anchor;
 
2907
 
 
2908
      for ( n = 0; n < num_classes; n++ )
 
2909
      {
 
2910
        if ( ACCESS_Frame( 2L ) )
 
2911
          goto Fail0;
 
2912
 
 
2913
        new_offset = GET_UShort() + base_offset;
 
2914
 
 
2915
        FORGET_Frame();
 
2916
 
 
2917
        cur_offset = FILE_Pos();
 
2918
        if ( FILE_Seek( new_offset ) ||
 
2919
             ( error = Load_Anchor( &m2an[n], stream ) ) != TT_Err_Ok )
 
2920
          goto Fail0;
 
2921
        (void)FILE_Seek( cur_offset );
 
2922
      }
 
2923
 
 
2924
      continue;
 
2925
    Fail0:
 
2926
      for ( k = 0; k < n; k++ )
 
2927
        Free_Anchor( &m2an[k], memory );
 
2928
      goto Fail;
 
2929
    }
 
2930
 
 
2931
    return TT_Err_Ok;
 
2932
 
 
2933
  Fail:
 
2934
    for ( k = 0; k < m; k++ )
 
2935
    {
 
2936
      m2an = m2r[k].Mark2Anchor;
 
2937
 
 
2938
      for ( n = 0; n < num_classes; n++ )
 
2939
        Free_Anchor( &m2an[n], memory );
 
2940
 
 
2941
      FREE( m2an );
 
2942
    }
 
2943
 
 
2944
    FREE( m2r );
 
2945
    return error;
 
2946
  }
 
2947
 
 
2948
 
 
2949
  static void  Free_Mark2Array( TTO_Mark2Array*  m2a,
 
2950
                                FT_UShort        num_classes,
 
2951
                                FT_Memory        memory )
 
2952
  {
 
2953
    FT_UShort         m, n, count;
 
2954
 
 
2955
    TTO_Mark2Record*  m2r;
 
2956
    TTO_Anchor*       m2an;
 
2957
 
 
2958
 
 
2959
    if ( m2a->Mark2Record )
 
2960
    {
 
2961
      count = m2a->Mark2Count;
 
2962
      m2r   = m2a->Mark2Record;
 
2963
 
 
2964
      for ( m = 0; m < count; m++ )
 
2965
      {
 
2966
        m2an = m2r[m].Mark2Anchor;
 
2967
 
 
2968
        for ( n = 0; n < num_classes; n++ )
 
2969
          Free_Anchor( &m2an[n], memory );
 
2970
 
 
2971
        FREE( m2an );
 
2972
      }
 
2973
 
 
2974
      FREE( m2r );
 
2975
    }
 
2976
  }
 
2977
 
 
2978
 
 
2979
  /* MarkMarkPosFormat1 */
 
2980
 
 
2981
  FT_Error  Load_MarkMarkPos( TTO_MarkMarkPos*  mmp,
 
2982
                              FT_Stream         stream )
 
2983
  {
 
2984
    FT_Error  error;
 
2985
    FT_Memory memory = stream->memory;
 
2986
 
 
2987
    FT_ULong  cur_offset, new_offset, base_offset;
 
2988
 
 
2989
 
 
2990
    base_offset = FILE_Pos();
 
2991
 
 
2992
    if ( ACCESS_Frame( 4L ) )
 
2993
      return error;
 
2994
 
 
2995
    mmp->PosFormat = GET_UShort();
 
2996
    new_offset     = GET_UShort() + base_offset;
 
2997
 
 
2998
    FORGET_Frame();
 
2999
 
 
3000
    cur_offset = FILE_Pos();
 
3001
    if ( FILE_Seek( new_offset ) ||
 
3002
         ( error = Load_Coverage( &mmp->Mark1Coverage,
 
3003
                                  stream ) ) != TT_Err_Ok )
 
3004
      return error;
 
3005
    (void)FILE_Seek( cur_offset );
 
3006
 
 
3007
    if ( ACCESS_Frame( 2L ) )
 
3008
      goto Fail3;
 
3009
 
 
3010
    new_offset = GET_UShort() + base_offset;
 
3011
 
 
3012
    FORGET_Frame();
 
3013
 
 
3014
    cur_offset = FILE_Pos();
 
3015
    if ( FILE_Seek( new_offset ) ||
 
3016
         ( error = Load_Coverage( &mmp->Mark2Coverage,
 
3017
                                  stream ) ) != TT_Err_Ok )
 
3018
      goto Fail3;
 
3019
    (void)FILE_Seek( cur_offset );
 
3020
 
 
3021
    if ( ACCESS_Frame( 4L ) )
 
3022
      goto Fail2;
 
3023
 
 
3024
    mmp->ClassCount = GET_UShort();
 
3025
    new_offset      = GET_UShort() + base_offset;
 
3026
 
 
3027
    FORGET_Frame();
 
3028
 
 
3029
    cur_offset = FILE_Pos();
 
3030
    if ( FILE_Seek( new_offset ) ||
 
3031
         ( error = Load_MarkArray( &mmp->Mark1Array, stream ) ) != TT_Err_Ok )
 
3032
      goto Fail2;
 
3033
    (void)FILE_Seek( cur_offset );
 
3034
 
 
3035
    if ( ACCESS_Frame( 2L ) )
 
3036
      goto Fail1;
 
3037
 
 
3038
    new_offset = GET_UShort() + base_offset;
 
3039
 
 
3040
    FORGET_Frame();
 
3041
 
 
3042
    cur_offset = FILE_Pos();
 
3043
    if ( FILE_Seek( new_offset ) ||
 
3044
         ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount,
 
3045
                                    stream ) ) != TT_Err_Ok )
 
3046
      goto Fail1;
 
3047
 
 
3048
    return TT_Err_Ok;
 
3049
 
 
3050
  Fail1:
 
3051
    Free_MarkArray( &mmp->Mark1Array, memory );
 
3052
 
 
3053
  Fail2:
 
3054
    Free_Coverage( &mmp->Mark2Coverage, memory );
 
3055
 
 
3056
  Fail3:
 
3057
    Free_Coverage( &mmp->Mark1Coverage, memory );
 
3058
    return error;
 
3059
  }
 
3060
 
 
3061
 
 
3062
  void  Free_MarkMarkPos( TTO_MarkMarkPos*  mmp,
 
3063
                          FT_Memory         memory)
 
3064
  {
 
3065
    Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount, memory );
 
3066
    Free_MarkArray( &mmp->Mark1Array, memory );
 
3067
    Free_Coverage( &mmp->Mark2Coverage, memory );
 
3068
    Free_Coverage( &mmp->Mark1Coverage, memory );
 
3069
  }
 
3070
 
 
3071
 
 
3072
  static FT_Error  Lookup_MarkMarkPos( GPOS_Instance*    gpi,
 
3073
                                       TTO_MarkMarkPos*  mmp,
 
3074
                                       TTO_GSUB_String*  in,
 
3075
                                       TTO_GPOS_Data*    out,
 
3076
                                       FT_UShort         flags,
 
3077
                                       FT_UShort         context_length )
 
3078
  {
 
3079
    FT_UShort        j, mark1_index, mark2_index, property, klass;
 
3080
    FT_Pos           x_mark1_value, y_mark1_value,
 
3081
                     x_mark2_value, y_mark2_value;
 
3082
    FT_Error         error;
 
3083
    TTO_GPOSHeader*  gpos = gpi->gpos;
 
3084
 
 
3085
    TTO_MarkArray*    ma1;
 
3086
    TTO_Mark2Array*   ma2;
 
3087
    TTO_Mark2Record*  m2r;
 
3088
    TTO_Anchor*       mark1_anchor;
 
3089
    TTO_Anchor*       mark2_anchor;
 
3090
 
 
3091
    TTO_GPOS_Data*  o;
 
3092
 
 
3093
 
 
3094
    if ( context_length != 0xFFFF && context_length < 1 )
 
3095
      return TTO_Err_Not_Covered;
 
3096
 
 
3097
    if ( flags & IGNORE_MARKS )
 
3098
      return TTO_Err_Not_Covered;
 
3099
 
 
3100
    error = Coverage_Index( &mmp->Mark1Coverage, in->string[in->pos],
 
3101
                            &mark1_index );
 
3102
    if ( error )
 
3103
      return error;
 
3104
 
 
3105
    if ( CHECK_Property( gpos->gdef, in->string[in->pos],
 
3106
                         flags, &property ) )
 
3107
      return error;
 
3108
 
 
3109
 
 
3110
    /* now we check the preceding glyph whether it is a suitable
 
3111
       mark glyph                                                */
 
3112
 
 
3113
    if ( in->pos == 0 )
 
3114
      return TTO_Err_Not_Covered;
 
3115
 
 
3116
    j = in->pos - 1;
 
3117
    error = TT_GDEF_Get_Glyph_Property( gpos->gdef, in->string[j],
 
3118
                                        &property );
 
3119
    if ( error )
 
3120
      return error;
 
3121
 
 
3122
    if ( flags & IGNORE_SPECIAL_MARKS )
 
3123
    {
 
3124
      if ( property != (flags & 0xFF00) )
 
3125
        return TTO_Err_Not_Covered;
 
3126
    }
 
3127
    else
 
3128
    {
 
3129
      if ( property != TTO_MARK )
 
3130
        return TTO_Err_Not_Covered;
 
3131
    }
 
3132
 
 
3133
    error = Coverage_Index( &mmp->Mark2Coverage, in->string[j],
 
3134
                            &mark2_index );
 
3135
    if ( error )
 
3136
      return error;
 
3137
 
 
3138
    ma1 = &mmp->Mark1Array;
 
3139
 
 
3140
    if ( mark1_index >= ma1->MarkCount )
 
3141
      return TTO_Err_Invalid_GPOS_SubTable;
 
3142
 
 
3143
    klass        = ma1->MarkRecord[mark1_index].Class;
 
3144
    mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor;
 
3145
 
 
3146
    if ( klass >= mmp->ClassCount )
 
3147
      return TTO_Err_Invalid_GPOS_SubTable;
 
3148
 
 
3149
    ma2 = &mmp->Mark2Array;
 
3150
 
 
3151
    if ( mark2_index >= ma2->Mark2Count )
 
3152
      return TTO_Err_Invalid_GPOS_SubTable;
 
3153
 
 
3154
    m2r          = &ma2->Mark2Record[mark2_index];
 
3155
    mark2_anchor = &m2r->Mark2Anchor[klass];
 
3156
 
 
3157
    error = Get_Anchor( gpi, mark1_anchor, in->string[in->pos],
 
3158
                        &x_mark1_value, &y_mark1_value );
 
3159
    if ( error )
 
3160
      return error;
 
3161
    error = Get_Anchor( gpi, mark2_anchor, in->string[j],
 
3162
                        &x_mark2_value, &y_mark2_value );
 
3163
    if ( error )
 
3164
      return error;
 
3165
 
 
3166
    /* anchor points are not cumulative */
 
3167
 
 
3168
    o = &out[in->pos];
 
3169
 
 
3170
    o->x_pos     = x_mark2_value - x_mark1_value;
 
3171
    o->y_pos     = y_mark2_value - y_mark1_value;
 
3172
    o->x_advance = 0;
 
3173
    o->y_advance = 0;
 
3174
    o->back      = 1;
 
3175
 
 
3176
    (in->pos)++;
 
3177
 
 
3178
    return TT_Err_Ok;
 
3179
  }
 
3180
 
 
3181
 
 
3182
  /* Do the actual positioning for a context positioning (either format
 
3183
     7 or 8).  This is only called after we've determined that the stream
 
3184
     matches the subrule.                                                 */
 
3185
 
 
3186
  static FT_Error  Do_ContextPos( GPOS_Instance*        gpi,
 
3187
                                  FT_UShort             GlyphCount,
 
3188
                                  FT_UShort             PosCount,
 
3189
                                  TTO_PosLookupRecord*  pos,
 
3190
                                  TTO_GSUB_String*      in,
 
3191
                                  TTO_GPOS_Data*        out,
 
3192
                                  int                   nesting_level )
 
3193
  {
 
3194
    FT_Error  error;
 
3195
    FT_UShort i, old_pos;
 
3196
 
 
3197
 
 
3198
    i = 0;
 
3199
 
 
3200
    while ( i < GlyphCount )
 
3201
    {
 
3202
      if ( PosCount && i == pos->SequenceIndex )
 
3203
      {
 
3204
        old_pos = in->pos;
 
3205
 
 
3206
        /* Do a positioning */
 
3207
 
 
3208
        error = GPos_Do_Glyph_Lookup( gpi, pos->LookupListIndex, in, out,
 
3209
                                 GlyphCount, nesting_level );
 
3210
 
 
3211
        if ( error )
 
3212
          return error;
 
3213
 
 
3214
        pos++;
 
3215
        PosCount--;
 
3216
        i += in->pos - old_pos;
 
3217
      }
 
3218
      else
 
3219
      {
 
3220
        i++;
 
3221
        (in->pos)++;
 
3222
      }
 
3223
    }
 
3224
 
 
3225
    return TT_Err_Ok;
 
3226
  }
 
3227
 
 
3228
 
 
3229
  /* LookupType 7 */
 
3230
 
 
3231
  /* PosRule */
 
3232
 
 
3233
  static FT_Error  Load_PosRule( TTO_PosRule*  pr,
 
3234
                                 FT_Stream     stream )
 
3235
  {
 
3236
    FT_Error  error;
 
3237
    FT_Memory memory = stream->memory;
 
3238
 
 
3239
    FT_UShort             n, count;
 
3240
    FT_UShort*            i;
 
3241
 
 
3242
    TTO_PosLookupRecord*  plr;
 
3243
 
 
3244
 
 
3245
    if ( ACCESS_Frame( 4L ) )
 
3246
      return error;
 
3247
 
 
3248
    pr->GlyphCount = GET_UShort();
 
3249
    pr->PosCount   = GET_UShort();
 
3250
 
 
3251
    FORGET_Frame();
 
3252
 
 
3253
    pr->Input = NULL;
 
3254
 
 
3255
    count = pr->GlyphCount - 1;         /* only GlyphCount - 1 elements */
 
3256
 
 
3257
    if ( ALLOC_ARRAY( pr->Input, count, FT_UShort ) )
 
3258
      return error;
 
3259
 
 
3260
    i = pr->Input;
 
3261
 
 
3262
    if ( ACCESS_Frame( count * 2L ) )
 
3263
      goto Fail2;
 
3264
 
 
3265
    for ( n = 0; n < count; n++ )
 
3266
      i[n] = GET_UShort();
 
3267
 
 
3268
    FORGET_Frame();
 
3269
 
 
3270
    pr->PosLookupRecord = NULL;
 
3271
 
 
3272
    count = pr->PosCount;
 
3273
 
 
3274
    if ( ALLOC_ARRAY( pr->PosLookupRecord, count, TTO_PosLookupRecord ) )
 
3275
      goto Fail2;
 
3276
 
 
3277
    plr = pr->PosLookupRecord;
 
3278
 
 
3279
    if ( ACCESS_Frame( count * 4L ) )
 
3280
      goto Fail1;
 
3281
 
 
3282
    for ( n = 0; n < count; n++ )
 
3283
    {
 
3284
      plr[n].SequenceIndex   = GET_UShort();
 
3285
      plr[n].LookupListIndex = GET_UShort();
 
3286
    }
 
3287
 
 
3288
    FORGET_Frame();
 
3289
 
 
3290
    return TT_Err_Ok;
 
3291
 
 
3292
  Fail1:
 
3293
    FREE( plr );
 
3294
 
 
3295
  Fail2:
 
3296
    FREE( i );
 
3297
    return error;
 
3298
  }
 
3299
 
 
3300
 
 
3301
  static void  Free_PosRule( TTO_PosRule*  pr,
 
3302
                             FT_Memory     memory )
 
3303
  {
 
3304
    FREE( pr->PosLookupRecord );
 
3305
    FREE( pr->Input );
 
3306
  }
 
3307
 
 
3308
 
 
3309
  /* PosRuleSet */
 
3310
 
 
3311
  static FT_Error  Load_PosRuleSet( TTO_PosRuleSet*  prs,
 
3312
                                    FT_Stream        stream )
 
3313
  {
 
3314
    FT_Error  error;
 
3315
    FT_Memory memory = stream->memory;
 
3316
 
 
3317
    FT_UShort     n, m, count;
 
3318
    FT_ULong      cur_offset, new_offset, base_offset;
 
3319
 
 
3320
    TTO_PosRule*  pr;
 
3321
 
 
3322
 
 
3323
    base_offset = FILE_Pos();
 
3324
 
 
3325
    if ( ACCESS_Frame( 2L ) )
 
3326
      return error;
 
3327
 
 
3328
    count = prs->PosRuleCount = GET_UShort();
 
3329
 
 
3330
    FORGET_Frame();
 
3331
 
 
3332
    prs->PosRule = NULL;
 
3333
 
 
3334
    if ( ALLOC_ARRAY( prs->PosRule, count, TTO_PosRule ) )
 
3335
      return error;
 
3336
 
 
3337
    pr = prs->PosRule;
 
3338
 
 
3339
    for ( n = 0; n < count; n++ )
 
3340
    {
 
3341
      if ( ACCESS_Frame( 2L ) )
 
3342
        goto Fail;
 
3343
 
 
3344
      new_offset = GET_UShort() + base_offset;
 
3345
 
 
3346
      FORGET_Frame();
 
3347
 
 
3348
      cur_offset = FILE_Pos();
 
3349
      if ( FILE_Seek( new_offset ) ||
 
3350
           ( error = Load_PosRule( &pr[n], stream ) ) != TT_Err_Ok )
 
3351
        goto Fail;
 
3352
      (void)FILE_Seek( cur_offset );
 
3353
    }
 
3354
 
 
3355
    return TT_Err_Ok;
 
3356
 
 
3357
  Fail:
 
3358
    for ( m = 0; m < n; m++ )
 
3359
      Free_PosRule( &pr[m], memory );
 
3360
 
 
3361
    FREE( pr );
 
3362
    return error;
 
3363
  }
 
3364
 
 
3365
 
 
3366
  static void  Free_PosRuleSet( TTO_PosRuleSet*  prs,
 
3367
                                FT_Memory        memory )
 
3368
  {
 
3369
    FT_UShort     n, count;
 
3370
 
 
3371
    TTO_PosRule*  pr;
 
3372
 
 
3373
 
 
3374
    if ( prs->PosRule )
 
3375
    {
 
3376
      count = prs->PosRuleCount;
 
3377
      pr    = prs->PosRule;
 
3378
 
 
3379
      for ( n = 0; n < count; n++ )
 
3380
        Free_PosRule( &pr[n], memory );
 
3381
 
 
3382
      FREE( pr );
 
3383
    }
 
3384
  }
 
3385
 
 
3386
 
 
3387
  /* ContextPosFormat1 */
 
3388
 
 
3389
  static FT_Error  Load_ContextPos1( TTO_ContextPosFormat1*  cpf1,
 
3390
                                     FT_Stream               stream )
 
3391
  {
 
3392
    FT_Error  error;
 
3393
    FT_Memory memory = stream->memory;
 
3394
 
 
3395
    FT_UShort        n, m, count;
 
3396
    FT_ULong         cur_offset, new_offset, base_offset;
 
3397
 
 
3398
    TTO_PosRuleSet*  prs;
 
3399
 
 
3400
 
 
3401
    base_offset = FILE_Pos() - 2L;
 
3402
 
 
3403
    if ( ACCESS_Frame( 2L ) )
 
3404
      return error;
 
3405
 
 
3406
    new_offset = GET_UShort() + base_offset;
 
3407
 
 
3408
    FORGET_Frame();
 
3409
 
 
3410
    cur_offset = FILE_Pos();
 
3411
    if ( FILE_Seek( new_offset ) ||
 
3412
         ( error = Load_Coverage( &cpf1->Coverage, stream ) ) != TT_Err_Ok )
 
3413
      return error;
 
3414
    (void)FILE_Seek( cur_offset );
 
3415
 
 
3416
    if ( ACCESS_Frame( 2L ) )
 
3417
      goto Fail2;
 
3418
 
 
3419
    count = cpf1->PosRuleSetCount = GET_UShort();
 
3420
 
 
3421
    FORGET_Frame();
 
3422
 
 
3423
    cpf1->PosRuleSet = NULL;
 
3424
 
 
3425
    if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, TTO_PosRuleSet ) )
 
3426
      goto Fail2;
 
3427
 
 
3428
    prs = cpf1->PosRuleSet;
 
3429
 
 
3430
    for ( n = 0; n < count; n++ )
 
3431
    {
 
3432
      if ( ACCESS_Frame( 2L ) )
 
3433
        goto Fail1;
 
3434
 
 
3435
      new_offset = GET_UShort() + base_offset;
 
3436
 
 
3437
      FORGET_Frame();
 
3438
 
 
3439
      cur_offset = FILE_Pos();
 
3440
      if ( FILE_Seek( new_offset ) ||
 
3441
           ( error = Load_PosRuleSet( &prs[n], stream ) ) != TT_Err_Ok )
 
3442
        goto Fail1;
 
3443
      (void)FILE_Seek( cur_offset );
 
3444
    }
 
3445
 
 
3446
    return TT_Err_Ok;
 
3447
 
 
3448
  Fail1:
 
3449
    for ( m = 0; m < n; m++ )
 
3450
      Free_PosRuleSet( &prs[m], memory );
 
3451
 
 
3452
    FREE( prs );
 
3453
 
 
3454
  Fail2:
 
3455
    Free_Coverage( &cpf1->Coverage, memory );
 
3456
    return error;
 
3457
  }
 
3458
 
 
3459
 
 
3460
  static void  GPos_Free_Context1( TTO_ContextPosFormat1*  cpf1,
 
3461
                              FT_Memory               memory )
 
3462
  {
 
3463
    FT_UShort        n, count;
 
3464
 
 
3465
    TTO_PosRuleSet*  prs;
 
3466
 
 
3467
 
 
3468
    if ( cpf1->PosRuleSet )
 
3469
    {
 
3470
      count = cpf1->PosRuleSetCount;
 
3471
      prs   = cpf1->PosRuleSet;
 
3472
 
 
3473
      for ( n = 0; n < count; n++ )
 
3474
        Free_PosRuleSet( &prs[n], memory );
 
3475
 
 
3476
      FREE( prs );
 
3477
    }
 
3478
 
 
3479
    Free_Coverage( &cpf1->Coverage, memory );
 
3480
  }
 
3481
 
 
3482
 
 
3483
  /* PosClassRule */
 
3484
 
 
3485
  static FT_Error  Load_PosClassRule( TTO_ContextPosFormat2*  cpf2,
 
3486
                                      TTO_PosClassRule*       pcr,
 
3487
                                      FT_Stream               stream )
 
3488
  {
 
3489
    FT_Error  error;
 
3490
    FT_Memory memory = stream->memory;
 
3491
 
 
3492
    FT_UShort             n, count;
 
3493
 
 
3494
    FT_UShort*            c;
 
3495
    TTO_PosLookupRecord*  plr;
 
3496
    FT_Bool*              d;
 
3497
 
 
3498
 
 
3499
    if ( ACCESS_Frame( 4L ) )
 
3500
      return error;
 
3501
 
 
3502
    pcr->GlyphCount = GET_UShort();
 
3503
    pcr->PosCount   = GET_UShort();
 
3504
 
 
3505
    FORGET_Frame();
 
3506
 
 
3507
    if ( pcr->GlyphCount > cpf2->MaxContextLength )
 
3508
      cpf2->MaxContextLength = pcr->GlyphCount;
 
3509
 
 
3510
    pcr->Class = NULL;
 
3511
 
 
3512
    count = pcr->GlyphCount - 1;        /* only GlyphCount - 1 elements */
 
3513
 
 
3514
    if ( ALLOC_ARRAY( pcr->Class, count, FT_UShort ) )
 
3515
      return error;
 
3516
 
 
3517
    c = pcr->Class;
 
3518
    d = cpf2->ClassDef.Defined;
 
3519
 
 
3520
    if ( ACCESS_Frame( count * 2L ) )
 
3521
      goto Fail2;
 
3522
 
 
3523
    for ( n = 0; n < count; n++ )
 
3524
    {
 
3525
      c[n] = GET_UShort();
 
3526
 
 
3527
      /* We check whether the specific class is used at all.  If not,
 
3528
         class 0 is used instead.                                     */
 
3529
 
 
3530
      /*
 
3531
        if ( !d[c[n]] )
 
3532
            c[n] = 0;
 
3533
      */
 
3534
    }
 
3535
 
 
3536
    FORGET_Frame();
 
3537
 
 
3538
    pcr->PosLookupRecord = NULL;
 
3539
 
 
3540
    count = pcr->PosCount;
 
3541
 
 
3542
    if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, TTO_PosLookupRecord ) )
 
3543
      goto Fail2;
 
3544
 
 
3545
    plr = pcr->PosLookupRecord;
 
3546
 
 
3547
    if ( ACCESS_Frame( count * 4L ) )
 
3548
      goto Fail1;
 
3549
 
 
3550
    for ( n = 0; n < count; n++ )
 
3551
    {
 
3552
      plr[n].SequenceIndex   = GET_UShort();
 
3553
      plr[n].LookupListIndex = GET_UShort();
 
3554
    }
 
3555
 
 
3556
    FORGET_Frame();
 
3557
 
 
3558
    return TT_Err_Ok;
 
3559
 
 
3560
  Fail1:
 
3561
    FREE( plr );
 
3562
 
 
3563
  Fail2:
 
3564
    FREE( c );
 
3565
    return error;
 
3566
  }
 
3567
 
 
3568
 
 
3569
  static void  Free_PosClassRule( TTO_PosClassRule*  pcr,
 
3570
                                  FT_Memory          memory )
 
3571
  {
 
3572
    FREE( pcr->PosLookupRecord );
 
3573
    FREE( pcr->Class );
 
3574
  }
 
3575
 
 
3576
 
 
3577
  /* PosClassSet */
 
3578
 
 
3579
  static FT_Error  Load_PosClassSet( TTO_ContextPosFormat2*  cpf2,
 
3580
                                     TTO_PosClassSet*        pcs,
 
3581
                                     FT_Stream               stream )
 
3582
  {
 
3583
    FT_Error  error;
 
3584
    FT_Memory memory = stream->memory;
 
3585
 
 
3586
    FT_UShort          n, m, count;
 
3587
    FT_ULong           cur_offset, new_offset, base_offset;
 
3588
 
 
3589
    TTO_PosClassRule*  pcr;
 
3590
 
 
3591
 
 
3592
    base_offset = FILE_Pos();
 
3593
 
 
3594
    if ( ACCESS_Frame( 2L ) )
 
3595
      return error;
 
3596
 
 
3597
    count = pcs->PosClassRuleCount = GET_UShort();
 
3598
 
 
3599
    FORGET_Frame();
 
3600
 
 
3601
    pcs->PosClassRule = NULL;
 
3602
 
 
3603
    if ( ALLOC_ARRAY( pcs->PosClassRule, count, TTO_PosClassRule ) )
 
3604
      return error;
 
3605
 
 
3606
    pcr = pcs->PosClassRule;
 
3607
 
 
3608
    for ( n = 0; n < count; n++ )
 
3609
    {
 
3610
      if ( ACCESS_Frame( 2L ) )
 
3611
        goto Fail;
 
3612
 
 
3613
      new_offset = GET_UShort() + base_offset;
 
3614
 
 
3615
      FORGET_Frame();
 
3616
 
 
3617
      cur_offset = FILE_Pos();
 
3618
      if ( FILE_Seek( new_offset ) ||
 
3619
           ( error = Load_PosClassRule( cpf2, &pcr[n],
 
3620
                                        stream ) ) != TT_Err_Ok )
 
3621
        goto Fail;
 
3622
      (void)FILE_Seek( cur_offset );
 
3623
    }
 
3624
 
 
3625
    return TT_Err_Ok;
 
3626
 
 
3627
  Fail:
 
3628
    for ( m = 0; m < n; m++ )
 
3629
      Free_PosClassRule( &pcr[m], memory );
 
3630
 
 
3631
    FREE( pcr );
 
3632
    return error;
 
3633
  }
 
3634
 
 
3635
 
 
3636
  static void  Free_PosClassSet( TTO_PosClassSet*  pcs,
 
3637
                                 FT_Memory         memory )
 
3638
  {
 
3639
    FT_UShort          n, count;
 
3640
 
 
3641
    TTO_PosClassRule*  pcr;
 
3642
 
 
3643
 
 
3644
    if ( pcs->PosClassRule )
 
3645
    {
 
3646
      count = pcs->PosClassRuleCount;
 
3647
      pcr   = pcs->PosClassRule;
 
3648
 
 
3649
      for ( n = 0; n < count; n++ )
 
3650
        Free_PosClassRule( &pcr[n], memory );
 
3651
 
 
3652
      FREE( pcr );
 
3653
    }
 
3654
  }
 
3655
 
 
3656
 
 
3657
  /* ContextPosFormat2 */
 
3658
 
 
3659
  static FT_Error  Load_ContextPos2( TTO_ContextPosFormat2*  cpf2,
 
3660
                                     FT_Stream               stream )
 
3661
  {
 
3662
    FT_Error  error;
 
3663
    FT_Memory memory = stream->memory;
 
3664
 
 
3665
    FT_UShort         n, m, count;
 
3666
    FT_ULong          cur_offset, new_offset, base_offset;
 
3667
 
 
3668
    TTO_PosClassSet*  pcs;
 
3669
 
 
3670
 
 
3671
    base_offset = FILE_Pos() - 2;
 
3672
 
 
3673
    if ( ACCESS_Frame( 2L ) )
 
3674
      return error;
 
3675
 
 
3676
    new_offset = GET_UShort() + base_offset;
 
3677
 
 
3678
    FORGET_Frame();
 
3679
 
 
3680
    cur_offset = FILE_Pos();
 
3681
    if ( FILE_Seek( new_offset ) ||
 
3682
         ( error = Load_Coverage( &cpf2->Coverage, stream ) ) != TT_Err_Ok )
 
3683
      return error;
 
3684
    (void)FILE_Seek( cur_offset );
 
3685
 
 
3686
    if ( ACCESS_Frame( 4L ) )
 
3687
      goto Fail3;
 
3688
 
 
3689
    new_offset = GET_UShort() + base_offset;
 
3690
 
 
3691
    /* `PosClassSetCount' is the upper limit for class values, thus we
 
3692
       read it now to make an additional safety check.                 */
 
3693
 
 
3694
    count = cpf2->PosClassSetCount = GET_UShort();
 
3695
 
 
3696
    FORGET_Frame();
 
3697
 
 
3698
    cur_offset = FILE_Pos();
 
3699
    if ( FILE_Seek( new_offset ) ||
 
3700
         ( error = Load_ClassDefinition( &cpf2->ClassDef, count,
 
3701
                                         stream ) ) != TT_Err_Ok )
 
3702
      goto Fail3;
 
3703
    (void)FILE_Seek( cur_offset );
 
3704
 
 
3705
    cpf2->PosClassSet      = NULL;
 
3706
    cpf2->MaxContextLength = 0;
 
3707
 
 
3708
    if ( ALLOC_ARRAY( cpf2->PosClassSet, count, TTO_PosClassSet ) )
 
3709
      goto Fail2;
 
3710
 
 
3711
    pcs = cpf2->PosClassSet;
 
3712
 
 
3713
    for ( n = 0; n < count; n++ )
 
3714
    {
 
3715
      if ( ACCESS_Frame( 2L ) )
 
3716
        goto Fail1;
 
3717
 
 
3718
      new_offset = GET_UShort() + base_offset;
 
3719
 
 
3720
      FORGET_Frame();
 
3721
 
 
3722
      if ( new_offset != base_offset )      /* not a NULL offset */
 
3723
      {
 
3724
        cur_offset = FILE_Pos();
 
3725
        if ( FILE_Seek( new_offset ) ||
 
3726
             ( error = Load_PosClassSet( cpf2, &pcs[n],
 
3727
                                         stream ) ) != TT_Err_Ok )
 
3728
          goto Fail1;
 
3729
        (void)FILE_Seek( cur_offset );
 
3730
      }
 
3731
      else
 
3732
      {
 
3733
        /* we create a PosClassSet table with no entries */
 
3734
 
 
3735
        cpf2->PosClassSet[n].PosClassRuleCount = 0;
 
3736
        cpf2->PosClassSet[n].PosClassRule      = NULL;
 
3737
      }
 
3738
    }
 
3739
 
 
3740
    return TT_Err_Ok;
 
3741
 
 
3742
  Fail1:
 
3743
    for ( m = 0; m < n; n++ )
 
3744
      Free_PosClassSet( &pcs[m], memory );
 
3745
 
 
3746
    FREE( pcs );
 
3747
 
 
3748
  Fail2:
 
3749
    Free_ClassDefinition( &cpf2->ClassDef, memory );
 
3750
 
 
3751
  Fail3:
 
3752
    Free_Coverage( &cpf2->Coverage, memory );
 
3753
    return error;
 
3754
  }
 
3755
 
 
3756
 
 
3757
  static void  GPos_Free_Context2( TTO_ContextPosFormat2*  cpf2,
 
3758
                              FT_Memory               memory )
 
3759
  {
 
3760
    FT_UShort         n, count;
 
3761
 
 
3762
    TTO_PosClassSet*  pcs;
 
3763
 
 
3764
 
 
3765
    if ( cpf2->PosClassSet )
 
3766
    {
 
3767
      count = cpf2->PosClassSetCount;
 
3768
      pcs   = cpf2->PosClassSet;
 
3769
 
 
3770
      for ( n = 0; n < count; n++ )
 
3771
        Free_PosClassSet( &pcs[n], memory );
 
3772
 
 
3773
      FREE( pcs );
 
3774
    }
 
3775
 
 
3776
    Free_ClassDefinition( &cpf2->ClassDef, memory );
 
3777
    Free_Coverage( &cpf2->Coverage, memory );
 
3778
  }
 
3779
 
 
3780
 
 
3781
  /* ContextPosFormat3 */
 
3782
 
 
3783
  static FT_Error  Load_ContextPos3( TTO_ContextPosFormat3*  cpf3,
 
3784
                                     FT_Stream               stream )
 
3785
  {
 
3786
    FT_Error  error;
 
3787
    FT_Memory memory = stream->memory;
 
3788
 
 
3789
    FT_UShort             n, count;
 
3790
    FT_ULong              cur_offset, new_offset, base_offset;
 
3791
 
 
3792
    TTO_Coverage*         c;
 
3793
    TTO_PosLookupRecord*  plr;
 
3794
 
 
3795
 
 
3796
    base_offset = FILE_Pos() - 2L;
 
3797
 
 
3798
    if ( ACCESS_Frame( 4L ) )
 
3799
      return error;
 
3800
 
 
3801
    cpf3->GlyphCount = GET_UShort();
 
3802
    cpf3->PosCount   = GET_UShort();
 
3803
 
 
3804
    FORGET_Frame();
 
3805
 
 
3806
    cpf3->Coverage = NULL;
 
3807
 
 
3808
    count = cpf3->GlyphCount;
 
3809
 
 
3810
    if ( ALLOC_ARRAY( cpf3->Coverage, count, TTO_Coverage ) )
 
3811
      return error;
 
3812
 
 
3813
    c = cpf3->Coverage;
 
3814
 
 
3815
    for ( n = 0; n < count; n++ )
 
3816
    {
 
3817
      if ( ACCESS_Frame( 2L ) )
 
3818
        goto Fail2;
 
3819
 
 
3820
      new_offset = GET_UShort() + base_offset;
 
3821
 
 
3822
      FORGET_Frame();
 
3823
 
 
3824
      cur_offset = FILE_Pos();
 
3825
      if ( FILE_Seek( new_offset ) ||
 
3826
           ( error = Load_Coverage( &c[n], stream ) ) != TT_Err_Ok )
 
3827
        goto Fail2;
 
3828
      (void)FILE_Seek( cur_offset );
 
3829
    }
 
3830
 
 
3831
    cpf3->PosLookupRecord = NULL;
 
3832
 
 
3833
    count = cpf3->PosCount;
 
3834
 
 
3835
    if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, TTO_PosLookupRecord ) )
 
3836
      goto Fail2;
 
3837
 
 
3838
    plr = cpf3->PosLookupRecord;
 
3839
 
 
3840
    if ( ACCESS_Frame( count * 4L ) )
 
3841
      goto Fail1;
 
3842
 
 
3843
    for ( n = 0; n < count; n++ )
 
3844
    {
 
3845
      plr[n].SequenceIndex   = GET_UShort();
 
3846
      plr[n].LookupListIndex = GET_UShort();
 
3847
    }
 
3848
 
 
3849
    FORGET_Frame();
 
3850
 
 
3851
    return TT_Err_Ok;
 
3852
 
 
3853
  Fail1:
 
3854
    FREE( plr );
 
3855
 
 
3856
  Fail2:
 
3857
    for ( n = 0; n < count; n++ )
 
3858
      Free_Coverage( &c[n], memory );
 
3859
 
 
3860
    FREE( c );
 
3861
    return error;
 
3862
  }
 
3863
 
 
3864
 
 
3865
  static void  GPos_Free_Context3( TTO_ContextPosFormat3*  cpf3,
 
3866
                              FT_Memory               memory )
 
3867
  {
 
3868
    FT_UShort      n, count;
 
3869
 
 
3870
    TTO_Coverage*  c;
 
3871
 
 
3872
 
 
3873
    FREE( cpf3->PosLookupRecord );
 
3874
 
 
3875
    if ( cpf3->Coverage )
 
3876
    {
 
3877
      count = cpf3->GlyphCount;
 
3878
      c     = cpf3->Coverage;
 
3879
 
 
3880
      for ( n = 0; n < count; n++ )
 
3881
        Free_Coverage( &c[n], memory );
 
3882
 
 
3883
      FREE( c );
 
3884
    }
 
3885
  }
 
3886
 
 
3887
 
 
3888
  /* ContextPos */
 
3889
 
 
3890
  FT_Error  Load_ContextPos( TTO_ContextPos*  cp,
 
3891
                             FT_Stream        stream )
 
3892
  {
 
3893
    FT_Error  error;
 
3894
 
 
3895
 
 
3896
    if ( ACCESS_Frame( 2L ) )
 
3897
      return error;
 
3898
 
 
3899
    cp->PosFormat = GET_UShort();
 
3900
 
 
3901
    FORGET_Frame();
 
3902
 
 
3903
    switch ( cp->PosFormat )
 
3904
    {
 
3905
    case 1:
 
3906
      return Load_ContextPos1( &cp->cpf.cpf1, stream );
 
3907
 
 
3908
    case 2:
 
3909
      return Load_ContextPos2( &cp->cpf.cpf2, stream );
 
3910
 
 
3911
    case 3:
 
3912
      return Load_ContextPos3( &cp->cpf.cpf3, stream );
 
3913
 
 
3914
    default:
 
3915
      return TTO_Err_Invalid_GPOS_SubTable_Format;
 
3916
    }
 
3917
 
 
3918
    return TT_Err_Ok;               /* never reached */
 
3919
  }
 
3920
 
 
3921
 
 
3922
  void  Free_ContextPos( TTO_ContextPos*  cp,
 
3923
                         FT_Memory        memory )
 
3924
  {
 
3925
    switch ( cp->PosFormat )
 
3926
    {
 
3927
    case 1:
 
3928
      GPos_Free_Context1( &cp->cpf.cpf1, memory );
 
3929
      break;
 
3930
 
 
3931
    case 2:
 
3932
      GPos_Free_Context2( &cp->cpf.cpf2, memory );
 
3933
      break;
 
3934
 
 
3935
    case 3:
 
3936
      GPos_Free_Context3( &cp->cpf.cpf3, memory );
 
3937
      break;
 
3938
    }
 
3939
  }
 
3940
 
 
3941
 
 
3942
  static FT_Error  Lookup_ContextPos1( GPOS_Instance*          gpi,
 
3943
                                       TTO_ContextPosFormat1*  cpf1,
 
3944
                                       TTO_GSUB_String*        in,
 
3945
                                       TTO_GPOS_Data*          out,
 
3946
                                       FT_UShort               flags,
 
3947
                                       FT_UShort               context_length,
 
3948
                                       int                     nesting_level )
 
3949
  {
 
3950
    FT_UShort        index, property;
 
3951
    FT_UShort        i, j, k, numpr;
 
3952
    FT_Error         error;
 
3953
    FT_UShort*       s_in;
 
3954
    TTO_GPOSHeader*  gpos = gpi->gpos;
 
3955
 
 
3956
    TTO_PosRule*     pr;
 
3957
    TTO_GDEFHeader*  gdef;
 
3958
 
 
3959
    error = Coverage_Index( &cpf1->Coverage, in->string[in->pos], &index );
 
3960
    if ( error )
 
3961
      return error;
 
3962
 
 
3963
    gdef = gpos->gdef;
 
3964
 
 
3965
    if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
 
3966
      return error;
 
3967
 
 
3968
    pr    = cpf1->PosRuleSet[index].PosRule;
 
3969
    numpr = cpf1->PosRuleSet[index].PosRuleCount;
 
3970
 
 
3971
    for ( k = 0; k < numpr; k++ )
 
3972
    {
 
3973
      if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount )
 
3974
        continue;
 
3975
 
 
3976
      if ( in->pos + pr[k].GlyphCount > in->length )
 
3977
        continue;                           /* context is too long */
 
3978
 
 
3979
      s_in = &in->string[in->pos];
 
3980
 
 
3981
      for ( i = 1, j = 1; i < pr[k].GlyphCount; i++, j++ )
 
3982
      {
 
3983
        while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
 
3984
        {
 
3985
          if ( error && error != TTO_Err_Not_Covered )
 
3986
            return error;
 
3987
 
 
3988
          if ( in->pos + j < in->length )
 
3989
            j++;
 
3990
          else
 
3991
            break;
 
3992
        }
 
3993
 
 
3994
        if ( s_in[j] != pr[k].Input[i - 1] )
 
3995
          break;
 
3996
      }
 
3997
 
 
3998
      if ( i == pr[k].GlyphCount )
 
3999
        return Do_ContextPos( gpi, pr[k].GlyphCount,
 
4000
                              pr[k].PosCount, pr[k].PosLookupRecord,
 
4001
                              in, out,
 
4002
                              nesting_level );
 
4003
    }
 
4004
 
 
4005
    return TTO_Err_Not_Covered;
 
4006
  }
 
4007
 
 
4008
 
 
4009
  static FT_Error  Lookup_ContextPos2( GPOS_Instance*          gpi,
 
4010
                                       TTO_ContextPosFormat2*  cpf2,
 
4011
                                       TTO_GSUB_String*        in,
 
4012
                                       TTO_GPOS_Data*          out,
 
4013
                                       FT_UShort               flags,
 
4014
                                       FT_UShort               context_length,
 
4015
                                       int                     nesting_level )
 
4016
  {
 
4017
    FT_UShort          index, property;
 
4018
    FT_Error           error;
 
4019
    FT_Memory          memory = gpi->face->memory;
 
4020
    FT_UShort          i, j, k, known_classes;
 
4021
 
 
4022
    FT_UShort*         classes;
 
4023
    FT_UShort*         s_in;
 
4024
    FT_UShort*         cl;
 
4025
    TTO_GPOSHeader*    gpos = gpi->gpos;
 
4026
 
 
4027
    TTO_PosClassSet*   pcs;
 
4028
    TTO_PosClassRule*  pr;
 
4029
    TTO_GDEFHeader*    gdef;
 
4030
 
 
4031
    /* Note: The coverage table in format 2 doesn't give an index into
 
4032
             anything.  It just lets us know whether or not we need to
 
4033
             do any lookup at all.                                     */
 
4034
 
 
4035
    error = Coverage_Index( &cpf2->Coverage, in->string[in->pos], &index );
 
4036
    if ( error )
 
4037
      return error;
 
4038
 
 
4039
    gdef = gpos->gdef;
 
4040
 
 
4041
    if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
 
4042
      return error;
 
4043
 
 
4044
    if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, FT_UShort ) )
 
4045
      return error;
 
4046
 
 
4047
    error = Get_Class( &cpf2->ClassDef, in->string[in->pos],
 
4048
                       &classes[0], NULL );
 
4049
    if ( error && error != TTO_Err_Not_Covered )
 
4050
      goto End;
 
4051
    known_classes = 0;
 
4052
 
 
4053
    pcs = &cpf2->PosClassSet[classes[0]];
 
4054
    if ( !pcs )
 
4055
    {
 
4056
      error = TTO_Err_Invalid_GPOS_SubTable;
 
4057
      goto End;
 
4058
    }
 
4059
 
 
4060
    for ( k = 0; k < pcs->PosClassRuleCount; k++ )
 
4061
    {
 
4062
      pr = &pcs->PosClassRule[k];
 
4063
 
 
4064
      if ( context_length != 0xFFFF && context_length < pr->GlyphCount )
 
4065
        continue;
 
4066
 
 
4067
      if ( in->pos + pr->GlyphCount > in->length )
 
4068
        continue;                           /* context is too long */
 
4069
 
 
4070
      s_in = &in->string[in->pos];
 
4071
      cl   = pr->Class;
 
4072
 
 
4073
      /* Start at 1 because [0] is implied */
 
4074
 
 
4075
      for ( i = 1, j = 1; i < pr->GlyphCount; i++, j++ )
 
4076
      {
 
4077
        while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
 
4078
        {
 
4079
          if ( error && error != TTO_Err_Not_Covered )
 
4080
            goto End;
 
4081
 
 
4082
          if ( in->pos + j < in->length )
 
4083
            j++;
 
4084
          else
 
4085
            break;
 
4086
        }
 
4087
 
 
4088
        if ( i > known_classes )
 
4089
        {
 
4090
          /* Keeps us from having to do this for each rule */
 
4091
 
 
4092
          error = Get_Class( &cpf2->ClassDef, s_in[j], &classes[i], NULL );
 
4093
          if ( error && error != TTO_Err_Not_Covered )
 
4094
            goto End;
 
4095
          known_classes = i;
 
4096
        }
 
4097
 
 
4098
        if ( cl[i - 1] != classes[i] )
 
4099
          break;
 
4100
      }
 
4101
 
 
4102
      if ( i == pr->GlyphCount )
 
4103
      {
 
4104
        error = Do_ContextPos( gpi, pr->GlyphCount,
 
4105
                               pr->PosCount, pr->PosLookupRecord,
 
4106
                               in, out,
 
4107
                               nesting_level );
 
4108
        goto End;
 
4109
      }
 
4110
    }
 
4111
 
 
4112
    error = TTO_Err_Not_Covered;
 
4113
 
 
4114
  End:
 
4115
    FREE( classes );
 
4116
    return error;
 
4117
  }
 
4118
 
 
4119
 
 
4120
  static FT_Error  Lookup_ContextPos3( GPOS_Instance*          gpi,
 
4121
                                       TTO_ContextPosFormat3*  cpf3,
 
4122
                                       TTO_GSUB_String*        in,
 
4123
                                       TTO_GPOS_Data*          out,
 
4124
                                       FT_UShort               flags,
 
4125
                                       FT_UShort               context_length,
 
4126
                                       int                     nesting_level )
 
4127
  {
 
4128
    FT_Error         error;
 
4129
    FT_UShort        index, i, j, property;
 
4130
    FT_UShort*       s_in;
 
4131
    TTO_GPOSHeader*  gpos = gpi->gpos;
 
4132
 
 
4133
    TTO_Coverage*    c;
 
4134
    TTO_GDEFHeader*  gdef;
 
4135
 
 
4136
 
 
4137
    gdef = gpos->gdef;
 
4138
 
 
4139
    if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
 
4140
      return TTO_Err_Not_Covered;
 
4141
 
 
4142
    if ( in->pos + cpf3->GlyphCount > in->length )
 
4143
      return TTO_Err_Not_Covered;         /* context is too long */
 
4144
 
 
4145
    if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
 
4146
      return error;
 
4147
 
 
4148
    s_in = &in->string[in->pos];
 
4149
    c    = cpf3->Coverage;
 
4150
 
 
4151
    for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
 
4152
    {
 
4153
      while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
 
4154
      {
 
4155
        if ( error && error != TTO_Err_Not_Covered )
 
4156
          return error;
 
4157
 
 
4158
        if ( in->pos + j < in->length )
 
4159
          j++;
 
4160
        else
 
4161
          return TTO_Err_Not_Covered;
 
4162
      }
 
4163
 
 
4164
      error = Coverage_Index( &c[i], s_in[j], &index );
 
4165
      if ( error )
 
4166
        return error;
 
4167
    }
 
4168
 
 
4169
    return Do_ContextPos( gpi, cpf3->GlyphCount,
 
4170
                          cpf3->PosCount, cpf3->PosLookupRecord,
 
4171
                          in, out,
 
4172
                          nesting_level );
 
4173
  }
 
4174
 
 
4175
 
 
4176
  static FT_Error  Lookup_ContextPos( GPOS_Instance*    gpi,
 
4177
                                      TTO_ContextPos*   cp,
 
4178
                                      TTO_GSUB_String*  in,
 
4179
                                      TTO_GPOS_Data*    out,
 
4180
                                      FT_UShort         flags,
 
4181
                                      FT_UShort         context_length,
 
4182
                                      int               nesting_level )
 
4183
  {
 
4184
    switch ( cp->PosFormat )
 
4185
    {
 
4186
    case 1:
 
4187
      return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, in, out,
 
4188
                                 flags, context_length, nesting_level );
 
4189
 
 
4190
    case 2:
 
4191
      return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, in, out,
 
4192
                                 flags, context_length, nesting_level );
 
4193
 
 
4194
    case 3:
 
4195
      return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, in, out,
 
4196
                                 flags, context_length, nesting_level );
 
4197
 
 
4198
    default:
 
4199
      return TTO_Err_Invalid_GPOS_SubTable_Format;
 
4200
    }
 
4201
 
 
4202
    return TT_Err_Ok;               /* never reached */
 
4203
  }
 
4204
 
 
4205
 
 
4206
  /* LookupType 8 */
 
4207
 
 
4208
  /* ChainPosRule */
 
4209
 
 
4210
  static FT_Error  Load_ChainPosRule( TTO_ChainPosRule*  cpr,
 
4211
                                      FT_Stream          stream )
 
4212
  {
 
4213
    FT_Error  error;
 
4214
    FT_Memory memory = stream->memory;
 
4215
 
 
4216
    FT_UShort             n, count;
 
4217
    FT_UShort*            b;
 
4218
    FT_UShort*            i;
 
4219
    FT_UShort*            l;
 
4220
 
 
4221
    TTO_PosLookupRecord*  plr;
 
4222
 
 
4223
 
 
4224
    if ( ACCESS_Frame( 2L ) )
 
4225
      return error;
 
4226
 
 
4227
    cpr->BacktrackGlyphCount = GET_UShort();
 
4228
 
 
4229
    FORGET_Frame();
 
4230
 
 
4231
    cpr->Backtrack = NULL;
 
4232
 
 
4233
    count = cpr->BacktrackGlyphCount;
 
4234
 
 
4235
    if ( ALLOC_ARRAY( cpr->Backtrack, count, FT_UShort ) )
 
4236
      return error;
 
4237
 
 
4238
    b = cpr->Backtrack;
 
4239
 
 
4240
    if ( ACCESS_Frame( count * 2L ) )
 
4241
      goto Fail4;
 
4242
 
 
4243
    for ( n = 0; n < count; n++ )
 
4244
      b[n] = GET_UShort();
 
4245
 
 
4246
    FORGET_Frame();
 
4247
 
 
4248
    if ( ACCESS_Frame( 2L ) )
 
4249
      goto Fail4;
 
4250
 
 
4251
    cpr->InputGlyphCount = GET_UShort();
 
4252
 
 
4253
    FORGET_Frame();
 
4254
 
 
4255
    cpr->Input = NULL;
 
4256
 
 
4257
    count = cpr->InputGlyphCount - 1;  /* only InputGlyphCount - 1 elements */
 
4258
 
 
4259
    if ( ALLOC_ARRAY( cpr->Input, count, FT_UShort ) )
 
4260
      goto Fail4;
 
4261
 
 
4262
    i = cpr->Input;
 
4263
 
 
4264
    if ( ACCESS_Frame( count * 2L ) )
 
4265
      goto Fail3;
 
4266
 
 
4267
    for ( n = 0; n < count; n++ )
 
4268
      i[n] = GET_UShort();
 
4269
 
 
4270
    FORGET_Frame();
 
4271
 
 
4272
    if ( ACCESS_Frame( 2L ) )
 
4273
      goto Fail3;
 
4274
 
 
4275
    cpr->LookaheadGlyphCount = GET_UShort();
 
4276
 
 
4277
    FORGET_Frame();
 
4278
 
 
4279
    cpr->Lookahead = NULL;
 
4280
 
 
4281
    count = cpr->LookaheadGlyphCount;
 
4282
 
 
4283
    if ( ALLOC_ARRAY( cpr->Lookahead, count, FT_UShort ) )
 
4284
      goto Fail3;
 
4285
 
 
4286
    l = cpr->Lookahead;
 
4287
 
 
4288
    if ( ACCESS_Frame( count * 2L ) )
 
4289
      goto Fail2;
 
4290
 
 
4291
    for ( n = 0; n < count; n++ )
 
4292
      l[n] = GET_UShort();
 
4293
 
 
4294
    FORGET_Frame();
 
4295
 
 
4296
    if ( ACCESS_Frame( 2L ) )
 
4297
      goto Fail2;
 
4298
 
 
4299
    cpr->PosCount = GET_UShort();
 
4300
 
 
4301
    FORGET_Frame();
 
4302
 
 
4303
    cpr->PosLookupRecord = NULL;
 
4304
 
 
4305
    count = cpr->PosCount;
 
4306
 
 
4307
    if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, TTO_PosLookupRecord ) )
 
4308
      goto Fail2;
 
4309
 
 
4310
    plr = cpr->PosLookupRecord;
 
4311
 
 
4312
    if ( ACCESS_Frame( count * 4L ) )
 
4313
      goto Fail1;
 
4314
 
 
4315
    for ( n = 0; n < count; n++ )
 
4316
    {
 
4317
      plr[n].SequenceIndex   = GET_UShort();
 
4318
      plr[n].LookupListIndex = GET_UShort();
 
4319
    }
 
4320
 
 
4321
    FORGET_Frame();
 
4322
 
 
4323
    return TT_Err_Ok;
 
4324
 
 
4325
  Fail1:
 
4326
    FREE( plr );
 
4327
 
 
4328
  Fail2:
 
4329
    FREE( l );
 
4330
 
 
4331
  Fail3:
 
4332
    FREE( i );
 
4333
 
 
4334
  Fail4:
 
4335
    FREE( b );
 
4336
    return error;
 
4337
  }
 
4338
 
 
4339
 
 
4340
  static void  Free_ChainPosRule( TTO_ChainPosRule*  cpr,
 
4341
                                  FT_Memory          memory )
 
4342
  {
 
4343
    FREE( cpr->PosLookupRecord );
 
4344
    FREE( cpr->Lookahead );
 
4345
    FREE( cpr->Input );
 
4346
    FREE( cpr->Backtrack );
 
4347
  }
 
4348
 
 
4349
 
 
4350
  /* ChainPosRuleSet */
 
4351
 
 
4352
  static FT_Error  Load_ChainPosRuleSet( TTO_ChainPosRuleSet*  cprs,
 
4353
                                         FT_Stream             stream )
 
4354
  {
 
4355
    FT_Error  error;
 
4356
    FT_Memory memory = stream->memory;
 
4357
 
 
4358
    FT_UShort          n, m, count;
 
4359
    FT_ULong           cur_offset, new_offset, base_offset;
 
4360
 
 
4361
    TTO_ChainPosRule*  cpr;
 
4362
 
 
4363
 
 
4364
    base_offset = FILE_Pos();
 
4365
 
 
4366
    if ( ACCESS_Frame( 2L ) )
 
4367
      return error;
 
4368
 
 
4369
    count = cprs->ChainPosRuleCount = GET_UShort();
 
4370
 
 
4371
    FORGET_Frame();
 
4372
 
 
4373
    cprs->ChainPosRule = NULL;
 
4374
 
 
4375
    if ( ALLOC_ARRAY( cprs->ChainPosRule, count, TTO_ChainPosRule ) )
 
4376
      return error;
 
4377
 
 
4378
    cpr = cprs->ChainPosRule;
 
4379
 
 
4380
    for ( n = 0; n < count; n++ )
 
4381
    {
 
4382
      if ( ACCESS_Frame( 2L ) )
 
4383
        goto Fail;
 
4384
 
 
4385
      new_offset = GET_UShort() + base_offset;
 
4386
 
 
4387
      FORGET_Frame();
 
4388
 
 
4389
      cur_offset = FILE_Pos();
 
4390
      if ( FILE_Seek( new_offset ) ||
 
4391
           ( error = Load_ChainPosRule( &cpr[n], stream ) ) != TT_Err_Ok )
 
4392
        goto Fail;
 
4393
      (void)FILE_Seek( cur_offset );
 
4394
    }
 
4395
 
 
4396
    return TT_Err_Ok;
 
4397
 
 
4398
  Fail:
 
4399
    for ( m = 0; m < n; m++ )
 
4400
      Free_ChainPosRule( &cpr[m], memory );
 
4401
 
 
4402
    FREE( cpr );
 
4403
    return error;
 
4404
  }
 
4405
 
 
4406
 
 
4407
  static void  Free_ChainPosRuleSet( TTO_ChainPosRuleSet*  cprs,
 
4408
                                     FT_Memory             memory )
 
4409
  {
 
4410
    FT_UShort          n, count;
 
4411
 
 
4412
    TTO_ChainPosRule*  cpr;
 
4413
 
 
4414
 
 
4415
    if ( cprs->ChainPosRule )
 
4416
    {
 
4417
      count = cprs->ChainPosRuleCount;
 
4418
      cpr   = cprs->ChainPosRule;
 
4419
 
 
4420
      for ( n = 0; n < count; n++ )
 
4421
        Free_ChainPosRule( &cpr[n], memory );
 
4422
 
 
4423
      FREE( cpr );
 
4424
    }
 
4425
  }
 
4426
 
 
4427
 
 
4428
  /* ChainContextPosFormat1 */
 
4429
 
 
4430
  static FT_Error  Load_ChainContextPos1( TTO_ChainContextPosFormat1*  ccpf1,
 
4431
                                          FT_Stream                    stream )
 
4432
  {
 
4433
    FT_Error  error;
 
4434
    FT_Memory memory = stream->memory;
 
4435
 
 
4436
    FT_UShort             n, m, count;
 
4437
    FT_ULong              cur_offset, new_offset, base_offset;
 
4438
 
 
4439
    TTO_ChainPosRuleSet*  cprs;
 
4440
 
 
4441
 
 
4442
    base_offset = FILE_Pos() - 2L;
 
4443
 
 
4444
    if ( ACCESS_Frame( 2L ) )
 
4445
      return error;
 
4446
 
 
4447
    new_offset = GET_UShort() + base_offset;
 
4448
 
 
4449
    FORGET_Frame();
 
4450
 
 
4451
    cur_offset = FILE_Pos();
 
4452
    if ( FILE_Seek( new_offset ) ||
 
4453
         ( error = Load_Coverage( &ccpf1->Coverage, stream ) ) != TT_Err_Ok )
 
4454
      return error;
 
4455
    (void)FILE_Seek( cur_offset );
 
4456
 
 
4457
    if ( ACCESS_Frame( 2L ) )
 
4458
      goto Fail2;
 
4459
 
 
4460
    count = ccpf1->ChainPosRuleSetCount = GET_UShort();
 
4461
 
 
4462
    FORGET_Frame();
 
4463
 
 
4464
    ccpf1->ChainPosRuleSet = NULL;
 
4465
 
 
4466
    if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, TTO_ChainPosRuleSet ) )
 
4467
      goto Fail2;
 
4468
 
 
4469
    cprs = ccpf1->ChainPosRuleSet;
 
4470
 
 
4471
    for ( n = 0; n < count; n++ )
 
4472
    {
 
4473
      if ( ACCESS_Frame( 2L ) )
 
4474
        goto Fail1;
 
4475
 
 
4476
      new_offset = GET_UShort() + base_offset;
 
4477
 
 
4478
      FORGET_Frame();
 
4479
 
 
4480
      cur_offset = FILE_Pos();
 
4481
      if ( FILE_Seek( new_offset ) ||
 
4482
           ( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != TT_Err_Ok )
 
4483
        goto Fail1;
 
4484
      (void)FILE_Seek( cur_offset );
 
4485
    }
 
4486
 
 
4487
    return TT_Err_Ok;
 
4488
 
 
4489
  Fail1:
 
4490
    for ( m = 0; m < n; m++ )
 
4491
      Free_ChainPosRuleSet( &cprs[m], memory );
 
4492
 
 
4493
    FREE( cprs );
 
4494
 
 
4495
  Fail2:
 
4496
    Free_Coverage( &ccpf1->Coverage, memory );
 
4497
    return error;
 
4498
  }
 
4499
 
 
4500
 
 
4501
  static void  GPos_Free_ChainContext1( TTO_ChainContextPosFormat1*  ccpf1,
 
4502
                                   FT_Memory                    memory )
 
4503
  {
 
4504
    FT_UShort             n, count;
 
4505
 
 
4506
    TTO_ChainPosRuleSet*  cprs;
 
4507
 
 
4508
 
 
4509
    if ( ccpf1->ChainPosRuleSet )
 
4510
    {
 
4511
      count = ccpf1->ChainPosRuleSetCount;
 
4512
      cprs  = ccpf1->ChainPosRuleSet;
 
4513
 
 
4514
      for ( n = 0; n < count; n++ )
 
4515
        Free_ChainPosRuleSet( &cprs[n], memory );
 
4516
 
 
4517
      FREE( cprs );
 
4518
    }
 
4519
 
 
4520
    Free_Coverage( &ccpf1->Coverage, memory );
 
4521
  }
 
4522
 
 
4523
 
 
4524
  /* ChainPosClassRule */
 
4525
 
 
4526
  static FT_Error  Load_ChainPosClassRule(
 
4527
                     TTO_ChainContextPosFormat2*  ccpf2,
 
4528
                     TTO_ChainPosClassRule*       cpcr,
 
4529
                     FT_Stream                    stream )
 
4530
  {
 
4531
    FT_Error  error;
 
4532
    FT_Memory memory = stream->memory;
 
4533
 
 
4534
    FT_UShort             n, count;
 
4535
 
 
4536
    FT_UShort*            b;
 
4537
    FT_UShort*            i;
 
4538
    FT_UShort*            l;
 
4539
    TTO_PosLookupRecord*  plr;
 
4540
    FT_Bool*              d;
 
4541
 
 
4542
 
 
4543
    if ( ACCESS_Frame( 2L ) )
 
4544
      return error;
 
4545
 
 
4546
    cpcr->BacktrackGlyphCount = GET_UShort();
 
4547
 
 
4548
    FORGET_Frame();
 
4549
 
 
4550
    if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength )
 
4551
      ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount;
 
4552
 
 
4553
    cpcr->Backtrack = NULL;
 
4554
 
 
4555
    count = cpcr->BacktrackGlyphCount;
 
4556
 
 
4557
    if ( ALLOC_ARRAY( cpcr->Backtrack, count, FT_UShort ) )
 
4558
      return error;
 
4559
 
 
4560
    b = cpcr->Backtrack;
 
4561
    d = ccpf2->BacktrackClassDef.Defined;
 
4562
 
 
4563
    if ( ACCESS_Frame( count * 2L ) )
 
4564
      goto Fail4;
 
4565
 
 
4566
    for ( n = 0; n < count; n++ )
 
4567
    {
 
4568
      b[n] = GET_UShort();
 
4569
 
 
4570
      /* We check whether the specific class is used at all.  If not,
 
4571
         class 0 is used instead.                                     */
 
4572
      /*
 
4573
        if ( !d[b[n]] )
 
4574
            b[n] = 0;
 
4575
      */
 
4576
    }
 
4577
 
 
4578
    FORGET_Frame();
 
4579
 
 
4580
    if ( ACCESS_Frame( 2L ) )
 
4581
      goto Fail4;
 
4582
 
 
4583
    cpcr->InputGlyphCount = GET_UShort();
 
4584
 
 
4585
    if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
 
4586
      ccpf2->MaxInputLength = cpcr->InputGlyphCount;
 
4587
 
 
4588
    FORGET_Frame();
 
4589
 
 
4590
    cpcr->Input = NULL;
 
4591
 
 
4592
    count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
 
4593
 
 
4594
    if ( ALLOC_ARRAY( cpcr->Input, count, FT_UShort ) )
 
4595
      goto Fail4;
 
4596
 
 
4597
    i = cpcr->Input;
 
4598
    d = ccpf2->InputClassDef.Defined;
 
4599
 
 
4600
    if ( ACCESS_Frame( count * 2L ) )
 
4601
      goto Fail3;
 
4602
 
 
4603
    for ( n = 0; n < count; n++ )
 
4604
    {
 
4605
      i[n] = GET_UShort();
 
4606
 
 
4607
      /*
 
4608
        if ( !d[i[n]] )
 
4609
            i[n] = 0;
 
4610
      */
 
4611
    }
 
4612
 
 
4613
    FORGET_Frame();
 
4614
 
 
4615
    if ( ACCESS_Frame( 2L ) )
 
4616
      goto Fail3;
 
4617
 
 
4618
    cpcr->LookaheadGlyphCount = GET_UShort();
 
4619
 
 
4620
    FORGET_Frame();
 
4621
 
 
4622
    if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength )
 
4623
      ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount;
 
4624
 
 
4625
    cpcr->Lookahead = NULL;
 
4626
 
 
4627
    count = cpcr->LookaheadGlyphCount;
 
4628
 
 
4629
    if ( ALLOC_ARRAY( cpcr->Lookahead, count, FT_UShort ) )
 
4630
      goto Fail3;
 
4631
 
 
4632
    l = cpcr->Lookahead;
 
4633
    d = ccpf2->LookaheadClassDef.Defined;
 
4634
 
 
4635
    if ( ACCESS_Frame( count * 2L ) )
 
4636
      goto Fail2;
 
4637
 
 
4638
    for ( n = 0; n < count; n++ )
 
4639
    {
 
4640
      l[n] = GET_UShort();
 
4641
 
 
4642
      /*
 
4643
        if ( !d[l[n]] )
 
4644
            l[n] = 0;
 
4645
      */
 
4646
    }
 
4647
 
 
4648
    FORGET_Frame();
 
4649
 
 
4650
    if ( ACCESS_Frame( 2L ) )
 
4651
      goto Fail2;
 
4652
 
 
4653
    cpcr->PosCount = GET_UShort();
 
4654
 
 
4655
    FORGET_Frame();
 
4656
 
 
4657
    cpcr->PosLookupRecord = NULL;
 
4658
 
 
4659
    count = cpcr->PosCount;
 
4660
 
 
4661
    if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, TTO_PosLookupRecord ) )
 
4662
      goto Fail2;
 
4663
 
 
4664
    plr = cpcr->PosLookupRecord;
 
4665
 
 
4666
    if ( ACCESS_Frame( count * 4L ) )
 
4667
      goto Fail1;
 
4668
 
 
4669
    for ( n = 0; n < count; n++ )
 
4670
    {
 
4671
      plr[n].SequenceIndex   = GET_UShort();
 
4672
      plr[n].LookupListIndex = GET_UShort();
 
4673
    }
 
4674
 
 
4675
    FORGET_Frame();
 
4676
 
 
4677
    return TT_Err_Ok;
 
4678
 
 
4679
  Fail1:
 
4680
    FREE( plr );
 
4681
 
 
4682
  Fail2:
 
4683
    FREE( l );
 
4684
 
 
4685
  Fail3:
 
4686
    FREE( i );
 
4687
 
 
4688
  Fail4:
 
4689
    FREE( b );
 
4690
    return error;
 
4691
  }
 
4692
 
 
4693
 
 
4694
  static void  Free_ChainPosClassRule( TTO_ChainPosClassRule*  cpcr,
 
4695
                                       FT_Memory               memory )
 
4696
  {
 
4697
    FREE( cpcr->PosLookupRecord );
 
4698
    FREE( cpcr->Lookahead );
 
4699
    FREE( cpcr->Input );
 
4700
    FREE( cpcr->Backtrack );
 
4701
  }
 
4702
 
 
4703
 
 
4704
  /* PosClassSet */
 
4705
 
 
4706
  static FT_Error  Load_ChainPosClassSet(
 
4707
                     TTO_ChainContextPosFormat2*  ccpf2,
 
4708
                     TTO_ChainPosClassSet*        cpcs,
 
4709
                     FT_Stream                    stream )
 
4710
  {
 
4711
    FT_Error  error;
 
4712
    FT_Memory memory = stream->memory;
 
4713
 
 
4714
    FT_UShort               n, m, count;
 
4715
    FT_ULong                cur_offset, new_offset, base_offset;
 
4716
 
 
4717
    TTO_ChainPosClassRule*  cpcr;
 
4718
 
 
4719
 
 
4720
    base_offset = FILE_Pos();
 
4721
 
 
4722
    if ( ACCESS_Frame( 2L ) )
 
4723
      return error;
 
4724
 
 
4725
    count = cpcs->ChainPosClassRuleCount = GET_UShort();
 
4726
 
 
4727
    FORGET_Frame();
 
4728
 
 
4729
    cpcs->ChainPosClassRule = NULL;
 
4730
 
 
4731
    if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
 
4732
                      TTO_ChainPosClassRule ) )
 
4733
      return error;
 
4734
 
 
4735
    cpcr = cpcs->ChainPosClassRule;
 
4736
 
 
4737
    for ( n = 0; n < count; n++ )
 
4738
    {
 
4739
      if ( ACCESS_Frame( 2L ) )
 
4740
        goto Fail;
 
4741
 
 
4742
      new_offset = GET_UShort() + base_offset;
 
4743
 
 
4744
      FORGET_Frame();
 
4745
 
 
4746
      cur_offset = FILE_Pos();
 
4747
      if ( FILE_Seek( new_offset ) ||
 
4748
           ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
 
4749
                                             stream ) ) != TT_Err_Ok )
 
4750
        goto Fail;
 
4751
      (void)FILE_Seek( cur_offset );
 
4752
    }
 
4753
 
 
4754
    return TT_Err_Ok;
 
4755
 
 
4756
  Fail:
 
4757
    for ( m = 0; m < n; m++ )
 
4758
      Free_ChainPosClassRule( &cpcr[m], memory );
 
4759
 
 
4760
    FREE( cpcr );
 
4761
    return error;
 
4762
  }
 
4763
 
 
4764
 
 
4765
  static void  Free_ChainPosClassSet( TTO_ChainPosClassSet*  cpcs,
 
4766
                                      FT_Memory              memory )
 
4767
  {
 
4768
    FT_UShort               n, count;
 
4769
 
 
4770
    TTO_ChainPosClassRule*  cpcr;
 
4771
 
 
4772
 
 
4773
    if ( cpcs->ChainPosClassRule )
 
4774
    {
 
4775
      count = cpcs->ChainPosClassRuleCount;
 
4776
      cpcr  = cpcs->ChainPosClassRule;
 
4777
 
 
4778
      for ( n = 0; n < count; n++ )
 
4779
        Free_ChainPosClassRule( &cpcr[n], memory );
 
4780
 
 
4781
      FREE( cpcr );
 
4782
    }
 
4783
  }
 
4784
 
 
4785
 
 
4786
  static FT_Error Load_EmptyOrClassDefinition( TTO_ClassDefinition*  cd,
 
4787
                                               FT_UShort             limit,
 
4788
                                               FT_ULong              class_offset,
 
4789
                                               FT_ULong              base_offset,
 
4790
                                               FT_Stream             stream )
 
4791
  {
 
4792
    FT_Error error;
 
4793
    FT_ULong               cur_offset;
 
4794
 
 
4795
    cur_offset = FILE_Pos();
 
4796
 
 
4797
    if ( class_offset )
 
4798
      {
 
4799
        if ( !FILE_Seek( class_offset + base_offset ) )
 
4800
          error = Load_ClassDefinition( cd, limit, stream );
 
4801
      }
 
4802
    else
 
4803
       error = Load_EmptyClassDefinition ( cd, stream );
 
4804
 
 
4805
    if (error == TT_Err_Ok)
 
4806
      (void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */
 
4807
 
 
4808
    return error;
 
4809
  }
 
4810
 
 
4811
  /* ChainContextPosFormat2 */
 
4812
 
 
4813
  static FT_Error  Load_ChainContextPos2( TTO_ChainContextPosFormat2*  ccpf2,
 
4814
                                          FT_Stream                    stream )
 
4815
  {
 
4816
    FT_Error  error;
 
4817
    FT_Memory memory = stream->memory;
 
4818
 
 
4819
    FT_UShort              n, m, count;
 
4820
    FT_ULong               cur_offset, new_offset, base_offset;
 
4821
    FT_ULong               backtrack_offset, input_offset, lookahead_offset;
 
4822
 
 
4823
    TTO_ChainPosClassSet*  cpcs;
 
4824
 
 
4825
 
 
4826
    base_offset = FILE_Pos() - 2;
 
4827
 
 
4828
    if ( ACCESS_Frame( 2L ) )
 
4829
      return error;
 
4830
 
 
4831
    new_offset = GET_UShort() + base_offset;
 
4832
 
 
4833
    FORGET_Frame();
 
4834
 
 
4835
    cur_offset = FILE_Pos();
 
4836
    if ( FILE_Seek( new_offset ) ||
 
4837
         ( error = Load_Coverage( &ccpf2->Coverage, stream ) ) != TT_Err_Ok )
 
4838
      return error;
 
4839
    (void)FILE_Seek( cur_offset );
 
4840
 
 
4841
    if ( ACCESS_Frame( 8L ) )
 
4842
      goto Fail5;
 
4843
 
 
4844
    backtrack_offset = GET_UShort();
 
4845
    input_offset     = GET_UShort();
 
4846
    lookahead_offset = GET_UShort();
 
4847
 
 
4848
    /* `ChainPosClassSetCount' is the upper limit for input class values,
 
4849
       thus we read it now to make an additional safety check.            */
 
4850
 
 
4851
    count = ccpf2->ChainPosClassSetCount = GET_UShort();
 
4852
 
 
4853
    FORGET_Frame();
 
4854
 
 
4855
    if ( ( error = Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, count,
 
4856
                                                backtrack_offset, base_offset,
 
4857
                                                stream ) ) != TT_Err_Ok )
 
4858
      goto Fail5;
 
4859
    if ( ( error = Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
 
4860
                                                input_offset, base_offset,
 
4861
                                                stream ) ) != TT_Err_Ok )
 
4862
      goto Fail4;
 
4863
    if ( ( error = Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, count,
 
4864
                                                lookahead_offset, base_offset,
 
4865
                                                stream ) ) != TT_Err_Ok )
 
4866
      goto Fail3;
 
4867
 
 
4868
    ccpf2->ChainPosClassSet   = NULL;
 
4869
    ccpf2->MaxBacktrackLength = 0;
 
4870
    ccpf2->MaxInputLength     = 0;
 
4871
    ccpf2->MaxLookaheadLength = 0;
 
4872
 
 
4873
    if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, TTO_ChainPosClassSet ) )
 
4874
      goto Fail2;
 
4875
 
 
4876
    cpcs = ccpf2->ChainPosClassSet;
 
4877
 
 
4878
    for ( n = 0; n < count; n++ )
 
4879
    {
 
4880
      if ( ACCESS_Frame( 2L ) )
 
4881
        goto Fail1;
 
4882
 
 
4883
      new_offset = GET_UShort() + base_offset;
 
4884
 
 
4885
      FORGET_Frame();
 
4886
 
 
4887
      if ( new_offset != base_offset )      /* not a NULL offset */
 
4888
      {
 
4889
        cur_offset = FILE_Pos();
 
4890
        if ( FILE_Seek( new_offset ) ||
 
4891
             ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n],
 
4892
                                              stream ) ) != TT_Err_Ok )
 
4893
          goto Fail1;
 
4894
        (void)FILE_Seek( cur_offset );
 
4895
      }
 
4896
      else
 
4897
      {
 
4898
        /* we create a ChainPosClassSet table with no entries */
 
4899
 
 
4900
        ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
 
4901
        ccpf2->ChainPosClassSet[n].ChainPosClassRule      = NULL;
 
4902
      }
 
4903
    }
 
4904
 
 
4905
    return TT_Err_Ok;
 
4906
 
 
4907
  Fail1:
 
4908
    for ( m = 0; m < n; m++ )
 
4909
      Free_ChainPosClassSet( &cpcs[m], memory );
 
4910
 
 
4911
    FREE( cpcs );
 
4912
 
 
4913
  Fail2:
 
4914
    Free_ClassDefinition( &ccpf2->LookaheadClassDef, memory );
 
4915
 
 
4916
  Fail3:
 
4917
    Free_ClassDefinition( &ccpf2->InputClassDef, memory );
 
4918
 
 
4919
  Fail4:
 
4920
    Free_ClassDefinition( &ccpf2->BacktrackClassDef, memory );
 
4921
 
 
4922
  Fail5:
 
4923
    Free_Coverage( &ccpf2->Coverage, memory );
 
4924
    return error;
 
4925
  }
 
4926
 
 
4927
 
 
4928
  static void  GPos_Free_ChainContext2( TTO_ChainContextPosFormat2*  ccpf2,
 
4929
                                   FT_Memory                    memory )
 
4930
  {
 
4931
    FT_UShort              n, count;
 
4932
 
 
4933
    TTO_ChainPosClassSet*  cpcs;
 
4934
 
 
4935
 
 
4936
    if ( ccpf2->ChainPosClassSet )
 
4937
    {
 
4938
      count = ccpf2->ChainPosClassSetCount;
 
4939
      cpcs  = ccpf2->ChainPosClassSet;
 
4940
 
 
4941
      for ( n = 0; n < count; n++ )
 
4942
        Free_ChainPosClassSet( &cpcs[n], memory );
 
4943
 
 
4944
      FREE( cpcs );
 
4945
    }
 
4946
 
 
4947
    Free_ClassDefinition( &ccpf2->LookaheadClassDef, memory );
 
4948
    Free_ClassDefinition( &ccpf2->InputClassDef, memory );
 
4949
    Free_ClassDefinition( &ccpf2->BacktrackClassDef, memory );
 
4950
 
 
4951
    Free_Coverage( &ccpf2->Coverage, memory );
 
4952
  }
 
4953
 
 
4954
 
 
4955
  /* ChainContextPosFormat3 */
 
4956
 
 
4957
  static FT_Error  Load_ChainContextPos3( TTO_ChainContextPosFormat3*  ccpf3,
 
4958
                                          FT_Stream                    stream )
 
4959
  {
 
4960
    FT_Error  error;
 
4961
    FT_Memory memory = stream->memory;
 
4962
 
 
4963
    FT_UShort             n, nb, ni, nl, m, count;
 
4964
    FT_UShort             backtrack_count, input_count, lookahead_count;
 
4965
    FT_ULong              cur_offset, new_offset, base_offset;
 
4966
 
 
4967
    TTO_Coverage*         b;
 
4968
    TTO_Coverage*         i;
 
4969
    TTO_Coverage*         l;
 
4970
    TTO_PosLookupRecord*  plr;
 
4971
 
 
4972
 
 
4973
    base_offset = FILE_Pos() - 2L;
 
4974
 
 
4975
    if ( ACCESS_Frame( 2L ) )
 
4976
      return error;
 
4977
 
 
4978
    ccpf3->BacktrackGlyphCount = GET_UShort();
 
4979
 
 
4980
    FORGET_Frame();
 
4981
 
 
4982
    ccpf3->BacktrackCoverage = NULL;
 
4983
 
 
4984
    backtrack_count = ccpf3->BacktrackGlyphCount;
 
4985
 
 
4986
    if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
 
4987
                      TTO_Coverage ) )
 
4988
      return error;
 
4989
 
 
4990
    b = ccpf3->BacktrackCoverage;
 
4991
 
 
4992
    for ( nb = 0; nb < backtrack_count; nb++ )
 
4993
    {
 
4994
      if ( ACCESS_Frame( 2L ) )
 
4995
        goto Fail4;
 
4996
 
 
4997
      new_offset = GET_UShort() + base_offset;
 
4998
 
 
4999
      FORGET_Frame();
 
5000
 
 
5001
      cur_offset = FILE_Pos();
 
5002
      if ( FILE_Seek( new_offset ) ||
 
5003
           ( error = Load_Coverage( &b[nb], stream ) ) != TT_Err_Ok )
 
5004
        goto Fail4;
 
5005
      (void)FILE_Seek( cur_offset );
 
5006
    }
 
5007
 
 
5008
    if ( ACCESS_Frame( 2L ) )
 
5009
      goto Fail4;
 
5010
 
 
5011
    ccpf3->InputGlyphCount = GET_UShort();
 
5012
 
 
5013
    FORGET_Frame();
 
5014
 
 
5015
    ccpf3->InputCoverage = NULL;
 
5016
 
 
5017
    input_count = ccpf3->InputGlyphCount;
 
5018
 
 
5019
    if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, TTO_Coverage ) )
 
5020
      goto Fail4;
 
5021
 
 
5022
    i = ccpf3->InputCoverage;
 
5023
 
 
5024
    for ( ni = 0; ni < input_count; ni++ )
 
5025
    {
 
5026
      if ( ACCESS_Frame( 2L ) )
 
5027
        goto Fail3;
 
5028
 
 
5029
      new_offset = GET_UShort() + base_offset;
 
5030
 
 
5031
      FORGET_Frame();
 
5032
 
 
5033
      cur_offset = FILE_Pos();
 
5034
      if ( FILE_Seek( new_offset ) ||
 
5035
           ( error = Load_Coverage( &i[ni], stream ) ) != TT_Err_Ok )
 
5036
        goto Fail3;
 
5037
      (void)FILE_Seek( cur_offset );
 
5038
    }
 
5039
 
 
5040
    if ( ACCESS_Frame( 2L ) )
 
5041
      goto Fail3;
 
5042
 
 
5043
    ccpf3->LookaheadGlyphCount = GET_UShort();
 
5044
 
 
5045
    FORGET_Frame();
 
5046
 
 
5047
    ccpf3->LookaheadCoverage = NULL;
 
5048
 
 
5049
    lookahead_count = ccpf3->LookaheadGlyphCount;
 
5050
 
 
5051
    if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
 
5052
                      TTO_Coverage ) )
 
5053
      goto Fail3;
 
5054
 
 
5055
    l = ccpf3->LookaheadCoverage;
 
5056
 
 
5057
    for ( nl = 0; nl < lookahead_count; nl++ )
 
5058
    {
 
5059
      if ( ACCESS_Frame( 2L ) )
 
5060
        goto Fail2;
 
5061
 
 
5062
      new_offset = GET_UShort() + base_offset;
 
5063
 
 
5064
      FORGET_Frame();
 
5065
 
 
5066
      cur_offset = FILE_Pos();
 
5067
      if ( FILE_Seek( new_offset ) ||
 
5068
           ( error = Load_Coverage( &l[nl], stream ) ) != TT_Err_Ok )
 
5069
        goto Fail2;
 
5070
      (void)FILE_Seek( cur_offset );
 
5071
    }
 
5072
 
 
5073
    if ( ACCESS_Frame( 2L ) )
 
5074
      goto Fail2;
 
5075
 
 
5076
    ccpf3->PosCount = GET_UShort();
 
5077
 
 
5078
    FORGET_Frame();
 
5079
 
 
5080
    ccpf3->PosLookupRecord = NULL;
 
5081
 
 
5082
    count = ccpf3->PosCount;
 
5083
 
 
5084
    if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, TTO_PosLookupRecord ) )
 
5085
      goto Fail2;
 
5086
 
 
5087
    plr = ccpf3->PosLookupRecord;
 
5088
 
 
5089
    if ( ACCESS_Frame( count * 4L ) )
 
5090
      goto Fail1;
 
5091
 
 
5092
    for ( n = 0; n < count; n++ )
 
5093
    {
 
5094
      plr[n].SequenceIndex   = GET_UShort();
 
5095
      plr[n].LookupListIndex = GET_UShort();
 
5096
    }
 
5097
 
 
5098
    FORGET_Frame();
 
5099
 
 
5100
    return TT_Err_Ok;
 
5101
 
 
5102
  Fail1:
 
5103
    FREE( plr );
 
5104
 
 
5105
  Fail2:
 
5106
    for ( m = 0; m < nl; nl++ )
 
5107
      Free_Coverage( &l[m], memory );
 
5108
 
 
5109
    FREE( l );
 
5110
 
 
5111
  Fail3:
 
5112
    for ( m = 0; m < ni; n++ )
 
5113
      Free_Coverage( &i[m], memory );
 
5114
 
 
5115
    FREE( i );
 
5116
 
 
5117
  Fail4:
 
5118
    for ( m = 0; m < nb; n++ )
 
5119
      Free_Coverage( &b[m], memory );
 
5120
 
 
5121
    FREE( b );
 
5122
    return error;
 
5123
  }
 
5124
 
 
5125
 
 
5126
  static void  GPos_Free_ChainContext3( TTO_ChainContextPosFormat3*  ccpf3,
 
5127
                                   FT_Memory                    memory )
 
5128
  {
 
5129
    FT_UShort      n, count;
 
5130
 
 
5131
    TTO_Coverage*  c;
 
5132
 
 
5133
 
 
5134
    FREE( ccpf3->PosLookupRecord );
 
5135
 
 
5136
    if ( ccpf3->LookaheadCoverage )
 
5137
    {
 
5138
      count = ccpf3->LookaheadGlyphCount;
 
5139
      c     = ccpf3->LookaheadCoverage;
 
5140
 
 
5141
      for ( n = 0; n < count; n++ )
 
5142
        Free_Coverage( &c[n], memory );
 
5143
 
 
5144
      FREE( c );
 
5145
    }
 
5146
 
 
5147
    if ( ccpf3->InputCoverage )
 
5148
    {
 
5149
      count = ccpf3->InputGlyphCount;
 
5150
      c     = ccpf3->InputCoverage;
 
5151
 
 
5152
      for ( n = 0; n < count; n++ )
 
5153
        Free_Coverage( &c[n], memory );
 
5154
 
 
5155
      FREE( c );
 
5156
    }
 
5157
 
 
5158
    if ( ccpf3->BacktrackCoverage )
 
5159
    {
 
5160
      count = ccpf3->BacktrackGlyphCount;
 
5161
      c     = ccpf3->BacktrackCoverage;
 
5162
 
 
5163
      for ( n = 0; n < count; n++ )
 
5164
        Free_Coverage( &c[n], memory );
 
5165
 
 
5166
      FREE( c );
 
5167
    }
 
5168
  }
 
5169
 
 
5170
 
 
5171
  /* ChainContextPos */
 
5172
 
 
5173
  FT_Error  Load_ChainContextPos( TTO_ChainContextPos*  ccp,
 
5174
                                  FT_Stream             stream )
 
5175
  {
 
5176
    FT_Error  error;
 
5177
 
 
5178
 
 
5179
    if ( ACCESS_Frame( 2L ) )
 
5180
      return error;
 
5181
 
 
5182
    ccp->PosFormat = GET_UShort();
 
5183
 
 
5184
    FORGET_Frame();
 
5185
 
 
5186
    switch ( ccp->PosFormat )
 
5187
    {
 
5188
    case 1:
 
5189
      return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream );
 
5190
 
 
5191
    case 2:
 
5192
      return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream );
 
5193
 
 
5194
    case 3:
 
5195
      return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream );
 
5196
 
 
5197
    default:
 
5198
      return TTO_Err_Invalid_GPOS_SubTable_Format;
 
5199
    }
 
5200
 
 
5201
    return TT_Err_Ok;               /* never reached */
 
5202
  }
 
5203
 
 
5204
 
 
5205
  void  Free_ChainContextPos( TTO_ChainContextPos*  ccp,
 
5206
                              FT_Memory             memory )
 
5207
  {
 
5208
    switch ( ccp->PosFormat )
 
5209
    {
 
5210
    case 1:
 
5211
      GPos_Free_ChainContext1( &ccp->ccpf.ccpf1, memory );
 
5212
      break;
 
5213
 
 
5214
    case 2:
 
5215
      GPos_Free_ChainContext2( &ccp->ccpf.ccpf2, memory );
 
5216
      break;
 
5217
 
 
5218
    case 3:
 
5219
      GPos_Free_ChainContext3( &ccp->ccpf.ccpf3, memory );
 
5220
      break;
 
5221
    }
 
5222
  }
 
5223
 
 
5224
 
 
5225
  static FT_Error  Lookup_ChainContextPos1(
 
5226
                     GPOS_Instance*               gpi,
 
5227
                     TTO_ChainContextPosFormat1*  ccpf1,
 
5228
                     TTO_GSUB_String*             in,
 
5229
                     TTO_GPOS_Data*               out,
 
5230
                     FT_UShort                    flags,
 
5231
                     FT_UShort                    context_length,
 
5232
                     int                          nesting_level )
 
5233
  {
 
5234
    FT_UShort          index, property;
 
5235
    FT_UShort          i, j, k, num_cpr, curr_pos;
 
5236
    FT_UShort          bgc, igc, lgc;
 
5237
    FT_Error           error;
 
5238
    FT_UShort*         s_in;
 
5239
    TTO_GPOSHeader*    gpos = gpi->gpos;
 
5240
 
 
5241
    TTO_ChainPosRule*  cpr;
 
5242
    TTO_ChainPosRule   curr_cpr;
 
5243
    TTO_GDEFHeader*    gdef;
 
5244
 
 
5245
 
 
5246
    error = Coverage_Index( &ccpf1->Coverage, in->string[in->pos], &index );
 
5247
    if ( error )
 
5248
      return error;
 
5249
 
 
5250
    gdef = gpos->gdef;
 
5251
 
 
5252
    if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
 
5253
      return error;
 
5254
 
 
5255
    cpr     = ccpf1->ChainPosRuleSet[index].ChainPosRule;
 
5256
    num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount;
 
5257
 
 
5258
    for ( k = 0; k < num_cpr; k++ )
 
5259
    {
 
5260
      curr_cpr = cpr[k];
 
5261
      bgc      = curr_cpr.BacktrackGlyphCount;
 
5262
      igc      = curr_cpr.InputGlyphCount;
 
5263
      lgc      = curr_cpr.LookaheadGlyphCount;
 
5264
 
 
5265
      if ( context_length != 0xFFFF && context_length < igc )
 
5266
        continue;
 
5267
 
 
5268
      /* check whether context is too long; it is a first guess only */
 
5269
 
 
5270
      if ( bgc > in->pos || in->pos + igc + lgc > in->length )
 
5271
        continue;
 
5272
 
 
5273
      if ( bgc )
 
5274
      {
 
5275
        /* Since we don't know in advance the number of glyphs to inspect,
 
5276
           we search backwards for matches in the backtrack glyph array    */
 
5277
 
 
5278
        curr_pos = 0;
 
5279
        s_in     = &in->string[curr_pos];
 
5280
 
 
5281
        for ( i = 0, j = in->pos - 1; i < bgc; i++, j-- )
 
5282
        {
 
5283
          while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
 
5284
          {
 
5285
            if ( error && error != TTO_Err_Not_Covered )
 
5286
              return error;
 
5287
 
 
5288
            if ( j > curr_pos )
 
5289
              j--;
 
5290
            else
 
5291
              break;
 
5292
          }
 
5293
 
 
5294
          /* In OpenType 1.3, it is undefined whether the offsets of
 
5295
             backtrack glyphs is in logical order or not.  Version 1.4
 
5296
             will clarify this:
 
5297
 
 
5298
               Logical order -      a  b  c  d  e  f  g  h  i  j
 
5299
                                                i
 
5300
               Input offsets -                  0  1
 
5301
               Backtrack offsets -  3  2  1  0
 
5302
               Lookahead offsets -                    0  1  2  3           */
 
5303
 
 
5304
          if ( s_in[j] != curr_cpr.Backtrack[i] )
 
5305
            break;
 
5306
        }
 
5307
 
 
5308
        if ( i != bgc )
 
5309
          continue;
 
5310
      }
 
5311
 
 
5312
      curr_pos = in->pos;
 
5313
      s_in     = &in->string[curr_pos];
 
5314
 
 
5315
      /* Start at 1 because [0] is implied */
 
5316
 
 
5317
      for ( i = 1, j = 1; i < igc; i++, j++ )
 
5318
      {
 
5319
        while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
 
5320
        {
 
5321
          if ( error && error != TTO_Err_Not_Covered )
 
5322
            return error;
 
5323
 
 
5324
          if ( curr_pos + j < (int)in->length )
 
5325
            j++;
 
5326
          else
 
5327
            break;
 
5328
        }
 
5329
 
 
5330
        if ( s_in[j] != curr_cpr.Input[i - 1] )
 
5331
          break;
 
5332
      }
 
5333
 
 
5334
      if ( i != igc )
 
5335
        continue;
 
5336
 
 
5337
      /* we are starting to check for lookahead glyphs right after the
 
5338
         last context glyph                                            */
 
5339
 
 
5340
      curr_pos += j;
 
5341
      s_in     = &in->string[curr_pos];
 
5342
 
 
5343
      for ( i = 0, j = 0; i < lgc; i++, j++ )
 
5344
      {
 
5345
        while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
 
5346
        {
 
5347
          if ( error && error != TTO_Err_Not_Covered )
 
5348
            return error;
 
5349
 
 
5350
          if ( curr_pos + j < (int)in->length )
 
5351
            j++;
 
5352
          else
 
5353
            break;
 
5354
        }
 
5355
 
 
5356
        if ( s_in[j] != curr_cpr.Lookahead[i] )
 
5357
          break;
 
5358
      }
 
5359
 
 
5360
      if ( i == lgc )
 
5361
        return Do_ContextPos( gpi, igc,
 
5362
                              curr_cpr.PosCount,
 
5363
                              curr_cpr.PosLookupRecord,
 
5364
                              in, out,
 
5365
                              nesting_level );
 
5366
    }
 
5367
 
 
5368
    return TTO_Err_Not_Covered;
 
5369
  }
 
5370
 
 
5371
 
 
5372
  static FT_Error  Lookup_ChainContextPos2(
 
5373
                     GPOS_Instance*               gpi,
 
5374
                     TTO_ChainContextPosFormat2*  ccpf2,
 
5375
                     TTO_GSUB_String*             in,
 
5376
                     TTO_GPOS_Data*               out,
 
5377
                     FT_UShort                    flags,
 
5378
                     FT_UShort                    context_length,
 
5379
                     int                          nesting_level )
 
5380
  {
 
5381
    FT_UShort              index, property;
 
5382
    FT_Memory              memory = gpi->face->memory;
 
5383
    FT_Error               error;
 
5384
    FT_UShort              i, j, k, curr_pos;
 
5385
    FT_UShort              bgc, igc, lgc;
 
5386
    FT_UShort              known_backtrack_classes,
 
5387
                           known_input_classes,
 
5388
                           known_lookahead_classes;
 
5389
 
 
5390
    FT_UShort*             backtrack_classes;
 
5391
    FT_UShort*             input_classes;
 
5392
    FT_UShort*             lookahead_classes;
 
5393
 
 
5394
    FT_UShort*             s_in;
 
5395
 
 
5396
    FT_UShort*             bc;
 
5397
    FT_UShort*             ic;
 
5398
    FT_UShort*             lc;
 
5399
    TTO_GPOSHeader*        gpos = gpi->gpos;
 
5400
 
 
5401
    TTO_ChainPosClassSet*  cpcs;
 
5402
    TTO_ChainPosClassRule  cpcr;
 
5403
    TTO_GDEFHeader*        gdef;
 
5404
 
 
5405
 
 
5406
    gdef = gpos->gdef;
 
5407
 
 
5408
    /* Note: The coverage table in format 2 doesn't give an index into
 
5409
             anything.  It just lets us know whether or not we need to
 
5410
             do any lookup at all.                                     */
 
5411
 
 
5412
    error = Coverage_Index( &ccpf2->Coverage, in->string[in->pos], &index );
 
5413
    if ( error )
 
5414
      return error;
 
5415
 
 
5416
    if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
 
5417
      return error;
 
5418
 
 
5419
    if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, FT_UShort ) )
 
5420
      return error;
 
5421
    known_backtrack_classes = 0;
 
5422
 
 
5423
    if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, FT_UShort ) )
 
5424
      goto End3;
 
5425
    known_input_classes = 1;
 
5426
 
 
5427
    if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, FT_UShort ) )
 
5428
      goto End2;
 
5429
    known_lookahead_classes = 0;
 
5430
 
 
5431
    error = Get_Class( &ccpf2->InputClassDef, in->string[in->pos],
 
5432
                       &input_classes[0], NULL );
 
5433
    if ( error && error != TTO_Err_Not_Covered )
 
5434
      goto End1;
 
5435
 
 
5436
    cpcs = &ccpf2->ChainPosClassSet[input_classes[0]];
 
5437
    if ( !cpcs )
 
5438
    {
 
5439
      error = TTO_Err_Invalid_GPOS_SubTable;
 
5440
      goto End1;
 
5441
    }
 
5442
 
 
5443
    for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ )
 
5444
    {
 
5445
      cpcr = cpcs->ChainPosClassRule[k];
 
5446
      bgc  = cpcr.BacktrackGlyphCount;
 
5447
      igc  = cpcr.InputGlyphCount;
 
5448
      lgc  = cpcr.LookaheadGlyphCount;
 
5449
 
 
5450
      if ( context_length != 0xFFFF && context_length < igc )
 
5451
        continue;
 
5452
 
 
5453
      /* check whether context is too long; it is a first guess only */
 
5454
 
 
5455
      if ( bgc > in->pos || in->pos + igc + lgc > in->length )
 
5456
        continue;
 
5457
 
 
5458
      if ( bgc )
 
5459
      {
 
5460
        /* Since we don't know in advance the number of glyphs to inspect,
 
5461
           we search backwards for matches in the backtrack glyph array.
 
5462
           Note that `known_backtrack_classes' starts at index 0.         */
 
5463
 
 
5464
        curr_pos = 0;
 
5465
        s_in     = &in->string[curr_pos];
 
5466
        bc       = cpcr.Backtrack;
 
5467
 
 
5468
        for ( i = 0, j = in->pos - 1; i < bgc; i++, j-- )
 
5469
        {
 
5470
          while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
 
5471
          {
 
5472
            if ( error && error != TTO_Err_Not_Covered )
 
5473
              goto End1;
 
5474
 
 
5475
            if ( j > curr_pos )
 
5476
              j--;
 
5477
            else
 
5478
              break;
 
5479
          }
 
5480
 
 
5481
          if ( i >= known_backtrack_classes )
 
5482
          {
 
5483
            /* Keeps us from having to do this for each rule */
 
5484
 
 
5485
            error = Get_Class( &ccpf2->BacktrackClassDef, s_in[j],
 
5486
                               &backtrack_classes[i], NULL );
 
5487
            if ( error && error != TTO_Err_Not_Covered )
 
5488
              goto End1;
 
5489
            known_backtrack_classes = i;
 
5490
          }
 
5491
 
 
5492
          if ( bc[i] != backtrack_classes[i] )
 
5493
            break;
 
5494
        }
 
5495
 
 
5496
        if ( i != bgc )
 
5497
          continue;
 
5498
      }
 
5499
 
 
5500
      curr_pos = in->pos;
 
5501
      s_in     = &in->string[curr_pos];
 
5502
      ic       = cpcr.Input;
 
5503
 
 
5504
      /* Start at 1 because [0] is implied */
 
5505
 
 
5506
      for ( i = 1, j = 1; i < igc; i++, j++ )
 
5507
      {
 
5508
        while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
 
5509
        {
 
5510
          if ( error && error != TTO_Err_Not_Covered )
 
5511
            goto End1;
 
5512
 
 
5513
          if ( curr_pos + j < (int)in->length )
 
5514
            j++;
 
5515
          else
 
5516
            break;
 
5517
        }
 
5518
 
 
5519
        if ( i >= known_input_classes )
 
5520
        {
 
5521
          error = Get_Class( &ccpf2->InputClassDef, s_in[j],
 
5522
                             &input_classes[i], NULL );
 
5523
          if ( error && error != TTO_Err_Not_Covered )
 
5524
            goto End1;
 
5525
          known_input_classes = i;
 
5526
        }
 
5527
 
 
5528
        if ( ic[i - 1] != input_classes[i] )
 
5529
          break;
 
5530
      }
 
5531
 
 
5532
      if ( i != igc )
 
5533
        continue;
 
5534
 
 
5535
      /* we are starting to check for lookahead glyphs right after the
 
5536
         last context glyph                                            */
 
5537
 
 
5538
      curr_pos += j;
 
5539
      s_in     = &in->string[curr_pos];
 
5540
      lc       = cpcr.Lookahead;
 
5541
 
 
5542
      for ( i = 0, j = 0; i < lgc; i++, j++ )
 
5543
      {
 
5544
        while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
 
5545
        {
 
5546
          if ( error && error != TTO_Err_Not_Covered )
 
5547
            goto End1;
 
5548
 
 
5549
          if ( curr_pos + j < (int)in->length )
 
5550
            j++;
 
5551
          else
 
5552
            break;
 
5553
        }
 
5554
 
 
5555
        if ( i >= known_lookahead_classes )
 
5556
        {
 
5557
          error = Get_Class( &ccpf2->LookaheadClassDef, s_in[j],
 
5558
                             &lookahead_classes[i], NULL );
 
5559
          if ( error && error != TTO_Err_Not_Covered )
 
5560
            goto End1;
 
5561
          known_lookahead_classes = i;
 
5562
        }
 
5563
 
 
5564
        if ( lc[i] != lookahead_classes[i] )
 
5565
          break;
 
5566
      }
 
5567
 
 
5568
      if ( i == lgc )
 
5569
      {
 
5570
        error = Do_ContextPos( gpi, igc,
 
5571
                               cpcr.PosCount,
 
5572
                               cpcr.PosLookupRecord,
 
5573
                               in, out,
 
5574
                               nesting_level );
 
5575
        goto End1;
 
5576
      }
 
5577
    }
 
5578
 
 
5579
    error = TTO_Err_Not_Covered;
 
5580
 
 
5581
  End1:
 
5582
    FREE( lookahead_classes );
 
5583
 
 
5584
  End2:
 
5585
    FREE( input_classes );
 
5586
 
 
5587
  End3:
 
5588
    FREE( backtrack_classes );
 
5589
    return error;
 
5590
  }
 
5591
 
 
5592
 
 
5593
  static FT_Error  Lookup_ChainContextPos3(
 
5594
                     GPOS_Instance*               gpi,
 
5595
                     TTO_ChainContextPosFormat3*  ccpf3,
 
5596
                     TTO_GSUB_String*             in,
 
5597
                     TTO_GPOS_Data*               out,
 
5598
                     FT_UShort                    flags,
 
5599
                     FT_UShort                    context_length,
 
5600
                     int                          nesting_level )
 
5601
  {
 
5602
    FT_UShort        index, i, j, curr_pos, property;
 
5603
    FT_UShort        bgc, igc, lgc;
 
5604
    FT_Error         error;
 
5605
    FT_UShort*       s_in;
 
5606
    TTO_GPOSHeader*  gpos = gpi->gpos;
 
5607
 
 
5608
    TTO_Coverage*    bc;
 
5609
    TTO_Coverage*    ic;
 
5610
    TTO_Coverage*    lc;
 
5611
    TTO_GDEFHeader*  gdef;
 
5612
 
 
5613
 
 
5614
    bgc = ccpf3->BacktrackGlyphCount;
 
5615
    igc = ccpf3->InputGlyphCount;
 
5616
    lgc = ccpf3->LookaheadGlyphCount;
 
5617
 
 
5618
    if ( context_length != 0xFFFF && context_length < igc )
 
5619
      return TTO_Err_Not_Covered;
 
5620
 
 
5621
    /* check whether context is too long; it is a first guess only */
 
5622
 
 
5623
    if ( bgc > in->pos || in->pos + igc + lgc > in->length )
 
5624
      return TTO_Err_Not_Covered;
 
5625
 
 
5626
    gdef = gpos->gdef;
 
5627
 
 
5628
    if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
 
5629
      return error;
 
5630
 
 
5631
    if ( bgc )
 
5632
    {
 
5633
      /* Since we don't know in advance the number of glyphs to inspect,
 
5634
         we search backwards for matches in the backtrack glyph array    */
 
5635
 
 
5636
      curr_pos = 0;
 
5637
      s_in     = &in->string[curr_pos];
 
5638
      bc       = ccpf3->BacktrackCoverage;
 
5639
 
 
5640
      for ( i = 0, j = in->pos - 1; i < bgc; i++, j-- )
 
5641
      {
 
5642
        while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
 
5643
        {
 
5644
          if ( error && error != TTO_Err_Not_Covered )
 
5645
            return error;
 
5646
 
 
5647
          if ( j > curr_pos )
 
5648
            j--;
 
5649
          else
 
5650
            return TTO_Err_Not_Covered;
 
5651
        }
 
5652
 
 
5653
        error = Coverage_Index( &bc[i], s_in[j], &index );
 
5654
        if ( error )
 
5655
          return error;
 
5656
      }
 
5657
    }
 
5658
 
 
5659
    curr_pos = in->pos;
 
5660
    s_in     = &in->string[curr_pos];
 
5661
    ic       = ccpf3->InputCoverage;
 
5662
 
 
5663
    for ( i = 0, j = 0; i < igc; i++, j++ )
 
5664
    {
 
5665
      /* We already called CHECK_Property for s_in[0] */
 
5666
      while ( j > 0 && CHECK_Property( gdef, s_in[j], flags, &property ) )
 
5667
      {
 
5668
        if ( error && error != TTO_Err_Not_Covered )
 
5669
          return error;
 
5670
 
 
5671
        if ( curr_pos + j < (int)in->length )
 
5672
          j++;
 
5673
        else
 
5674
          return TTO_Err_Not_Covered;
 
5675
      }
 
5676
 
 
5677
      error = Coverage_Index( &ic[i], s_in[j], &index );
 
5678
      if ( error )
 
5679
        return error;
 
5680
    }
 
5681
 
 
5682
    /* we are starting to check for lookahead glyphs right after the
 
5683
       last context glyph                                            */
 
5684
 
 
5685
    curr_pos += j;
 
5686
    s_in     = &in->string[curr_pos];
 
5687
    lc       = ccpf3->LookaheadCoverage;
 
5688
 
 
5689
    for ( i = 0, j = 0; i < lgc; i++, j++ )
 
5690
    {
 
5691
      while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
 
5692
      {
 
5693
        if ( error && error != TTO_Err_Not_Covered )
 
5694
          return error;
 
5695
 
 
5696
        if ( curr_pos + j < (int)in->length )
 
5697
          j++;
 
5698
        else
 
5699
          return TTO_Err_Not_Covered;
 
5700
      }
 
5701
 
 
5702
      error = Coverage_Index( &lc[i], s_in[j], &index );
 
5703
      if ( error )
 
5704
        return error;
 
5705
    }
 
5706
 
 
5707
    return Do_ContextPos( gpi, igc,
 
5708
                          ccpf3->PosCount,
 
5709
                          ccpf3->PosLookupRecord,
 
5710
                          in, out,
 
5711
                          nesting_level );
 
5712
  }
 
5713
 
 
5714
 
 
5715
  static FT_Error  Lookup_ChainContextPos(
 
5716
                     GPOS_Instance*        gpi,
 
5717
                     TTO_ChainContextPos*  ccp,
 
5718
                     TTO_GSUB_String*      in,
 
5719
                     TTO_GPOS_Data*        out,
 
5720
                     FT_UShort             flags,
 
5721
                     FT_UShort             context_length,
 
5722
                     int                   nesting_level )
 
5723
  {
 
5724
    switch ( ccp->PosFormat )
 
5725
    {
 
5726
    case 1:
 
5727
      return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, in, out,
 
5728
                                      flags, context_length,
 
5729
                                      nesting_level );
 
5730
 
 
5731
    case 2:
 
5732
      return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, in, out,
 
5733
                                      flags, context_length,
 
5734
                                      nesting_level );
 
5735
 
 
5736
    case 3:
 
5737
      return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, in, out,
 
5738
                                      flags, context_length,
 
5739
                                      nesting_level );
 
5740
 
 
5741
    default:
 
5742
      return TTO_Err_Invalid_GPOS_SubTable_Format;
 
5743
    }
 
5744
 
 
5745
    return TT_Err_Ok;               /* never reached */
 
5746
  }
 
5747
 
 
5748
 
 
5749
 
 
5750
  /***********
 
5751
   * GPOS API
 
5752
   ***********/
 
5753
 
 
5754
 
 
5755
  EXPORT_FUNC
 
5756
  FT_Error  TT_GPOS_Select_Script( TTO_GPOSHeader*  gpos,
 
5757
                                   FT_ULong         script_tag,
 
5758
                                   FT_UShort*       script_index )
 
5759
  {
 
5760
    FT_UShort          n;
 
5761
 
 
5762
    TTO_ScriptList*    sl;
 
5763
    TTO_ScriptRecord*  sr;
 
5764
 
 
5765
 
 
5766
    if ( !gpos || !script_index )
 
5767
      return TT_Err_Invalid_Argument;
 
5768
 
 
5769
    sl = &gpos->ScriptList;
 
5770
    sr = sl->ScriptRecord;
 
5771
 
 
5772
    for ( n = 0; n < sl->ScriptCount; n++ )
 
5773
      if ( script_tag == sr[n].ScriptTag )
 
5774
      {
 
5775
        *script_index = n;
 
5776
 
 
5777
        return TT_Err_Ok;
 
5778
      }
 
5779
 
 
5780
    return TTO_Err_Not_Covered;
 
5781
  }
 
5782
 
 
5783
 
 
5784
  EXPORT_FUNC
 
5785
  FT_Error  TT_GPOS_Select_Language( TTO_GPOSHeader*  gpos,
 
5786
                                     FT_ULong         language_tag,
 
5787
                                     FT_UShort        script_index,
 
5788
                                     FT_UShort*       language_index,
 
5789
                                     FT_UShort*       req_feature_index )
 
5790
  {
 
5791
    FT_UShort           n;
 
5792
 
 
5793
    TTO_ScriptList*     sl;
 
5794
    TTO_ScriptRecord*   sr;
 
5795
    TTO_Script*         s;
 
5796
    TTO_LangSysRecord*  lsr;
 
5797
 
 
5798
 
 
5799
    if ( !gpos || !language_index || !req_feature_index )
 
5800
      return TT_Err_Invalid_Argument;
 
5801
 
 
5802
    sl = &gpos->ScriptList;
 
5803
    sr = sl->ScriptRecord;
 
5804
 
 
5805
    if ( script_index >= sl->ScriptCount )
 
5806
      return TT_Err_Invalid_Argument;
 
5807
 
 
5808
    s   = &sr[script_index].Script;
 
5809
    lsr = s->LangSysRecord;
 
5810
 
 
5811
    for ( n = 0; n < s->LangSysCount; n++ )
 
5812
      if ( language_tag == lsr[n].LangSysTag )
 
5813
      {
 
5814
        *language_index = n;
 
5815
        *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
 
5816
 
 
5817
        return TT_Err_Ok;
 
5818
      }
 
5819
 
 
5820
    return TTO_Err_Not_Covered;
 
5821
  }
 
5822
 
 
5823
 
 
5824
  /* selecting 0xFFFF for language_index asks for the values of the
 
5825
     default language (DefaultLangSys)                              */
 
5826
 
 
5827
  EXPORT_FUNC
 
5828
  FT_Error  TT_GPOS_Select_Feature( TTO_GPOSHeader*  gpos,
 
5829
                                    FT_ULong         feature_tag,
 
5830
                                    FT_UShort        script_index,
 
5831
                                    FT_UShort        language_index,
 
5832
                                    FT_UShort*       feature_index )
 
5833
  {
 
5834
    FT_UShort           n;
 
5835
 
 
5836
    TTO_ScriptList*     sl;
 
5837
    TTO_ScriptRecord*   sr;
 
5838
    TTO_Script*         s;
 
5839
    TTO_LangSysRecord*  lsr;
 
5840
    TTO_LangSys*        ls;
 
5841
    FT_UShort*          fi;
 
5842
 
 
5843
    TTO_FeatureList*    fl;
 
5844
    TTO_FeatureRecord*  fr;
 
5845
 
 
5846
 
 
5847
    if ( !gpos || !feature_index )
 
5848
      return TT_Err_Invalid_Argument;
 
5849
 
 
5850
    sl = &gpos->ScriptList;
 
5851
    sr = sl->ScriptRecord;
 
5852
 
 
5853
    fl = &gpos->FeatureList;
 
5854
    fr = fl->FeatureRecord;
 
5855
 
 
5856
    if ( script_index >= sl->ScriptCount )
 
5857
      return TT_Err_Invalid_Argument;
 
5858
 
 
5859
    s   = &sr[script_index].Script;
 
5860
    lsr = s->LangSysRecord;
 
5861
 
 
5862
    if ( language_index == 0xFFFF )
 
5863
      ls = &s->DefaultLangSys;
 
5864
    else
 
5865
    {
 
5866
      if ( language_index >= s->LangSysCount )
 
5867
        return TT_Err_Invalid_Argument;
 
5868
 
 
5869
      ls = &lsr[language_index].LangSys;
 
5870
    }
 
5871
 
 
5872
    fi = ls->FeatureIndex;
 
5873
 
 
5874
    for ( n = 0; n < ls->FeatureCount; n++ )
 
5875
    {
 
5876
      if ( fi[n] >= fl->FeatureCount )
 
5877
        return TTO_Err_Invalid_GPOS_SubTable_Format;
 
5878
 
 
5879
      if ( feature_tag == fr[fi[n]].FeatureTag )
 
5880
      {
 
5881
        *feature_index = fi[n];
 
5882
 
 
5883
        return TT_Err_Ok;
 
5884
      }
 
5885
    }
 
5886
 
 
5887
    return TTO_Err_Not_Covered;
 
5888
  }
 
5889
 
 
5890
 
 
5891
  /* The next three functions return a null-terminated list */
 
5892
 
 
5893
  EXPORT_FUNC
 
5894
  FT_Error  TT_GPOS_Query_Scripts( TTO_GPOSHeader*  gpos,
 
5895
                                   FT_ULong**       script_tag_list )
 
5896
  {
 
5897
    FT_Error           error;
 
5898
    FT_Memory          memory = gpos->memory;
 
5899
    FT_UShort          n;
 
5900
    FT_ULong*          stl;
 
5901
 
 
5902
    TTO_ScriptList*    sl;
 
5903
    TTO_ScriptRecord*  sr;
 
5904
 
 
5905
 
 
5906
    if ( !gpos || !script_tag_list )
 
5907
      return TT_Err_Invalid_Argument;
 
5908
 
 
5909
    sl = &gpos->ScriptList;
 
5910
    sr = sl->ScriptRecord;
 
5911
 
 
5912
    if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, FT_ULong ) )
 
5913
      return error;
 
5914
 
 
5915
    for ( n = 0; n < sl->ScriptCount; n++ )
 
5916
      stl[n] = sr[n].ScriptTag;
 
5917
    stl[n] = 0;
 
5918
 
 
5919
    *script_tag_list = stl;
 
5920
 
 
5921
    return TT_Err_Ok;
 
5922
  }
 
5923
 
 
5924
 
 
5925
  EXPORT_FUNC
 
5926
  FT_Error  TT_GPOS_Query_Languages( TTO_GPOSHeader*  gpos,
 
5927
                                     FT_UShort        script_index,
 
5928
                                     FT_ULong**       language_tag_list )
 
5929
  {
 
5930
    FT_Error            error;
 
5931
    FT_Memory           memory = gpos->memory;
 
5932
    FT_UShort           n;
 
5933
    FT_ULong*           ltl;
 
5934
 
 
5935
    TTO_ScriptList*     sl;
 
5936
    TTO_ScriptRecord*   sr;
 
5937
    TTO_Script*         s;
 
5938
    TTO_LangSysRecord*  lsr;
 
5939
 
 
5940
 
 
5941
    if ( !gpos || !language_tag_list )
 
5942
      return TT_Err_Invalid_Argument;
 
5943
 
 
5944
    sl = &gpos->ScriptList;
 
5945
    sr = sl->ScriptRecord;
 
5946
 
 
5947
    if ( script_index >= sl->ScriptCount )
 
5948
      return TT_Err_Invalid_Argument;
 
5949
 
 
5950
    s   = &sr[script_index].Script;
 
5951
    lsr = s->LangSysRecord;
 
5952
 
 
5953
    if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, FT_ULong ) )
 
5954
      return error;
 
5955
 
 
5956
    for ( n = 0; n < s->LangSysCount; n++ )
 
5957
      ltl[n] = lsr[n].LangSysTag;
 
5958
    ltl[n] = 0;
 
5959
 
 
5960
    *language_tag_list = ltl;
 
5961
 
 
5962
    return TT_Err_Ok;
 
5963
  }
 
5964
 
 
5965
 
 
5966
  /* selecting 0xFFFF for language_index asks for the values of the
 
5967
     default language (DefaultLangSys)                              */
 
5968
 
 
5969
  EXPORT_FUNC
 
5970
  FT_Error  TT_GPOS_Query_Features( TTO_GPOSHeader*  gpos,
 
5971
                                    FT_UShort        script_index,
 
5972
                                    FT_UShort        language_index,
 
5973
                                    FT_ULong**       feature_tag_list )
 
5974
  {
 
5975
    FT_UShort           n;
 
5976
    FT_Error            error;
 
5977
    FT_Memory           memory = gpos->memory;
 
5978
    FT_ULong*           ftl;
 
5979
 
 
5980
    TTO_ScriptList*     sl;
 
5981
    TTO_ScriptRecord*   sr;
 
5982
    TTO_Script*         s;
 
5983
    TTO_LangSysRecord*  lsr;
 
5984
    TTO_LangSys*        ls;
 
5985
    FT_UShort*          fi;
 
5986
 
 
5987
    TTO_FeatureList*    fl;
 
5988
    TTO_FeatureRecord*  fr;
 
5989
 
 
5990
 
 
5991
    if ( !gpos || !feature_tag_list )
 
5992
      return TT_Err_Invalid_Argument;
 
5993
 
 
5994
    sl = &gpos->ScriptList;
 
5995
    sr = sl->ScriptRecord;
 
5996
 
 
5997
    fl = &gpos->FeatureList;
 
5998
    fr = fl->FeatureRecord;
 
5999
 
 
6000
    if ( script_index >= sl->ScriptCount )
 
6001
      return TT_Err_Invalid_Argument;
 
6002
 
 
6003
    s   = &sr[script_index].Script;
 
6004
    lsr = s->LangSysRecord;
 
6005
 
 
6006
    if ( language_index == 0xFFFF )
 
6007
      ls = &s->DefaultLangSys;
 
6008
    else
 
6009
    {
 
6010
      if ( language_index >= s->LangSysCount )
 
6011
        return TT_Err_Invalid_Argument;
 
6012
 
 
6013
      ls = &lsr[language_index].LangSys;
 
6014
    }
 
6015
 
 
6016
    fi = ls->FeatureIndex;
 
6017
 
 
6018
    if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, FT_ULong ) )
 
6019
      return error;
 
6020
 
 
6021
    for ( n = 0; n < ls->FeatureCount; n++ )
 
6022
    {
 
6023
      if ( fi[n] >= fl->FeatureCount )
 
6024
      {
 
6025
        FREE( ftl );
 
6026
        return TTO_Err_Invalid_GPOS_SubTable_Format;
 
6027
      }
 
6028
      ftl[n] = fr[fi[n]].FeatureTag;
 
6029
    }
 
6030
    ftl[n] = 0;
 
6031
 
 
6032
    *feature_tag_list = ftl;
 
6033
 
 
6034
    return TT_Err_Ok;
 
6035
  }
 
6036
 
 
6037
 
 
6038
  /* Do an individual subtable lookup.  Returns TT_Err_Ok if positioning
 
6039
     has been done, or TTO_Err_Not_Covered if not.                        */
 
6040
 
 
6041
  static FT_Error  GPos_Do_Glyph_Lookup( GPOS_Instance*    gpi,
 
6042
                                    FT_UShort         lookup_index,
 
6043
                                    TTO_GSUB_String*  in,
 
6044
                                    TTO_GPOS_Data*    out,
 
6045
                                    FT_UShort         context_length,
 
6046
                                    int               nesting_level )
 
6047
  {
 
6048
    FT_Error         error = TT_Err_Ok;
 
6049
    FT_UShort        i, flags;
 
6050
    TTO_GPOSHeader*  gpos = gpi->gpos;
 
6051
    TTO_Lookup*      lo;
 
6052
 
 
6053
 
 
6054
    nesting_level++;
 
6055
 
 
6056
    if ( nesting_level > TTO_MAX_NESTING_LEVEL )
 
6057
      return TTO_Err_Too_Many_Nested_Contexts;
 
6058
 
 
6059
    lo    = &gpos->LookupList.Lookup[lookup_index];
 
6060
    flags = lo->LookupFlag;
 
6061
 
 
6062
    for ( i = 0; i < lo->SubTableCount; i++ )
 
6063
    {
 
6064
      switch ( lo->LookupType )
 
6065
      {
 
6066
      case GPOS_LOOKUP_SINGLE:
 
6067
        error = Lookup_SinglePos( gpi,
 
6068
                                  &lo->SubTable[i].st.gpos.single,
 
6069
                                  in, out,
 
6070
                                  flags, context_length );
 
6071
        break;
 
6072
 
 
6073
      case GPOS_LOOKUP_PAIR:
 
6074
        error = Lookup_PairPos( gpi,
 
6075
                                &lo->SubTable[i].st.gpos.pair,
 
6076
                                in, out,
 
6077
                                flags, context_length );
 
6078
        break;
 
6079
 
 
6080
      case GPOS_LOOKUP_CURSIVE:
 
6081
        error = Lookup_CursivePos( gpi,
 
6082
                                   &lo->SubTable[i].st.gpos.cursive,
 
6083
                                   in, out,
 
6084
                                   flags, context_length );
 
6085
        break;
 
6086
 
 
6087
      case GPOS_LOOKUP_MARKBASE:
 
6088
        error = Lookup_MarkBasePos( gpi,
 
6089
                                    &lo->SubTable[i].st.gpos.markbase,
 
6090
                                    in, out,
 
6091
                                    flags, context_length );
 
6092
        break;
 
6093
 
 
6094
      case GPOS_LOOKUP_MARKLIG:
 
6095
        error = Lookup_MarkLigPos( gpi,
 
6096
                                   &lo->SubTable[i].st.gpos.marklig,
 
6097
                                   in, out,
 
6098
                                   flags, context_length );
 
6099
        break;
 
6100
 
 
6101
      case GPOS_LOOKUP_MARKMARK:
 
6102
        error = Lookup_MarkMarkPos( gpi,
 
6103
                                    &lo->SubTable[i].st.gpos.markmark,
 
6104
                                    in, out,
 
6105
                                    flags, context_length );
 
6106
        break;
 
6107
 
 
6108
      case GPOS_LOOKUP_CONTEXT:
 
6109
        error = Lookup_ContextPos( gpi,
 
6110
                                   &lo->SubTable[i].st.gpos.context,
 
6111
                                   in, out,
 
6112
                                   flags, context_length,
 
6113
                                   nesting_level );
 
6114
        break;
 
6115
 
 
6116
      case GPOS_LOOKUP_CHAIN:
 
6117
        error = Lookup_ChainContextPos( gpi,
 
6118
                                        &lo->SubTable[i].st.gpos.chain,
 
6119
                                        in, out,
 
6120
                                        flags, context_length,
 
6121
                                        nesting_level );
 
6122
        break;
 
6123
      }
 
6124
 
 
6125
      /* Check whether we have a successful positioning or an error other
 
6126
         than TTO_Err_Not_Covered                                         */
 
6127
 
 
6128
      if ( error != TTO_Err_Not_Covered )
 
6129
        return error;
 
6130
    }
 
6131
 
 
6132
    return TTO_Err_Not_Covered;
 
6133
  }
 
6134
 
 
6135
 
 
6136
  /* apply one lookup to the input string object */
 
6137
 
 
6138
  static FT_Error  GPos_Do_String_Lookup( GPOS_Instance*    gpi,
 
6139
                                     FT_UShort         lookup_index,
 
6140
/*                                        unsigned char *where_to_apply, */
 
6141
                                     TTO_GSUB_String*  in,
 
6142
                                     TTO_GPOS_Data*    out )
 
6143
  {
 
6144
    FT_Error         error = TTO_Err_Not_Covered;
 
6145
 
 
6146
    int       nesting_level = 0;
 
6147
    FT_UShort i;
 
6148
    FT_Pos    offset;
 
6149
 
 
6150
 
 
6151
    gpi->first = 0xFFFF;
 
6152
    gpi->last  = 0xFFFF;     /* no last valid glyph for cursive pos. */
 
6153
 
 
6154
    in->pos = 0;
 
6155
 
 
6156
    while ( in->pos < in->length )
 
6157
    {
 
6158
        if (1) /* where_to_apply[in->pos]) */
 
6159
      {
 
6160
        /* 0xFFFF indicates that we don't have a context length yet. */
 
6161
 
 
6162
        /* Note that the connection between mark and base glyphs hold
 
6163
           exactly one (string) lookup.  For example, it would be possible
 
6164
           that in the first lookup, mark glyph X is attached to base
 
6165
           glyph A, and in the next lookup it is attached to base glyph B.
 
6166
           It is up to the font designer to provide meaningful lookups and
 
6167
           lookup order.                                                   */
 
6168
 
 
6169
        error = GPos_Do_Glyph_Lookup( gpi, lookup_index, in, out,
 
6170
                                 0xFFFF, nesting_level );
 
6171
        if ( error && error != TTO_Err_Not_Covered )
 
6172
          return error;
 
6173
      }
 
6174
      else
 
6175
      {
 
6176
        /* Contrary to properties defined in GDEF, user-defined properties
 
6177
           will always stop a possible cursive positioning.                */
 
6178
        gpi->last = 0xFFFF;
 
6179
 
 
6180
        error = TTO_Err_Not_Covered;
 
6181
      }
 
6182
 
 
6183
      /* test whether we have to adjust the offsets for cursive connections */
 
6184
 
 
6185
      if ( gpi->first != 0xFFFF && gpi->last == 0xFFFF &&
 
6186
           gpi->gpos->LookupList.Lookup[lookup_index].LookupFlag & RIGHT_TO_LEFT )
 
6187
      {
 
6188
        offset = out[in->pos].y_pos;
 
6189
 
 
6190
        /* no horizontal offsets (for vertical writing direction)
 
6191
           supported yet                                          */
 
6192
 
 
6193
        for ( i = gpi->first; i <= in->pos; i++ )
 
6194
          out[i].y_pos -= offset;
 
6195
 
 
6196
        gpi->first = 0xFFFF;
 
6197
      }
 
6198
 
 
6199
      if ( error == TTO_Err_Not_Covered )
 
6200
        (in->pos)++;
 
6201
    }
 
6202
 
 
6203
    return error;
 
6204
  }
 
6205
 
 
6206
 
 
6207
 
 
6208
 
 
6209
  EXPORT_FUNC
 
6210
  FT_Error  TT_GPOS_Register_Glyph_Function( TTO_GPOSHeader*    gpos,
 
6211
                                             TTO_GlyphFunction  gfunc )
 
6212
  {
 
6213
    if ( !gpos )
 
6214
      return TT_Err_Invalid_Argument;
 
6215
 
 
6216
    gpos->gfunc = gfunc;
 
6217
 
 
6218
    return TT_Err_Ok;
 
6219
  }
 
6220
 
 
6221
 
 
6222
  EXPORT_FUNC
 
6223
  FT_Error  TT_GPOS_Register_MM_Function( TTO_GPOSHeader*  gpos,
 
6224
                                          TTO_MMFunction   mmfunc,
 
6225
                                          void*            data )
 
6226
  {
 
6227
    if ( !gpos )
 
6228
      return TT_Err_Invalid_Argument;
 
6229
 
 
6230
    gpos->mmfunc = mmfunc;
 
6231
    gpos->data   = data;
 
6232
 
 
6233
    return TT_Err_Ok;
 
6234
  }
 
6235
 
 
6236
 
 
6237
  /* If `dvi' is TRUE, glyph contour points for anchor points and device
 
6238
     tables are ignored -- you will get device independent values.         */
 
6239
 
 
6240
  EXPORT_FUNC
 
6241
  FT_Error  TT_GPOS_Apply_Feature(FT_Face            face,
 
6242
                                  TTO_GPOSHeader*    gpos,
 
6243
                                  FT_UShort          feature_index,
 
6244
                                  FT_UShort          load_flags,
 
6245
                                  TTO_GSUB_String*   in,
 
6246
                                  TTO_GPOS_Data**    out,
 
6247
                                  FT_Bool            dvi,
 
6248
                                  FT_Bool            r2l )
 
6249
  {
 
6250
    FT_Error       error = TTO_Err_Not_Covered;
 
6251
    GPOS_Instance  gpi;
 
6252
    TTO_Feature  feature;
 
6253
    FT_UShort *index;
 
6254
 
 
6255
    FT_UShort j;
 
6256
 
 
6257
    if ( !face || !gpos ||
 
6258
         !in || in->length == 0 || in->pos >= in->length )
 
6259
      return TT_Err_Invalid_Argument;
 
6260
 
 
6261
    gpi.face       = face;
 
6262
    gpi.gpos       = gpos;
 
6263
    gpi.load_flags = load_flags;
 
6264
    gpi.r2l        = r2l;
 
6265
    gpi.dvi        = dvi;
 
6266
 
 
6267
    feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
 
6268
    index   = feature.LookupListIndex;
 
6269
 
 
6270
    /*
 
6271
      ###### need to order lookups in the order they appear in the
 
6272
      ###### lookup list, not the order they appear in the
 
6273
      ###### featurelist.
 
6274
    */
 
6275
 
 
6276
    for ( j = 0; j < feature.LookupListCount; j++ ) {
 
6277
        error = GPos_Do_String_Lookup( &gpi, index[j], in, *out );
 
6278
        if ( error && error != TTO_Err_Not_Covered )
 
6279
          return error;
 
6280
    }
 
6281
 
 
6282
    return error;
 
6283
  }
 
6284
 
 
6285
/* END */