Coverage Report

Created: 2025-11-16 07:45

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