w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

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