ReactOS  0.4.13-dev-99-g7e18b6d
opentype.c
Go to the documentation of this file.
1 /*
2  * Opentype font interfaces for the Uniscribe Script Processor (usp10.dll)
3  *
4  * Copyright 2012 CodeWeavers, Aric Stewart
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  */
21 #include <stdarg.h>
22 #include <stdlib.h>
23 
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "usp10.h"
30 #include "winternl.h"
31 
32 #include "usp10_internal.h"
33 
34 #include "wine/debug.h"
35 #include "wine/heap.h"
36 
38 
39 #ifdef WORDS_BIGENDIAN
40 #define GET_BE_WORD(x) (x)
41 #define GET_BE_DWORD(x) (x)
42 #else
43 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
44 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
45 #endif
46 
47 #define round(x) (((x) < 0) ? (int)((x) - 0.5) : (int)((x) + 0.5))
48 
49 /* These are all structures needed for the cmap format 12 table */
50 #define CMAP_TAG MS_MAKE_TAG('c', 'm', 'a', 'p')
51 
53 {
63 };
64 
66 {
75 };
76 
77 typedef struct {
82 
83 typedef struct {
87 } CMAP_Header;
88 
89 typedef struct {
94 
95 typedef struct {
103 
104 /* These are all structures needed for the GDEF table */
106 
107 typedef struct {
113 } GDEF_Header;
114 
115 typedef struct {
119  WORD ClassValueArray[1];
121 
122 typedef struct {
127 
128 typedef struct {
131  OT_ClassRangeRecord ClassRangeRecord[1];
133 
134 /* These are all structures needed for the GSUB table */
135 
136 typedef struct {
141 } GSUB_Header;
142 
143 typedef struct {
144  CHAR ScriptTag[4];
147 
148 typedef struct {
150  OT_ScriptRecord ScriptRecord[1];
151 } OT_ScriptList;
152 
153 typedef struct {
154  CHAR LangSysTag[4];
157 
158 typedef struct {
161  OT_LangSysRecord LangSysRecord[1];
162 } OT_Script;
163 
164 typedef struct {
165  WORD LookupOrder; /* Reserved */
168  WORD FeatureIndex[1];
169 } OT_LangSys;
170 
171 typedef struct {
172  CHAR FeatureTag[4];
175 
176 typedef struct {
178  OT_FeatureRecord FeatureRecord[1];
180 
181 typedef struct {
182  WORD FeatureParams; /* Reserved */
184  WORD LookupListIndex[1];
185 } OT_Feature;
186 
187 typedef struct {
190 } OT_LookupList;
191 
192 typedef struct {
196  WORD SubTable[1];
198 
199 typedef struct {
202  WORD GlyphArray[1];
204 
205 typedef struct {
210 
211 typedef struct {
214  OT_RangeRecord RangeRecord[1];
216 
217 typedef struct {
218  WORD SubstFormat; /* = 1 */
222 
223 typedef struct {
224  WORD SubstFormat; /* = 2 */
229 
230 typedef struct {
231  WORD SubstFormat; /* = 1 */
234  WORD Sequence[1];
236 
237 typedef struct {
241 
242 typedef struct {
243  WORD SubstFormat; /* = 1 */
246  WORD LigatureSet[1];
248 
249 typedef struct {
253 
254 typedef struct{
257  WORD Component[1];
259 
260 typedef struct{
263 
265 
266 typedef struct{
270  WORD SubRuleSet[1];
272 
273 typedef struct{
275  WORD SubRule[1];
277 
278 typedef struct {
283 
284 typedef struct {
285  GSUB_SubstLookupRecord SubstLookupRecord[1];
287 
288 typedef struct {
293  WORD SubClassSet[1];
295 
296 typedef struct {
298  WORD SubClassRule[1];
300 
301 typedef struct {
306 
307 typedef struct {
308  GSUB_SubstLookupRecord SubstLookupRecord[1];
310 
311 typedef struct{
312  WORD SubstFormat; /* = 1 */
315  WORD ChainSubRuleSet[1];
317 
318 typedef struct {
319  WORD SubstFormat; /* = 2 */
325  WORD ChainSubClassSet[1];
327 
328 typedef struct {
330  WORD ChainSubClassRule[1];
332 
333 typedef struct {
335  WORD Backtrack[1];
337 
338 typedef struct {
342 
343 typedef struct {
345  WORD LookAhead[1];
347 
348 typedef struct {
350  GSUB_SubstLookupRecord SubstLookupRecord[1];
352 
353 typedef struct {
354  WORD SubstFormat; /* = 3 */
356  WORD Coverage[1];
358 
359 typedef struct{
361  WORD Coverage[1];
363 
364 typedef struct{
366  WORD Coverage[1];
368 
369 typedef struct{
371  GSUB_SubstLookupRecord SubstLookupRecord[1];
373 
374 typedef struct {
375  WORD SubstFormat; /* = 1 */
378  WORD AlternateSet[1];
380 
381 typedef struct{
383  WORD Alternate[1];
385 
386 typedef struct {
391 
392 /* These are all structures needed for the GPOS table */
393 
394 typedef struct {
399 } GPOS_Header;
400 
401 typedef struct {
405  WORD DeltaValue[1];
407 
408 typedef struct {
413 
414 typedef struct {
420 
421 typedef struct {
428 
429 typedef struct {
439 
440 typedef struct {
446 
447 typedef struct {
454 
455 typedef struct {
461  WORD PairSetOffset[1];
463 
464 typedef struct {
473  WORD Class1Record[1];
475 
476 typedef struct {
478  WORD Value1[1];
479  WORD Value2[1];
481 
482 typedef struct {
484  GPOS_PairValueRecord PairValueRecord[1];
485 } GPOS_PairSet;
486 
487 typedef struct {
491 
492 typedef struct {
496  GPOS_EntryExitRecord EntryExitRecord[1];
498 
499 typedef struct {
507 
508 typedef struct {
509  WORD BaseAnchor[1];
511 
512 typedef struct {
514  GPOS_BaseRecord BaseRecord[1];
516 
517 typedef struct {
521 
522 typedef struct {
524  GPOS_MarkRecord MarkRecord[1];
526 
527 typedef struct {
535 
536 typedef struct {
538  WORD LigatureAttach[1];
540 
541 typedef struct {
542  WORD LigatureAnchor[1];
544 
545 typedef struct {
547  GPOS_ComponentRecord ComponentRecord[1];
549 
550 typedef struct {
558 
559 typedef struct {
560  WORD Mark2Anchor[1];
562 
563 typedef struct {
565  GPOS_Mark2Record Mark2Record[1];
567 
568 typedef struct {
572 
573 typedef struct {
578  WORD PosClassSet[1];
580 
581 typedef struct {
583  WORD PosClassRule[1];
585 
586 typedef struct {
591 
592 typedef struct {
593  GPOS_PosLookupRecord PosLookupRecord[1];
595 
596 typedef struct {
599  WORD Coverage[1];
601 
602 typedef struct {
604  WORD Coverage[1];
606 
607 typedef struct {
609  WORD Coverage[1];
611 
612 typedef struct {
614  GPOS_PosLookupRecord PosLookupRecord[1];
616 
617 typedef struct {
622 
623 /**********
624  * CMAP
625  **********/
626 
628 {
629  CMAP_Header *CMAP_Table = NULL;
630  int length;
631  int i;
632 
633  if (!psc->CMAP_Table)
634  {
635  length = GetFontData(hdc, CMAP_TAG , 0, NULL, 0);
636  if (length != GDI_ERROR)
637  {
638  psc->CMAP_Table = heap_alloc(length);
639  GetFontData(hdc, CMAP_TAG , 0, psc->CMAP_Table, length);
640  TRACE("Loaded cmap table of %i bytes\n",length);
641  }
642  else
643  return NULL;
644  }
645 
646  CMAP_Table = psc->CMAP_Table;
647 
648  for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++)
649  {
650  if ( (GET_BE_WORD(CMAP_Table->tables[i].platformID) == 3) &&
651  (GET_BE_WORD(CMAP_Table->tables[i].encodingID) == 10) )
652  {
653  CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
654  if (GET_BE_WORD(format->format) == 12)
655  return format;
656  }
657  }
658  return NULL;
659 }
660 
661 static int compare_group(const void *a, const void* b)
662 {
663  const DWORD *chr = a;
665 
666  if (*chr < GET_BE_DWORD(group->startCharCode))
667  return -1;
668  if (*chr > GET_BE_DWORD(group->endCharCode))
669  return 1;
670  return 0;
671 }
672 
674 {
675  /* BMP: use gdi32 for ease */
676  if (utf32c < 0x10000)
677  {
678  WCHAR ch = utf32c;
679  return GetGlyphIndicesW(hdc, &ch, 1, glyph_index, flags);
680  }
681 
682  if (!psc->CMAP_format12_Table)
683  psc->CMAP_format12_Table = load_CMAP_format12_table(hdc, psc);
684 
686  *glyph_index = 0xffffu;
687  else
688  *glyph_index = 0u;
689 
690  if (psc->CMAP_format12_Table)
691  {
694 
695  format = (CMAP_SegmentedCoverage *)psc->CMAP_format12_Table;
696 
697  group = bsearch(&utf32c, format->groups, GET_BE_DWORD(format->nGroups),
699 
700  if (group)
701  {
702  DWORD offset = utf32c - GET_BE_DWORD(group->startCharCode);
703  *glyph_index = GET_BE_DWORD(group->startGlyphID) + offset;
704  return 0;
705  }
706  }
707  return 0;
708 }
709 
710 /**********
711  * GDEF
712  **********/
713 
714 static WORD OT_get_glyph_class(const void *table, WORD glyph)
715 {
716  WORD class = 0;
717  const OT_ClassDefFormat1 *cf1 = table;
718 
719  if (!table) return 0;
720 
721  if (GET_BE_WORD(cf1->ClassFormat) == 1)
722  {
723  if (glyph >= GET_BE_WORD(cf1->StartGlyph))
724  {
725  int index = glyph - GET_BE_WORD(cf1->StartGlyph);
726  if (index < GET_BE_WORD(cf1->GlyphCount))
727  class = GET_BE_WORD(cf1->ClassValueArray[index]);
728  }
729  }
730  else if (GET_BE_WORD(cf1->ClassFormat) == 2)
731  {
732  const OT_ClassDefFormat2 *cf2 = table;
733  int i, top;
735  for (i = 0; i < top; i++)
736  {
737  if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
738  glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
739  {
740  class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
741  break;
742  }
743  }
744  }
745  else
746  ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
747 
748  return class;
749 }
750 
752 {
753  int i;
754  void *glyph_class_table = NULL;
755 
756  if (psc->GDEF_Table)
757  {
758  const GDEF_Header *header = psc->GDEF_Table;
759  WORD offset = GET_BE_WORD( header->GlyphClassDef );
760  if (offset)
761  glyph_class_table = (BYTE *)psc->GDEF_Table + offset;
762  }
763 
764  for (i = 0; i < cGlyphs; i++)
765  {
766  WORD class;
767  int char_count = 0;
768  int k;
769 
771  if (k >= 0)
772  {
773  for (; k < cChars && pwLogClust[k] == i; k++)
774  char_count++;
775  }
776 
777  class = OT_get_glyph_class( glyph_class_table, pwGlyphs[i] );
778 
779  switch (class)
780  {
781  case 0:
782  case BaseGlyph:
783  pGlyphProp[i].sva.fClusterStart = 1;
784  pGlyphProp[i].sva.fDiacritic = 0;
785  pGlyphProp[i].sva.fZeroWidth = 0;
786  break;
787  case LigatureGlyph:
788  pGlyphProp[i].sva.fClusterStart = 1;
789  pGlyphProp[i].sva.fDiacritic = 0;
790  pGlyphProp[i].sva.fZeroWidth = 0;
791  break;
792  case MarkGlyph:
793  pGlyphProp[i].sva.fClusterStart = 0;
794  pGlyphProp[i].sva.fDiacritic = 1;
795  pGlyphProp[i].sva.fZeroWidth = 1;
796  break;
797  case ComponentGlyph:
798  pGlyphProp[i].sva.fClusterStart = 0;
799  pGlyphProp[i].sva.fDiacritic = 0;
800  pGlyphProp[i].sva.fZeroWidth = 0;
801  break;
802  default:
803  ERR("Unknown glyph class %i\n",class);
804  pGlyphProp[i].sva.fClusterStart = 1;
805  pGlyphProp[i].sva.fDiacritic = 0;
806  pGlyphProp[i].sva.fZeroWidth = 0;
807  }
808 
809  if (char_count == 0)
810  pGlyphProp[i].sva.fClusterStart = 0;
811  }
812 }
813 
814 /**********
815  * GSUB
816  **********/
817 static INT GSUB_apply_lookup(const OT_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
818 
819 static int GSUB_is_glyph_covered(const void *table, unsigned int glyph)
820 {
821  const OT_CoverageFormat1* cf1;
822 
823  cf1 = table;
824 
825  if (GET_BE_WORD(cf1->CoverageFormat) == 1)
826  {
827  int count = GET_BE_WORD(cf1->GlyphCount);
828  int i;
829  TRACE("Coverage Format 1, %i glyphs\n",count);
830  for (i = 0; i < count; i++)
831  if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
832  return i;
833  return -1;
834  }
835  else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
836  {
837  const OT_CoverageFormat2* cf2;
838  int i;
839  int count;
840  cf2 = (const OT_CoverageFormat2*)cf1;
841 
842  count = GET_BE_WORD(cf2->RangeCount);
843  TRACE("Coverage Format 2, %i ranges\n",count);
844  for (i = 0; i < count; i++)
845  {
846  if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
847  return -1;
848  if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
849  (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
850  {
852  glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
853  }
854  }
855  return -1;
856  }
857  else
858  ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
859 
860  return -1;
861 }
862 
863 static const BYTE *GSUB_get_subtable(const OT_LookupTable *look, int index)
864 {
865  int offset = GET_BE_WORD(look->SubTable[index]);
866 
868  {
869  const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)look + offset);
870  if (GET_BE_WORD(ext->SubstFormat) == 1)
871  {
872  offset += GET_BE_DWORD(ext->ExtensionOffset);
873  }
874  else
875  {
876  FIXME("Unhandled Extension Substitution Format %i\n",GET_BE_WORD(ext->SubstFormat));
877  }
878  }
879  return (const BYTE *)look + offset;
880 }
881 
882 static INT GSUB_apply_SingleSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
883 {
884  int j;
885  TRACE("Single Substitution Subtable\n");
886 
887  for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
888  {
890  if (GET_BE_WORD(ssf1->SubstFormat) == 1)
891  {
892  int offset = GET_BE_WORD(ssf1->Coverage);
893  TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
894  if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
895  {
896  TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
897  glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
898  TRACE(" 0x%x\n",glyphs[glyph_index]);
899  return glyph_index + write_dir;
900  }
901  }
902  else
903  {
904  const GSUB_SingleSubstFormat2 *ssf2;
905  INT index;
906  INT offset;
907 
908  ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
909  offset = GET_BE_WORD(ssf1->Coverage);
910  TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
911  index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
912  TRACE(" Coverage index %i\n",index);
913  if (index != -1)
914  {
915  if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
916  return GSUB_E_NOGLYPH;
917 
918  TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
919  glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
920  TRACE("0x%x\n",glyphs[glyph_index]);
921  return glyph_index + write_dir;
922  }
923  }
924  }
925  return GSUB_E_NOGLYPH;
926 }
927 
928 static INT GSUB_apply_MultipleSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
929 {
930  int j;
931  TRACE("Multiple Substitution Subtable\n");
932 
933  for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
934  {
935  int offset, index;
936  const GSUB_MultipleSubstFormat1 *msf1;
937  msf1 = (const GSUB_MultipleSubstFormat1*)GSUB_get_subtable(look, j);
938 
939  offset = GET_BE_WORD(msf1->Coverage);
940  index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
941  if (index != -1)
942  {
943  const GSUB_Sequence *seq;
944  int sub_count;
945  int j;
946  offset = GET_BE_WORD(msf1->Sequence[index]);
947  seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
948  sub_count = GET_BE_WORD(seq->GlyphCount);
949  TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
950 
951  for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
952  glyphs[j] =glyphs[j-(sub_count-1)];
953 
954  for (j = 0; j < sub_count; j++)
955  if (write_dir < 0)
956  glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
957  else
958  glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
959 
960  *glyph_count = *glyph_count + (sub_count - 1);
961 
962  if (TRACE_ON(uniscribe))
963  {
964  for (j = 0; j < sub_count; j++)
965  TRACE(" 0x%x",glyphs[glyph_index+j]);
966  TRACE("\n");
967  }
968 
969  if (write_dir > 0)
970  return glyph_index + sub_count;
971  else
972  return glyph_index - 1;
973  }
974  }
975  return GSUB_E_NOGLYPH;
976 }
977 
978 static INT GSUB_apply_AlternateSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
979 {
980  int j;
981  TRACE("Alternate Substitution Subtable\n");
982 
983  for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
984  {
985  int offset;
986  const GSUB_AlternateSubstFormat1 *asf1;
987  INT index;
988 
989  asf1 = (const GSUB_AlternateSubstFormat1*)GSUB_get_subtable(look, j);
990  offset = GET_BE_WORD(asf1->Coverage);
991 
992  index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
993  if (index != -1)
994  {
995  const GSUB_AlternateSet *as;
997  as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
998  FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
999  if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
1000  return GSUB_E_NOGLYPH;
1001 
1002  TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
1003  glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
1004  TRACE(" 0x%x\n",glyphs[glyph_index]);
1005  return glyph_index + write_dir;
1006  }
1007  }
1008  return GSUB_E_NOGLYPH;
1009 }
1010 
1011 static INT GSUB_apply_LigatureSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1012 {
1013  int j;
1014 
1015  TRACE("Ligature Substitution Subtable\n");
1016  for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1017  {
1018  const GSUB_LigatureSubstFormat1 *lsf1;
1019  int offset,index;
1020 
1021  lsf1 = (const GSUB_LigatureSubstFormat1*)GSUB_get_subtable(look, j);
1022  offset = GET_BE_WORD(lsf1->Coverage);
1023  index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
1024  TRACE(" Coverage index %i\n",index);
1025  if (index != -1)
1026  {
1027  const GSUB_LigatureSet *ls;
1028  int k, count;
1029 
1030  offset = GET_BE_WORD(lsf1->LigatureSet[index]);
1031  ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
1032  count = GET_BE_WORD(ls->LigatureCount);
1033  TRACE(" LigatureSet has %i members\n",count);
1034  for (k = 0; k < count; k++)
1035  {
1036  const GSUB_Ligature *lig;
1037  int CompCount,l,CompIndex;
1038 
1039  offset = GET_BE_WORD(ls->Ligature[k]);
1040  lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
1041  CompCount = GET_BE_WORD(lig->CompCount) - 1;
1042  CompIndex = glyph_index+write_dir;
1043  for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
1044  {
1045  int CompGlyph;
1046  CompGlyph = GET_BE_WORD(lig->Component[l]);
1047  if (CompGlyph != glyphs[CompIndex])
1048  break;
1049  CompIndex += write_dir;
1050  }
1051  if (l == CompCount)
1052  {
1053  int replaceIdx = glyph_index;
1054  if (write_dir < 0)
1055  replaceIdx = glyph_index - CompCount;
1056 
1057  TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
1058  glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
1059  TRACE("0x%x\n",glyphs[replaceIdx]);
1060  if (CompCount > 0)
1061  {
1062  unsigned int j = replaceIdx + 1;
1063  memmove(&glyphs[j], &glyphs[j + CompCount], (*glyph_count - j) * sizeof(*glyphs));
1064  *glyph_count = *glyph_count - CompCount;
1065  }
1066  return replaceIdx + write_dir;
1067  }
1068  }
1069  }
1070  }
1071  return GSUB_E_NOGLYPH;
1072 }
1073 
1074 static INT GSUB_apply_ContextSubst(const OT_LookupList* lookup, const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1075 {
1076  int j;
1077  TRACE("Context Substitution Subtable\n");
1078  for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1079  {
1080  const GSUB_ContextSubstFormat1 *csf1;
1081 
1082  csf1 = (const GSUB_ContextSubstFormat1*)GSUB_get_subtable(look, j);
1083  if (GET_BE_WORD(csf1->SubstFormat) == 1)
1084  {
1085  int offset, index;
1086  TRACE("Context Substitution Subtable: Class 1\n");
1087  offset = GET_BE_WORD(csf1->Coverage);
1088  index = GSUB_is_glyph_covered((const BYTE*)csf1+offset, glyphs[glyph_index]);
1089  TRACE(" Coverage index %i\n",index);
1090  if (index != -1)
1091  {
1092  int k, count;
1093  const GSUB_SubRuleSet *srs;
1094  offset = GET_BE_WORD(csf1->SubRuleSet[index]);
1095  srs = (const GSUB_SubRuleSet*)((const BYTE*)csf1+offset);
1096  count = GET_BE_WORD(srs->SubRuleCount);
1097  TRACE(" SubRuleSet has %i members\n",count);
1098  for (k = 0; k < count; k++)
1099  {
1100  const GSUB_SubRule_1 *sr;
1101  const GSUB_SubRule_2 *sr_2;
1102  unsigned int g;
1103  int g_count, l;
1104  int newIndex = glyph_index;
1105 
1106  offset = GET_BE_WORD(srs->SubRule[k]);
1107  sr = (const GSUB_SubRule_1*)((const BYTE*)srs+offset);
1108  g_count = GET_BE_WORD(sr->GlyphCount);
1109  TRACE(" SubRule has %i glyphs\n",g_count);
1110 
1111  g = glyph_index + write_dir * (g_count - 1);
1112  if (g >= *glyph_count)
1113  continue;
1114 
1115  for (l = 0; l < g_count-1; l++)
1116  if (glyphs[glyph_index + (write_dir * (l+1))] != GET_BE_WORD(sr->Input[l])) break;
1117 
1118  if (l < g_count-1)
1119  {
1120  TRACE(" Rule does not match\n");
1121  continue;
1122  }
1123 
1124  TRACE(" Rule matches\n");
1125  sr_2 = (const GSUB_SubRule_2 *)&sr->Input[g_count - 1];
1126 
1127  for (l = 0; l < GET_BE_WORD(sr->SubstCount); l++)
1128  {
1129  unsigned int lookup_index = GET_BE_WORD(sr_2->SubstLookupRecord[l].LookupListIndex);
1130  unsigned int sequence_index = GET_BE_WORD(sr_2->SubstLookupRecord[l].SequenceIndex);
1131 
1132  g = glyph_index + write_dir * sequence_index;
1133  if (g >= *glyph_count)
1134  {
1135  WARN("Invalid sequence index %u (glyph index %u, write dir %d).\n",
1136  sequence_index, glyph_index, write_dir);
1137  continue;
1138  }
1139 
1140  TRACE(" SUBST: %u -> %u %u.\n", l, sequence_index, lookup_index);
1141  newIndex = GSUB_apply_lookup(lookup, lookup_index, glyphs, g, write_dir, glyph_count);
1142  if (newIndex == GSUB_E_NOGLYPH)
1143  {
1144  ERR(" Chain failed to generate a glyph\n");
1145  continue;
1146  }
1147  }
1148  return newIndex;
1149  }
1150  }
1151  }
1152  else if (GET_BE_WORD(csf1->SubstFormat) == 2)
1153  {
1154  const GSUB_ContextSubstFormat2 *csf2;
1155  const void *glyph_class_table;
1156  int offset, index;
1157 
1158  csf2 = (const GSUB_ContextSubstFormat2*)csf1;
1159  TRACE("Context Substitution Subtable: Class 2\n");
1160  offset = GET_BE_WORD(csf2->Coverage);
1161  index = GSUB_is_glyph_covered((const BYTE*)csf2+offset, glyphs[glyph_index]);
1162  TRACE(" Coverage index %i\n",index);
1163  if (index != -1)
1164  {
1165  int k, count, class;
1166  const GSUB_SubClassSet *scs;
1167 
1168  offset = GET_BE_WORD(csf2->ClassDef);
1169  glyph_class_table = (const BYTE *)csf2 + offset;
1170 
1171  class = OT_get_glyph_class(glyph_class_table,glyphs[glyph_index]);
1172 
1173  offset = GET_BE_WORD(csf2->SubClassSet[class]);
1174  if (offset == 0)
1175  {
1176  TRACE(" No class rule table for class %i\n",class);
1177  continue;
1178  }
1179  scs = (const GSUB_SubClassSet*)((const BYTE*)csf2+offset);
1181  TRACE(" SubClassSet has %i members\n",count);
1182  for (k = 0; k < count; k++)
1183  {
1184  const GSUB_SubClassRule_1 *sr;
1185  const GSUB_SubClassRule_2 *sr_2;
1186  unsigned int g;
1187  int g_count, l;
1188  int newIndex = glyph_index;
1189 
1190  offset = GET_BE_WORD(scs->SubClassRule[k]);
1191  sr = (const GSUB_SubClassRule_1*)((const BYTE*)scs+offset);
1192  g_count = GET_BE_WORD(sr->GlyphCount);
1193  TRACE(" SubClassRule has %i glyphs classes\n",g_count);
1194 
1195  g = glyph_index + write_dir * (g_count - 1);
1196  if (g >= *glyph_count)
1197  continue;
1198 
1199  for (l = 0; l < g_count-1; l++)
1200  {
1201  int g_class = OT_get_glyph_class(glyph_class_table, glyphs[glyph_index + (write_dir * (l+1))]);
1202  if (g_class != GET_BE_WORD(sr->Class[l])) break;
1203  }
1204 
1205  if (l < g_count-1)
1206  {
1207  TRACE(" Rule does not match\n");
1208  continue;
1209  }
1210 
1211  TRACE(" Rule matches\n");
1212  sr_2 = (const GSUB_SubClassRule_2 *)&sr->Class[g_count - 1];
1213 
1214  for (l = 0; l < GET_BE_WORD(sr->SubstCount); l++)
1215  {
1216  unsigned int lookup_index = GET_BE_WORD(sr_2->SubstLookupRecord[l].LookupListIndex);
1217  unsigned int sequence_index = GET_BE_WORD(sr_2->SubstLookupRecord[l].SequenceIndex);
1218 
1219  g = glyph_index + write_dir * sequence_index;
1220  if (g >= *glyph_count)
1221  {
1222  WARN("Invalid sequence index %u (glyph index %u, write dir %d).\n",
1223  sequence_index, glyph_index, write_dir);
1224  continue;
1225  }
1226 
1227  TRACE(" SUBST: %u -> %u %u.\n", l, sequence_index, lookup_index);
1228  newIndex = GSUB_apply_lookup(lookup, lookup_index, glyphs, g, write_dir, glyph_count);
1229  if (newIndex == GSUB_E_NOGLYPH)
1230  {
1231  ERR(" Chain failed to generate a glyph\n");
1232  continue;
1233  }
1234  }
1235  return newIndex;
1236  }
1237  }
1238  }
1239  else
1240  FIXME("Unhandled Context Substitution Format %i\n", GET_BE_WORD(csf1->SubstFormat));
1241  }
1242  return GSUB_E_NOGLYPH;
1243 }
1244 
1245 static INT GSUB_apply_ChainContextSubst(const OT_LookupList* lookup, const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1246 {
1247  int j;
1248 
1249  TRACE("Chaining Contextual Substitution Subtable\n");
1250  for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1251  {
1252  const GSUB_ChainContextSubstFormat1 *ccsf1;
1253  int offset;
1254  int dirLookahead = write_dir;
1255  int dirBacktrack = -1 * write_dir;
1256 
1257  ccsf1 = (const GSUB_ChainContextSubstFormat1*)GSUB_get_subtable(look, j);
1258  if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
1259  {
1260  static int once;
1261  if (!once++)
1262  FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
1263  continue;
1264  }
1265  else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
1266  {
1267  WORD offset, count;
1268  const void *backtrack_class_table;
1269  const void *input_class_table;
1270  const void *lookahead_class_table;
1271  int i;
1272  WORD class;
1273 
1274  const GSUB_ChainContextSubstFormat2 *ccsf2 = (const GSUB_ChainContextSubstFormat2*)ccsf1;
1275  const GSUB_ChainSubClassSet *csc;
1276 
1277  TRACE(" subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
1278 
1279  offset = GET_BE_WORD(ccsf2->Coverage);
1280 
1281  if (GSUB_is_glyph_covered((const BYTE*)ccsf2+offset, glyphs[glyph_index]) == -1)
1282  {
1283  TRACE("Glyph not covered\n");
1284  continue;
1285  }
1287  backtrack_class_table = (const BYTE*)ccsf2+offset;
1288  offset = GET_BE_WORD(ccsf2->InputClassDef);
1289  input_class_table = (const BYTE*)ccsf2+offset;
1291  lookahead_class_table = (const BYTE*)ccsf2+offset;
1293 
1294  class = OT_get_glyph_class(input_class_table, glyphs[glyph_index]);
1295  offset = GET_BE_WORD(ccsf2->ChainSubClassSet[class]);
1296 
1297  if (offset == 0)
1298  {
1299  TRACE("No rules for class\n");
1300  continue;
1301  }
1302 
1303  csc = (const GSUB_ChainSubClassSet*)((BYTE*)ccsf2+offset);
1305 
1306  TRACE("%i rules to check\n",count);
1307 
1308  for (i = 0; i < count; i++)
1309  {
1310  WORD backtrack_count, input_count, lookahead_count, substitute_count;
1311  int k;
1312  const GSUB_ChainSubClassRule_1 *backtrack;
1314  const GSUB_ChainSubClassRule_3 *lookahead;
1315  const GSUB_ChainSubClassRule_4 *substitute;
1316  int new_index = GSUB_E_NOGLYPH;
1317 
1319  backtrack = (const GSUB_ChainSubClassRule_1 *)((BYTE *)csc + offset);
1320  backtrack_count = GET_BE_WORD(backtrack->BacktrackGlyphCount);
1321  k = glyph_index + dirBacktrack * backtrack_count;
1322  if (k < 0 || k >= *glyph_count)
1323  continue;
1324 
1325  input = (const GSUB_ChainSubClassRule_2 *)&backtrack->Backtrack[backtrack_count];
1326  input_count = GET_BE_WORD(input->InputGlyphCount) - 1;
1327  k = glyph_index + write_dir * input_count;
1328  if (k < 0 || k >= *glyph_count)
1329  continue;
1330 
1331  lookahead = (const GSUB_ChainSubClassRule_3 *)&input->Input[input_count];
1332  lookahead_count = GET_BE_WORD(lookahead->LookaheadGlyphCount);
1333  k = glyph_index + dirLookahead * (input_count + lookahead_count);
1334  if (k < 0 || k >= *glyph_count)
1335  continue;
1336 
1337  substitute = (const GSUB_ChainSubClassRule_4 *)&lookahead->LookAhead[lookahead_count];
1338 
1339  for (k = 0; k < backtrack_count; ++k)
1340  {
1341  WORD target_class = GET_BE_WORD(backtrack->Backtrack[k]);
1342  WORD glyph_class = OT_get_glyph_class(backtrack_class_table, glyphs[glyph_index + (dirBacktrack * (k+1))]);
1343  if (target_class != glyph_class)
1344  break;
1345  }
1346  if (k != backtrack_count)
1347  continue;
1348  TRACE("Matched Backtrack\n");
1349 
1350  for (k = 0; k < input_count; ++k)
1351  {
1352  WORD target_class = GET_BE_WORD(input->Input[k]);
1353  WORD glyph_class = OT_get_glyph_class(input_class_table, glyphs[glyph_index + (write_dir * (k+1))]);
1354  if (target_class != glyph_class)
1355  break;
1356  }
1357  if (k != input_count)
1358  continue;
1359  TRACE("Matched IndexGlyphs\n");
1360 
1361  for (k = 0; k < lookahead_count; ++k)
1362  {
1363  WORD target_class = GET_BE_WORD(lookahead->LookAhead[k]);
1364  WORD glyph_class = OT_get_glyph_class(lookahead_class_table,
1365  glyphs[glyph_index + (dirLookahead * (input_count + k + 1))]);
1366  if (target_class != glyph_class)
1367  break;
1368  }
1369  if (k != lookahead_count)
1370  continue;
1371  TRACE("Matched LookAhead\n");
1372 
1373  substitute_count = GET_BE_WORD(substitute->SubstCount);
1374  for (k = 0; k < substitute_count; ++k)
1375  {
1376  unsigned int lookup_index = GET_BE_WORD(substitute->SubstLookupRecord[k].LookupListIndex);
1377  unsigned int sequence_index = GET_BE_WORD(substitute->SubstLookupRecord[k].SequenceIndex);
1378  unsigned int g = glyph_index + write_dir * sequence_index;
1379 
1380  if (g >= *glyph_count)
1381  {
1382  WARN("Skipping invalid sequence index %u (glyph index %u, write dir %d).\n",
1383  sequence_index, glyph_index, write_dir);
1384  continue;
1385  }
1386 
1387  TRACE("SUBST: %u -> %u %u.\n", k, sequence_index, lookup_index);
1388  new_index = GSUB_apply_lookup(lookup, lookup_index, glyphs, g, write_dir, glyph_count);
1389  if (new_index == GSUB_E_NOGLYPH)
1390  ERR("Chain failed to generate a glyph.\n");
1391  }
1392  return new_index;
1393  }
1394  }
1395  else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
1396  {
1397  WORD backtrack_count, input_count, lookahead_count, substitution_count;
1398  int k;
1399  const GSUB_ChainContextSubstFormat3_1 *backtrack;
1401  const GSUB_ChainContextSubstFormat3_3 *lookahead;
1402  const GSUB_ChainContextSubstFormat3_4 *substitute;
1403  int new_index = GSUB_E_NOGLYPH;
1404 
1405  TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
1406 
1407  backtrack = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
1408  backtrack_count = GET_BE_WORD(backtrack->BacktrackGlyphCount);
1409  k = glyph_index + dirBacktrack * backtrack_count;
1410  if (k < 0 || k >= *glyph_count)
1411  continue;
1412 
1413  input = (const GSUB_ChainContextSubstFormat3_2 *)&backtrack->Coverage[backtrack_count];
1414  input_count = GET_BE_WORD(input->InputGlyphCount);
1415  k = glyph_index + write_dir * (input_count - 1);
1416  if (k < 0 || k >= *glyph_count)
1417  continue;
1418 
1419  lookahead = (const GSUB_ChainContextSubstFormat3_3 *)&input->Coverage[input_count];
1420  lookahead_count = GET_BE_WORD(lookahead->LookaheadGlyphCount);
1421  k = glyph_index + dirLookahead * (input_count + lookahead_count - 1);
1422  if (k < 0 || k >= *glyph_count)
1423  continue;
1424 
1425  substitute = (const GSUB_ChainContextSubstFormat3_4 *)&lookahead->Coverage[lookahead_count];
1426 
1427  for (k = 0; k < backtrack_count; ++k)
1428  {
1429  offset = GET_BE_WORD(backtrack->Coverage[k]);
1430  if (GSUB_is_glyph_covered((const BYTE *)ccsf1 + offset,
1431  glyphs[glyph_index + (dirBacktrack * (k + 1))]) == -1)
1432  break;
1433  }
1434  if (k != backtrack_count)
1435  continue;
1436  TRACE("Matched Backtrack\n");
1437 
1438  for (k = 0; k < input_count; ++k)
1439  {
1440  offset = GET_BE_WORD(input->Coverage[k]);
1441  if (GSUB_is_glyph_covered((const BYTE *)ccsf1 + offset,
1442  glyphs[glyph_index + (write_dir * k)]) == -1)
1443  break;
1444  }
1445  if (k != input_count)
1446  continue;
1447  TRACE("Matched IndexGlyphs\n");
1448 
1449  for (k = 0; k < lookahead_count; ++k)
1450  {
1451  offset = GET_BE_WORD(lookahead->Coverage[k]);
1452  if (GSUB_is_glyph_covered((const BYTE *)ccsf1 + offset,
1453  glyphs[glyph_index + (dirLookahead * (input_count + k))]) == -1)
1454  break;
1455  }
1456  if (k != lookahead_count)
1457  continue;
1458  TRACE("Matched LookAhead\n");
1459 
1460  substitution_count = GET_BE_WORD(substitute->SubstCount);
1461  for (k = 0; k < substitution_count; ++k)
1462  {
1463  unsigned int lookup_index = GET_BE_WORD(substitute->SubstLookupRecord[k].LookupListIndex);
1464  unsigned int sequence_index = GET_BE_WORD(substitute->SubstLookupRecord[k].SequenceIndex);
1465  unsigned int g = glyph_index + write_dir * sequence_index;
1466 
1467  if (g >= *glyph_count)
1468  {
1469  WARN("Skipping invalid sequence index %u (glyph index %u, write dir %d).\n",
1470  sequence_index, glyph_index, write_dir);
1471  continue;
1472  }
1473 
1474  TRACE("SUBST: %u -> %u %u.\n", k, sequence_index, lookup_index);
1475  new_index = GSUB_apply_lookup(lookup, lookup_index, glyphs, g, write_dir, glyph_count);
1476  if (new_index == GSUB_E_NOGLYPH)
1477  ERR("Chain failed to generate a glyph.\n");
1478  }
1479  return new_index;
1480  }
1481  }
1482  return GSUB_E_NOGLYPH;
1483 }
1484 
1485 static INT GSUB_apply_lookup(const OT_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1486 {
1487  int offset;
1488  enum gsub_lookup_type type;
1489  const OT_LookupTable *look;
1490 
1491  offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1492  look = (const OT_LookupTable*)((const BYTE*)lookup + offset);
1493  type = GET_BE_WORD(look->LookupType);
1494  TRACE("type %#x, flag %#x, subtables %u.\n", type,
1496 
1497  if (type == GSUB_LOOKUP_EXTENSION)
1498  {
1499  if (GET_BE_WORD(look->SubTableCount))
1500  {
1501  const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)look + GET_BE_WORD(look->SubTable[0]));
1502  if (GET_BE_WORD(ext->SubstFormat) == 1)
1503  {
1504  type = GET_BE_WORD(ext->ExtensionLookupType);
1505  TRACE("extension type %i\n",type);
1506  }
1507  else
1508  {
1509  FIXME("Unhandled Extension Substitution Format %i\n",GET_BE_WORD(ext->SubstFormat));
1510  }
1511  }
1512  else
1513  {
1514  WARN("lookup type is Extension Substitution but no extension subtable exists\n");
1515  }
1516  }
1517  switch(type)
1518  {
1519  case GSUB_LOOKUP_SINGLE:
1520  return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1521  case GSUB_LOOKUP_MULTIPLE:
1522  return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1523  case GSUB_LOOKUP_ALTERNATE:
1524  return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1525  case GSUB_LOOKUP_LIGATURE:
1526  return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1527  case GSUB_LOOKUP_CONTEXT:
1528  return GSUB_apply_ContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1530  return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1531  case GSUB_LOOKUP_EXTENSION:
1532  FIXME("Extension Substitution types not valid here\n");
1533  break;
1534  default:
1535  FIXME("Unhandled GSUB lookup type %#x.\n", type);
1536  }
1537  return GSUB_E_NOGLYPH;
1538 }
1539 
1540 int OpenType_apply_GSUB_lookup(const void *table, unsigned int lookup_index, WORD *glyphs,
1541  unsigned int glyph_index, int write_dir, int *glyph_count)
1542 {
1543  const GSUB_Header *header = (const GSUB_Header *)table;
1544  const OT_LookupList *lookup = (const OT_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1545 
1546  return GSUB_apply_lookup(lookup, lookup_index, glyphs, glyph_index, write_dir, glyph_count);
1547 }
1548 
1549 /**********
1550  * GPOS
1551  **********/
1552 static unsigned int GPOS_apply_lookup(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *otm,
1553  const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, const OT_LookupList *lookup,
1554  unsigned int lookup_index, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count,
1555  GOFFSET *goffset);
1556 
1557 static INT GPOS_get_device_table_value(const OT_DeviceTable *DeviceTable, WORD ppem)
1558 {
1559  static const WORD mask[3] = {3,0xf,0xff};
1560  if (DeviceTable && ppem >= GET_BE_WORD(DeviceTable->StartSize) && ppem <= GET_BE_WORD(DeviceTable->EndSize))
1561  {
1562  WORD format = GET_BE_WORD(DeviceTable->DeltaFormat);
1563  int index = ppem - GET_BE_WORD(DeviceTable->StartSize);
1564  int value;
1565 
1566  TRACE("device table, format %#x, index %i\n", format, index);
1567 
1568  if (format < 1 || format > 3)
1569  {
1570  WARN("invalid delta format %#x\n", format);
1571  return 0;
1572  }
1573 
1574  index = index << format;
1575  value = (DeviceTable->DeltaValue[index/sizeof(WORD)] << (index%sizeof(WORD)))&mask[format-1];
1576  TRACE("offset %i, value %i\n",index, value);
1577  if (value > mask[format-1]/2)
1578  value = -1 * ((mask[format-1]+1) - value);
1579  return value;
1580  }
1581  return 0;
1582 }
1583 
1584 static void GPOS_get_anchor_values(const void *table, POINT *pt, WORD ppem)
1585 {
1586  const GPOS_AnchorFormat1* anchor1 = (const GPOS_AnchorFormat1*)table;
1587 
1588  switch (GET_BE_WORD(anchor1->AnchorFormat))
1589  {
1590  case 1:
1591  {
1592  TRACE("Anchor Format 1\n");
1593  pt->x = (short)GET_BE_WORD(anchor1->XCoordinate);
1594  pt->y = (short)GET_BE_WORD(anchor1->YCoordinate);
1595  break;
1596  }
1597  case 2:
1598  {
1599  const GPOS_AnchorFormat2* anchor2 = (const GPOS_AnchorFormat2*)table;
1600  TRACE("Anchor Format 2\n");
1601  pt->x = (short)GET_BE_WORD(anchor2->XCoordinate);
1602  pt->y = (short)GET_BE_WORD(anchor2->YCoordinate);
1603  break;
1604  }
1605  case 3:
1606  {
1607  int offset;
1608  const GPOS_AnchorFormat3* anchor3 = (const GPOS_AnchorFormat3*)table;
1609  TRACE("Anchor Format 3\n");
1610  pt->x = (short)GET_BE_WORD(anchor3->XCoordinate);
1611  pt->y = (short)GET_BE_WORD(anchor3->YCoordinate);
1612  offset = GET_BE_WORD(anchor3->XDeviceTable);
1613  TRACE("ppem %i\n",ppem);
1614  if (offset)
1615  {
1616  const OT_DeviceTable* DeviceTableX = NULL;
1617  DeviceTableX = (const OT_DeviceTable*)((const BYTE*)anchor3 + offset);
1618  pt->x += GPOS_get_device_table_value(DeviceTableX, ppem);
1619  }
1620  offset = GET_BE_WORD(anchor3->YDeviceTable);
1621  if (offset)
1622  {
1623  const OT_DeviceTable* DeviceTableY = NULL;
1624  DeviceTableY = (const OT_DeviceTable*)((const BYTE*)anchor3 + offset);
1625  pt->y += GPOS_get_device_table_value(DeviceTableY, ppem);
1626  }
1627  break;
1628  }
1629  default:
1630  ERR("Unknown Anchor Format %i\n",GET_BE_WORD(anchor1->AnchorFormat));
1631  pt->x = 0;
1632  pt->y = 0;
1633  }
1634 }
1635 
1636 static void GPOS_convert_design_units_to_device(const OUTLINETEXTMETRICW *otm, const LOGFONTW *logfont,
1637  int desX, int desY, double *devX, double *devY)
1638 {
1640 
1641  TRACE("emHeight %i lfWidth %i\n",emHeight, logfont->lfWidth);
1642  *devX = (desX * emHeight) / (double)otm->otmEMSquare;
1643  *devY = (desY * emHeight) / (double)otm->otmEMSquare;
1644  if (logfont->lfWidth)
1645  FIXME("Font with lfWidth set not handled properly.\n");
1646 }
1647 
1649 {
1650  INT offset = 0;
1651  if (ValueFormat & 0x0001) { if (data) record->XPlacement = GET_BE_WORD(data[offset]); offset++; }
1652  if (ValueFormat & 0x0002) { if (data) record->YPlacement = GET_BE_WORD(data[offset]); offset++; }
1653  if (ValueFormat & 0x0004) { if (data) record->XAdvance = GET_BE_WORD(data[offset]); offset++; }
1654  if (ValueFormat & 0x0008) { if (data) record->YAdvance = GET_BE_WORD(data[offset]); offset++; }
1655  if (ValueFormat & 0x0010) { if (data) record->XPlaDevice = GET_BE_WORD(data[offset]); offset++; }
1656  if (ValueFormat & 0x0020) { if (data) record->YPlaDevice = GET_BE_WORD(data[offset]); offset++; }
1657  if (ValueFormat & 0x0040) { if (data) record->XAdvDevice = GET_BE_WORD(data[offset]); offset++; }
1658  if (ValueFormat & 0x0080) { if (data) record->YAdvDevice = GET_BE_WORD(data[offset]); offset++; }
1659  return offset;
1660 }
1661 
1662 static void GPOS_get_value_record_offsets(const BYTE *head, GPOS_ValueRecord *ValueRecord,
1663  WORD ValueFormat, unsigned int ppem, POINT *ptPlacement, POINT *ptAdvance)
1664 {
1665  if (ValueFormat & 0x0001) ptPlacement->x += (short)ValueRecord->XPlacement;
1666  if (ValueFormat & 0x0002) ptPlacement->y += (short)ValueRecord->YPlacement;
1667  if (ValueFormat & 0x0004) ptAdvance->x += (short)ValueRecord->XAdvance;
1668  if (ValueFormat & 0x0008) ptAdvance->y += (short)ValueRecord->YAdvance;
1669  if (ValueFormat & 0x0010) ptPlacement->x += GPOS_get_device_table_value((const OT_DeviceTable*)(head + ValueRecord->XPlaDevice), ppem);
1670  if (ValueFormat & 0x0020) ptPlacement->y += GPOS_get_device_table_value((const OT_DeviceTable*)(head + ValueRecord->YPlaDevice), ppem);
1671  if (ValueFormat & 0x0040) ptAdvance->x += GPOS_get_device_table_value((const OT_DeviceTable*)(head + ValueRecord->XAdvDevice), ppem);
1672  if (ValueFormat & 0x0080) ptAdvance->y += GPOS_get_device_table_value((const OT_DeviceTable*)(head + ValueRecord->YAdvDevice), ppem);
1673  if (ValueFormat & 0xFF00) FIXME("Unhandled Value Format %x\n",ValueFormat&0xFF00);
1674 }
1675 
1676 static const BYTE *GPOS_get_subtable(const OT_LookupTable *look, int index)
1677 {
1678  int offset = GET_BE_WORD(look->SubTable[index]);
1679 
1681  {
1682  const GPOS_ExtensionPosFormat1 *ext = (const GPOS_ExtensionPosFormat1 *)((const BYTE *)look + offset);
1683  if (GET_BE_WORD(ext->PosFormat) == 1)
1684  {
1685  offset += GET_BE_DWORD(ext->ExtensionOffset);
1686  }
1687  else
1688  {
1689  FIXME("Unhandled Extension Positioning Format %i\n",GET_BE_WORD(ext->PosFormat));
1690  }
1691  }
1692  return (const BYTE *)look + offset;
1693 }
1694 
1695 static void GPOS_apply_SingleAdjustment(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis,
1696  const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem,
1697  POINT *adjust, POINT *advance)
1698 {
1699  int j;
1700 
1701  TRACE("Single Adjustment Positioning Subtable\n");
1702 
1703  for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1704  {
1705  const GPOS_SinglePosFormat1 *spf1 = (const GPOS_SinglePosFormat1*)GPOS_get_subtable(look, j);
1706  WORD offset;
1707  if (GET_BE_WORD(spf1->PosFormat) == 1)
1708  {
1709  offset = GET_BE_WORD(spf1->Coverage);
1710  if (GSUB_is_glyph_covered((const BYTE*)spf1+offset, glyphs[glyph_index]) != -1)
1711  {
1712  GPOS_ValueRecord ValueRecord = {0,0,0,0,0,0,0,0};
1713  WORD ValueFormat = GET_BE_WORD(spf1->ValueFormat);
1714  GPOS_get_value_record(ValueFormat, spf1->Value, &ValueRecord);
1715  GPOS_get_value_record_offsets((const BYTE *)spf1, &ValueRecord, ValueFormat, ppem, adjust, advance);
1716  TRACE("Glyph Adjusted by %i,%i\n",ValueRecord.XPlacement,ValueRecord.YPlacement);
1717  }
1718  }
1719  else if (GET_BE_WORD(spf1->PosFormat) == 2)
1720  {
1721  int index;
1722  const GPOS_SinglePosFormat2 *spf2;
1723  spf2 = (const GPOS_SinglePosFormat2*)spf1;
1724  offset = GET_BE_WORD(spf2->Coverage);
1725  index = GSUB_is_glyph_covered((const BYTE*)spf2+offset, glyphs[glyph_index]);
1726  if (index != -1)
1727  {
1728  int size;
1729  GPOS_ValueRecord ValueRecord = {0,0,0,0,0,0,0,0};
1730  WORD ValueFormat = GET_BE_WORD(spf2->ValueFormat);
1731  size = GPOS_get_value_record(ValueFormat, spf2->Value, &ValueRecord);
1732  if (index > 0)
1733  {
1734  offset = size * index;
1735  GPOS_get_value_record(ValueFormat, &spf2->Value[offset], &ValueRecord);
1736  }
1737  GPOS_get_value_record_offsets((const BYTE *)spf2, &ValueRecord, ValueFormat, ppem, adjust, advance);
1738  TRACE("Glyph Adjusted by %i,%i\n",ValueRecord.XPlacement,ValueRecord.YPlacement);
1739  }
1740  }
1741  else
1742  FIXME("Single Adjustment Positioning: Format %i Unhandled\n",GET_BE_WORD(spf1->PosFormat));
1743  }
1744 }
1745 
1746 static void apply_pair_value( const void *pos_table, WORD val_fmt1, WORD val_fmt2, const WORD *pair,
1747  INT ppem, POINT *adjust, POINT *advance )
1748 {
1749  GPOS_ValueRecord val_rec1 = {0,0,0,0,0,0,0,0};
1750  GPOS_ValueRecord val_rec2 = {0,0,0,0,0,0,0,0};
1751  INT size;
1752 
1753  size = GPOS_get_value_record( val_fmt1, pair, &val_rec1 );
1754  GPOS_get_value_record( val_fmt2, pair + size, &val_rec2 );
1755 
1756  if (val_fmt1)
1757  {
1758  GPOS_get_value_record_offsets( pos_table, &val_rec1, val_fmt1, ppem, adjust, advance );
1759  TRACE( "Glyph 1 resulting cumulative offset is %s design units\n", wine_dbgstr_point(&adjust[0]) );
1760  TRACE( "Glyph 1 resulting cumulative advance is %s design units\n", wine_dbgstr_point(&advance[0]) );
1761  }
1762  if (val_fmt2)
1763  {
1764  GPOS_get_value_record_offsets( pos_table, &val_rec2, val_fmt2, ppem, adjust + 1, advance + 1 );
1765  TRACE( "Glyph 2 resulting cumulative offset is %s design units\n", wine_dbgstr_point(&adjust[1]) );
1766  TRACE( "Glyph 2 resulting cumulative advance is %s design units\n", wine_dbgstr_point(&advance[1]) );
1767  }
1768 }
1769 
1770 static int GPOS_apply_PairAdjustment(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis,
1771  const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem,
1772  POINT *adjust, POINT *advance)
1773 {
1774  int j;
1775  int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
1776 
1777  if (glyph_index + write_dir >= glyph_count)
1778  return 1;
1779 
1780  TRACE("Pair Adjustment Positioning Subtable\n");
1781 
1782  for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1783  {
1784  const GPOS_PairPosFormat1 *ppf1 = (const GPOS_PairPosFormat1*)GPOS_get_subtable(look, j);
1785  WORD offset;
1786  if (GET_BE_WORD(ppf1->PosFormat) == 1)
1787  {
1788  int index;
1789  WORD ValueFormat1 = GET_BE_WORD(ppf1->ValueFormat1);
1790  WORD ValueFormat2 = GET_BE_WORD(ppf1->ValueFormat2);
1791  INT val_fmt1_size = GPOS_get_value_record( ValueFormat1, NULL, NULL );
1792  INT val_fmt2_size = GPOS_get_value_record( ValueFormat2, NULL, NULL );
1793  offset = GET_BE_WORD(ppf1->Coverage);
1794  index = GSUB_is_glyph_covered((const BYTE*)ppf1+offset, glyphs[glyph_index]);
1795  if (index != -1 && index < GET_BE_WORD(ppf1->PairSetCount))
1796  {
1797  int k;
1798  int pair_count;
1799  const GPOS_PairSet *ps;
1800  const GPOS_PairValueRecord *pair_val_rec;
1802  ps = (const GPOS_PairSet*)((const BYTE*)ppf1+offset);
1803  pair_count = GET_BE_WORD(ps->PairValueCount);
1804  pair_val_rec = ps->PairValueRecord;
1805  for (k = 0; k < pair_count; k++)
1806  {
1807  WORD second_glyph = GET_BE_WORD(pair_val_rec->SecondGlyph);
1808  if (glyphs[glyph_index+write_dir] == second_glyph)
1809  {
1810  int next = 1;
1811  TRACE("Format 1: Found Pair %x,%x\n",glyphs[glyph_index],glyphs[glyph_index+write_dir]);
1812  apply_pair_value(ppf1, ValueFormat1, ValueFormat2,
1813  pair_val_rec->Value1, ppem, adjust, advance);
1814  if (ValueFormat2) next++;
1815  return next;
1816  }
1817  pair_val_rec = (const GPOS_PairValueRecord *)(pair_val_rec->Value1 + val_fmt1_size + val_fmt2_size);
1818  }
1819  }
1820  }
1821  else if (GET_BE_WORD(ppf1->PosFormat) == 2)
1822  {
1823  const GPOS_PairPosFormat2 *ppf2 = (const GPOS_PairPosFormat2*)ppf1;
1824  int index;
1825  WORD ValueFormat1 = GET_BE_WORD( ppf2->ValueFormat1 );
1826  WORD ValueFormat2 = GET_BE_WORD( ppf2->ValueFormat2 );
1827  INT val_fmt1_size = GPOS_get_value_record( ValueFormat1, NULL, NULL );
1828  INT val_fmt2_size = GPOS_get_value_record( ValueFormat2, NULL, NULL );
1829  WORD class1_count = GET_BE_WORD( ppf2->Class1Count );
1830  WORD class2_count = GET_BE_WORD( ppf2->Class2Count );
1831 
1832  offset = GET_BE_WORD( ppf2->Coverage );
1833  index = GSUB_is_glyph_covered( (const BYTE*)ppf2 + offset, glyphs[glyph_index] );
1834  if (index != -1)
1835  {
1836  WORD class1, class2;
1837  class1 = OT_get_glyph_class( (const BYTE *)ppf2 + GET_BE_WORD(ppf2->ClassDef1), glyphs[glyph_index] );
1838  class2 = OT_get_glyph_class( (const BYTE *)ppf2 + GET_BE_WORD(ppf2->ClassDef2), glyphs[glyph_index + write_dir] );
1839  if (class1 < class1_count && class2 < class2_count)
1840  {
1841  const WORD *pair_val = ppf2->Class1Record + (class1 * class2_count + class2) * (val_fmt1_size + val_fmt2_size);
1842  int next = 1;
1843 
1844  TRACE( "Format 2: Found Pair %x,%x\n", glyphs[glyph_index], glyphs[glyph_index + write_dir] );
1845 
1846  apply_pair_value(ppf2, ValueFormat1, ValueFormat2, pair_val, ppem, adjust, advance);
1847  if (ValueFormat2) next++;
1848  return next;
1849  }
1850  }
1851  }
1852  else
1853  FIXME("Pair Adjustment Positioning: Format %i Unhandled\n",GET_BE_WORD(ppf1->PosFormat));
1854  }
1855  return 1;
1856 }
1857 
1858 static void GPOS_apply_CursiveAttachment(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis,
1859  const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *pt)
1860 {
1861  int j;
1862  int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
1863 
1864  if (glyph_index + write_dir >= glyph_count)
1865  return;
1866 
1867  TRACE("Cursive Attachment Positioning Subtable\n");
1868 
1869  for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1870  {
1871  const GPOS_CursivePosFormat1 *cpf1 = (const GPOS_CursivePosFormat1 *)GPOS_get_subtable(look, j);
1872  if (GET_BE_WORD(cpf1->PosFormat) == 1)
1873  {
1874  int index_exit, index_entry;
1875  WORD offset = GET_BE_WORD( cpf1->Coverage );
1876  index_exit = GSUB_is_glyph_covered((const BYTE*)cpf1+offset, glyphs[glyph_index]);
1877  if (index_exit != -1 && cpf1->EntryExitRecord[index_exit].ExitAnchor!= 0)
1878  {
1879  index_entry = GSUB_is_glyph_covered((const BYTE*)cpf1+offset, glyphs[glyph_index+write_dir]);
1880  if (index_entry != -1 && cpf1->EntryExitRecord[index_entry].EntryAnchor != 0)
1881  {
1882  POINT exit_pt, entry_pt;
1883  offset = GET_BE_WORD(cpf1->EntryExitRecord[index_exit].ExitAnchor);
1884  GPOS_get_anchor_values((const BYTE*)cpf1 + offset, &exit_pt, ppem);
1885  offset = GET_BE_WORD(cpf1->EntryExitRecord[index_entry].EntryAnchor);
1886  GPOS_get_anchor_values((const BYTE*)cpf1 + offset, &entry_pt, ppem);
1887  TRACE("Found linkage %x[%s] %x[%s]\n",glyphs[glyph_index], wine_dbgstr_point(&exit_pt), glyphs[glyph_index+write_dir], wine_dbgstr_point(&entry_pt));
1888  pt->x = entry_pt.x - exit_pt.x;
1889  pt->y = entry_pt.y - exit_pt.y;
1890  return;
1891  }
1892  }
1893  }
1894  else
1895  FIXME("Cursive Attachment Positioning: Format %i Unhandled\n",GET_BE_WORD(cpf1->PosFormat));
1896  }
1897  return;
1898 }
1899 
1900 static int GPOS_apply_MarkToBase(const ScriptCache *script_cache, const OT_LookupTable *look,
1901  const SCRIPT_ANALYSIS *analysis, const WORD *glyphs, unsigned int glyph_index,
1902  unsigned int glyph_count, unsigned int ppem, POINT *pt)
1903 {
1904  int j;
1905  int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
1906  const void *glyph_class_table = NULL;
1907  int rc = -1;
1908 
1909  if (script_cache->GDEF_Table)
1910  {
1911  const GDEF_Header *header = script_cache->GDEF_Table;
1912  WORD offset = GET_BE_WORD( header->GlyphClassDef );
1913  if (offset)
1914  glyph_class_table = (const BYTE *)script_cache->GDEF_Table + offset;
1915  }
1916 
1917  TRACE("MarkToBase Attachment Positioning Subtable\n");
1918 
1919  for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1920  {
1921  const GPOS_MarkBasePosFormat1 *mbpf1 = (const GPOS_MarkBasePosFormat1 *)GPOS_get_subtable(look, j);
1922  if (GET_BE_WORD(mbpf1->PosFormat) == 1)
1923  {
1924  int offset = GET_BE_WORD(mbpf1->MarkCoverage);
1925  int mark_index;
1926  mark_index = GSUB_is_glyph_covered((const BYTE*)mbpf1+offset, glyphs[glyph_index]);
1927  if (mark_index != -1)
1928  {
1929  int base_index;
1930  int base_glyph = glyph_index - write_dir;
1931 
1932  if (glyph_class_table)
1933  {
1934  while (OT_get_glyph_class(glyph_class_table, glyphs[base_glyph]) == MarkGlyph && base_glyph > 0 && base_glyph < glyph_count)
1935  base_glyph -= write_dir;
1936  }
1937 
1938  offset = GET_BE_WORD(mbpf1->BaseCoverage);
1939  base_index = GSUB_is_glyph_covered((const BYTE*)mbpf1+offset, glyphs[base_glyph]);
1940  if (base_index != -1)
1941  {
1942  const GPOS_MarkArray *ma;
1943  const GPOS_MarkRecord *mr;
1944  const GPOS_BaseArray *ba;
1945  const GPOS_BaseRecord *br;
1946  int mark_class;
1947  int class_count = GET_BE_WORD(mbpf1->ClassCount);
1948  int baserecord_size;
1949  POINT base_pt;
1950  POINT mark_pt;
1951  TRACE("Mark %x(%i) and base %x(%i)\n",glyphs[glyph_index], mark_index, glyphs[base_glyph], base_index);
1952  offset = GET_BE_WORD(mbpf1->MarkArray);
1953  ma = (const GPOS_MarkArray*)((const BYTE*)mbpf1 + offset);
1954  if (mark_index > GET_BE_WORD(ma->MarkCount))
1955  {
1956  ERR("Mark index exceeded mark count\n");
1957  return -1;
1958  }
1959  mr = &ma->MarkRecord[mark_index];
1960  mark_class = GET_BE_WORD(mr->Class);
1961  TRACE("Mark Class %i total classes %i\n",mark_class,class_count);
1962  offset = GET_BE_WORD(mbpf1->BaseArray);
1963  ba = (const GPOS_BaseArray*)((const BYTE*)mbpf1 + offset);
1964  baserecord_size = class_count * sizeof(WORD);
1965  br = (const GPOS_BaseRecord*)((const BYTE*)ba + sizeof(WORD) + (baserecord_size * base_index));
1966  offset = GET_BE_WORD(br->BaseAnchor[mark_class]);
1967  GPOS_get_anchor_values((const BYTE*)ba + offset, &base_pt, ppem);
1968  offset = GET_BE_WORD(mr->MarkAnchor);
1969  GPOS_get_anchor_values((const BYTE*)ma + offset, &mark_pt, ppem);
1970  TRACE("Offset on base is %s design units\n",wine_dbgstr_point(&base_pt));
1971  TRACE("Offset on mark is %s design units\n",wine_dbgstr_point(&mark_pt));
1972  pt->x += base_pt.x - mark_pt.x;
1973  pt->y += base_pt.y - mark_pt.y;
1974  TRACE("Resulting cumulative offset is %s design units\n",wine_dbgstr_point(pt));
1975  rc = base_glyph;
1976  }
1977  }
1978  }
1979  else
1980  FIXME("Unhandled Mark To Base Format %i\n",GET_BE_WORD(mbpf1->PosFormat));
1981  }
1982  return rc;
1983 }
1984 
1985 static void GPOS_apply_MarkToLigature(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis,
1986  const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *pt)
1987 {
1988  int j;
1989  int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
1990 
1991  TRACE("MarkToLigature Attachment Positioning Subtable\n");
1992 
1993  for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
1994  {
1995  const GPOS_MarkLigPosFormat1 *mlpf1 = (const GPOS_MarkLigPosFormat1 *)GPOS_get_subtable(look, j);
1996  if (GET_BE_WORD(mlpf1->PosFormat) == 1)
1997  {
1998  int offset = GET_BE_WORD(mlpf1->MarkCoverage);
1999  int mark_index;
2000  mark_index = GSUB_is_glyph_covered((const BYTE*)mlpf1+offset, glyphs[glyph_index]);
2001  if (mark_index != -1)
2002  {
2003  int ligature_index;
2005  ligature_index = GSUB_is_glyph_covered((const BYTE*)mlpf1+offset, glyphs[glyph_index - write_dir]);
2006  if (ligature_index != -1)
2007  {
2008  const GPOS_MarkArray *ma;
2009  const GPOS_MarkRecord *mr;
2010 
2011  const GPOS_LigatureArray *la;
2012  const GPOS_LigatureAttach *lt;
2013  int mark_class;
2014  int class_count = GET_BE_WORD(mlpf1->ClassCount);
2015  int component_count;
2016  int component_size;
2017  int i;
2018  POINT ligature_pt;
2019  POINT mark_pt;
2020 
2021  TRACE("Mark %x(%i) and ligature %x(%i)\n",glyphs[glyph_index], mark_index, glyphs[glyph_index - write_dir], ligature_index);
2022  offset = GET_BE_WORD(mlpf1->MarkArray);
2023  ma = (const GPOS_MarkArray*)((const BYTE*)mlpf1 + offset);
2024  if (mark_index > GET_BE_WORD(ma->MarkCount))
2025  {
2026  ERR("Mark index exceeded mark count\n");
2027  return;
2028  }
2029  mr = &ma->MarkRecord[mark_index];
2030  mark_class = GET_BE_WORD(mr->Class);
2031  TRACE("Mark Class %i total classes %i\n",mark_class,class_count);
2032  offset = GET_BE_WORD(mlpf1->LigatureArray);
2033  la = (const GPOS_LigatureArray*)((const BYTE*)mlpf1 + offset);
2034  if (ligature_index > GET_BE_WORD(la->LigatureCount))
2035  {
2036  ERR("Ligature index exceeded ligature count\n");
2037  return;
2038  }
2039  offset = GET_BE_WORD(la->LigatureAttach[ligature_index]);
2040  lt = (const GPOS_LigatureAttach*)((const BYTE*)la + offset);
2041 
2043  component_size = class_count * sizeof(WORD);
2044  offset = 0;
2045  for (i = 0; i < component_count && !offset; i++)
2046  {
2047  int k;
2048  const GPOS_ComponentRecord *cr = (const GPOS_ComponentRecord*)((const BYTE*)lt->ComponentRecord + (component_size * i));
2049  for (k = 0; k < class_count && !offset; k++)
2051  cr = (const GPOS_ComponentRecord*)((const BYTE*)cr + component_size);
2052  }
2053  if (!offset)
2054  {
2055  ERR("Failed to find available ligature connection point\n");
2056  return;
2057  }
2058 
2059  GPOS_get_anchor_values((const BYTE*)lt + offset, &ligature_pt, ppem);
2060  offset = GET_BE_WORD(mr->MarkAnchor);
2061  GPOS_get_anchor_values((const BYTE*)ma + offset, &mark_pt, ppem);
2062  TRACE("Offset on ligature is %s design units\n",wine_dbgstr_point(&ligature_pt));
2063  TRACE("Offset on mark is %s design units\n",wine_dbgstr_point(&mark_pt));
2064  pt->x += ligature_pt.x - mark_pt.x;
2065  pt->y += ligature_pt.y - mark_pt.y;
2066  TRACE("Resulting cumulative offset is %s design units\n",wine_dbgstr_point(pt));
2067  }
2068  }
2069  }
2070  else
2071  FIXME("Unhandled Mark To Ligature Format %i\n",GET_BE_WORD(mlpf1->PosFormat));
2072  }
2073 }
2074 
2075 static BOOL GPOS_apply_MarkToMark(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis,
2076  const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *pt)
2077 {
2078  int j;
2079  BOOL rc = FALSE;
2080  int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
2081 
2082  TRACE("MarkToMark Attachment Positioning Subtable\n");
2083 
2084  for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
2085  {
2086  const GPOS_MarkMarkPosFormat1 *mmpf1 = (const GPOS_MarkMarkPosFormat1 *)GPOS_get_subtable(look, j);
2087  if (GET_BE_WORD(mmpf1->PosFormat) == 1)
2088  {
2089  int offset = GET_BE_WORD(mmpf1->Mark1Coverage);
2090  int mark_index;
2091  mark_index = GSUB_is_glyph_covered((const BYTE*)mmpf1+offset, glyphs[glyph_index]);
2092  if (mark_index != -1)
2093  {
2094  int mark2_index;
2095  offset = GET_BE_WORD(mmpf1->Mark2Coverage);
2096  mark2_index = GSUB_is_glyph_covered((const BYTE*)mmpf1+offset, glyphs[glyph_index - write_dir]);
2097  if (mark2_index != -1)
2098  {
2099  const GPOS_MarkArray *ma;
2100  const GPOS_MarkRecord *mr;
2101  const GPOS_Mark2Array *m2a;
2102  const GPOS_Mark2Record *m2r;
2103  int mark_class;
2104  int class_count = GET_BE_WORD(mmpf1->ClassCount);
2105  int mark2record_size;
2106  POINT mark2_pt;
2107  POINT mark_pt;
2108  TRACE("Mark %x(%i) and Mark2 %x(%i)\n",glyphs[glyph_index], mark_index, glyphs[glyph_index - write_dir], mark2_index);
2109  offset = GET_BE_WORD(mmpf1->Mark1Array);
2110  ma = (const GPOS_MarkArray*)((const BYTE*)mmpf1 + offset);
2111  if (mark_index > GET_BE_WORD(ma->MarkCount))
2112  {
2113  ERR("Mark index exceeded mark count\n");
2114  return FALSE;
2115  }
2116  mr = &ma->MarkRecord[mark_index];
2117  mark_class = GET_BE_WORD(mr->Class);
2118  TRACE("Mark Class %i total classes %i\n",mark_class,class_count);
2119  offset = GET_BE_WORD(mmpf1->Mark2Array);
2120  m2a = (const GPOS_Mark2Array*)((const BYTE*)mmpf1 + offset);
2121  mark2record_size = class_count * sizeof(WORD);
2122  m2r = (const GPOS_Mark2Record*)((const BYTE*)m2a + sizeof(WORD) + (mark2record_size * mark2_index));
2123  offset = GET_BE_WORD(m2r->Mark2Anchor[mark_class]);
2124  GPOS_get_anchor_values((const BYTE*)m2a + offset, &mark2_pt, ppem);
2125  offset = GET_BE_WORD(mr->MarkAnchor);
2126  GPOS_get_anchor_values((const BYTE*)ma + offset, &mark_pt, ppem);
2127  TRACE("Offset on mark2 is %s design units\n",wine_dbgstr_point(&mark2_pt));
2128  TRACE("Offset on mark is %s design units\n",wine_dbgstr_point(&mark_pt));
2129  pt->x += mark2_pt.x - mark_pt.x;
2130  pt->y += mark2_pt.y - mark_pt.y;
2131  TRACE("Resulting cumulative offset is %s design units\n",wine_dbgstr_point(pt));
2132  rc = TRUE;
2133  }
2134  }
2135  }
2136  else
2137  FIXME("Unhandled Mark To Mark Format %i\n",GET_BE_WORD(mmpf1->PosFormat));
2138  }
2139  return rc;
2140 }
2141 
2142 static unsigned int GPOS_apply_ContextPos(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *otm,
2143  const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, const OT_LookupList *lookup,
2144  const OT_LookupTable *look, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count,
2145  GOFFSET *goffset)
2146 {
2147  int j;
2148  int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
2149 
2150  TRACE("Contextual Positioning Subtable\n");
2151 
2152  for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
2153  {
2155 
2156  if (GET_BE_WORD(cpf2->PosFormat) == 1)
2157  {
2158  static int once;
2159  if (!once++)
2160  FIXME(" TODO: subtype 1\n");
2161  continue;
2162  }
2163  else if (GET_BE_WORD(cpf2->PosFormat) == 2)
2164  {
2165  WORD offset = GET_BE_WORD(cpf2->Coverage);
2166  int index;
2167 
2168  TRACE("Contextual Positioning Subtable: Format 2\n");
2169 
2170  index = GSUB_is_glyph_covered((const BYTE*)cpf2+offset, glyphs[glyph_index]);
2171  TRACE("Coverage index %i\n",index);
2172  if (index != -1)
2173  {
2174  int k, count, class;
2175  const GPOS_PosClassSet *pcs;
2176  const void *glyph_class_table = NULL;
2177 
2178  offset = GET_BE_WORD(cpf2->ClassDef);
2179  glyph_class_table = (const BYTE *)cpf2 + offset;
2180 
2181  class = OT_get_glyph_class(glyph_class_table,glyphs[glyph_index]);
2182 
2183  offset = GET_BE_WORD(cpf2->PosClassSet[class]);
2184  if (offset == 0)
2185  {
2186  TRACE("No class rule table for class %i\n",class);
2187  continue;
2188  }
2189  pcs = (const GPOS_PosClassSet*)((const BYTE*)cpf2+offset);
2191  TRACE("PosClassSet has %i members\n",count);
2192  for (k = 0; k < count; k++)
2193  {
2194  const GPOS_PosClassRule_1 *pr;
2195  const GPOS_PosClassRule_2 *pr_2;
2196  unsigned int g;
2197  int g_count, l;
2198 
2199  offset = GET_BE_WORD(pcs->PosClassRule[k]);
2200  pr = (const GPOS_PosClassRule_1*)((const BYTE*)pcs+offset);
2201  g_count = GET_BE_WORD(pr->GlyphCount);
2202  TRACE("PosClassRule has %i glyphs classes\n",g_count);
2203 
2204  g = glyph_index + write_dir * (g_count - 1);
2205  if (g >= glyph_count)
2206  continue;
2207 
2208  for (l = 0; l < g_count-1; l++)
2209  {
2210  int g_class = OT_get_glyph_class(glyph_class_table, glyphs[glyph_index + (write_dir * (l+1))]);
2211  if (g_class != GET_BE_WORD(pr->Class[l])) break;
2212  }
2213 
2214  if (l < g_count-1)
2215  {
2216  TRACE("Rule does not match\n");
2217  continue;
2218  }
2219 
2220  TRACE("Rule matches\n");
2221  pr_2 = (const GPOS_PosClassRule_2 *)&pr->Class[g_count - 1];
2222 
2223  for (l = 0; l < GET_BE_WORD(pr->PosCount); l++)
2224  {
2225  unsigned int lookup_index = GET_BE_WORD(pr_2->PosLookupRecord[l].LookupListIndex);
2226  unsigned int sequence_index = GET_BE_WORD(pr_2->PosLookupRecord[l].SequenceIndex);
2227 
2228  g = glyph_index + write_dir * sequence_index;
2229  if (g >= glyph_count)
2230  {
2231  WARN("Invalid sequence index %u (glyph index %u, write dir %d).\n",
2232  sequence_index, glyph_index, write_dir);
2233  continue;
2234  }
2235 
2236  TRACE("Position: %u -> %u %u.\n", l, sequence_index, lookup_index);
2237 
2238  GPOS_apply_lookup(script_cache, otm, logfont, analysis, advance,
2239  lookup, lookup_index, glyphs, g, glyph_count, goffset);
2240  }
2241  return 1;
2242  }
2243  }
2244 
2245  TRACE("Not covered\n");
2246  continue;
2247  }
2248  else if (GET_BE_WORD(cpf2->PosFormat) == 3)
2249  {
2250  static int once;
2251  if (!once++)
2252  FIXME(" TODO: subtype 3\n");
2253  continue;
2254  }
2255  else
2256  FIXME("Unhandled Contextual Positioning Format %i\n",GET_BE_WORD(cpf2->PosFormat));
2257  }
2258  return 1;
2259 }
2260 
2261 static unsigned int GPOS_apply_ChainContextPos(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *otm,
2262  const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, const OT_LookupList *lookup,
2263  const OT_LookupTable *look, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count,
2264  GOFFSET *goffset)
2265 {
2266  int j;
2267  int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
2268 
2269  TRACE("Chaining Contextual Positioning Subtable\n");
2270 
2271  for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
2272  {
2273  int offset;
2275  int dirLookahead = write_dir;
2276  int dirBacktrack = -1 * write_dir;
2277 
2278  if (GET_BE_WORD(backtrack->PosFormat) == 1)
2279  {
2280  static int once;
2281  if (!once++)
2282  FIXME(" TODO: subtype 1 (Simple Chaining Context Glyph Positioning)\n");
2283  continue;
2284  }
2285  else if (GET_BE_WORD(backtrack->PosFormat) == 2)
2286  {
2287  static int once;
2288  if (!once++)
2289  FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Positioning)\n");
2290  continue;
2291  }
2292  else if (GET_BE_WORD(backtrack->PosFormat) == 3)
2293  {
2294  WORD backtrack_count, input_count, lookahead_count, positioning_count;
2295  int k;
2297  const GPOS_ChainContextPosFormat3_3 *lookahead;
2298  const GPOS_ChainContextPosFormat3_4 *positioning;
2299 
2300  TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Positioning)\n");
2301 
2302  backtrack_count = GET_BE_WORD(backtrack->BacktrackGlyphCount);
2303  k = glyph_index + dirBacktrack * backtrack_count;
2304  if (k < 0 || k >= glyph_count)
2305  continue;
2306 
2307  input = (const GPOS_ChainContextPosFormat3_2 *)&backtrack->Coverage[backtrack_count];
2308  input_count = GET_BE_WORD(input->InputGlyphCount);
2309  k = glyph_index + write_dir * (input_count - 1);
2310  if (k < 0 || k >= glyph_count)
2311  continue;
2312 
2313  lookahead = (const GPOS_ChainContextPosFormat3_3 *)&input->Coverage[input_count];
2314  lookahead_count = GET_BE_WORD(lookahead->LookaheadGlyphCount);
2315  k = glyph_index + dirLookahead * (input_count + lookahead_count - 1);
2316  if (k < 0 || k >= glyph_count)
2317  continue;
2318 
2319  positioning = (const GPOS_ChainContextPosFormat3_4 *)&lookahead->Coverage[lookahead_count];
2320 
2321  for (k = 0; k < backtrack_count; ++k)
2322  {
2323  offset = GET_BE_WORD(backtrack->Coverage[k]);
2324  if (GSUB_is_glyph_covered((const BYTE *)backtrack + offset,
2325  glyphs[glyph_index + (dirBacktrack * (k + 1))]) == -1)
2326  break;
2327  }
2328  if (k != backtrack_count)
2329  continue;
2330  TRACE("Matched Backtrack\n");
2331 
2332  for (k = 0; k < input_count; ++k)
2333  {
2334  offset = GET_BE_WORD(input->Coverage[k]);
2335  if (GSUB_is_glyph_covered((const BYTE *)backtrack + offset,
2336  glyphs[glyph_index + (write_dir * k)]) == -1)
2337  break;
2338  }
2339  if (k != input_count)
2340  continue;
2341  TRACE("Matched IndexGlyphs\n");
2342 
2343  for (k = 0; k < lookahead_count; ++k)
2344  {
2345  offset = GET_BE_WORD(lookahead->Coverage[k]);
2346  if (GSUB_is_glyph_covered((const BYTE *)backtrack + offset,
2347  glyphs[glyph_index + (dirLookahead * (input_count + k))]) == -1)
2348  break;
2349  }
2350  if (k != lookahead_count)
2351  continue;
2352  TRACE("Matched LookAhead\n");
2353 
2354  if (!(positioning_count = GET_BE_WORD(positioning->PosCount)))
2355  return 1;
2356 
2357  for (k = 0; k < positioning_count; ++k)
2358  {
2359  unsigned int lookup_index = GET_BE_WORD(positioning->PosLookupRecord[k].LookupListIndex);
2360  unsigned int sequence_index = GET_BE_WORD(positioning->PosLookupRecord[k].SequenceIndex);
2361  unsigned int g = glyph_index + write_dir * sequence_index;
2362 
2363  if (g >= glyph_count)
2364  {
2365  WARN("Skipping invalid sequence index %u (glyph index %u, write dir %d).\n",
2366  sequence_index, glyph_index, write_dir);
2367  continue;
2368  }
2369 
2370  TRACE("Position: %u -> %u %u.\n", k, sequence_index, lookup_index);
2371  GPOS_apply_lookup(script_cache, otm, logfont, analysis, advance, lookup, lookup_index,
2372  glyphs, g, glyph_count, goffset);
2373  }
2374  return input_count + lookahead_count;
2375  }
2376  else
2377  FIXME("Unhandled Chaining Contextual Positioning Format %#x.\n", GET_BE_WORD(backtrack->PosFormat));
2378  }
2379  return 1;
2380 }
2381 
2382 static unsigned int GPOS_apply_lookup(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *lpotm,
2383  const LOGFONTW *lplogfont, const SCRIPT_ANALYSIS *analysis, int *piAdvance, const OT_LookupList *lookup,
2384  unsigned int lookup_index, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count,
2385  GOFFSET *pGoffset)
2386 {
2387  int offset;
2388  const OT_LookupTable *look;
2390  enum gpos_lookup_type type;
2391 
2392  offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
2393  look = (const OT_LookupTable*)((const BYTE*)lookup + offset);
2394  type = GET_BE_WORD(look->LookupType);
2395  TRACE("type %#x, flag %#x, subtables %u.\n", type,
2397 
2399  {
2400  if (GET_BE_WORD(look->SubTableCount))
2401  {
2402  const GPOS_ExtensionPosFormat1 *ext = (const GPOS_ExtensionPosFormat1 *)((const BYTE *)look + GET_BE_WORD(look->SubTable[0]));
2403  if (GET_BE_WORD(ext->PosFormat) == 1)
2404  {
2405  type = GET_BE_WORD(ext->ExtensionLookupType);
2406  TRACE("extension type %i\n",type);
2407  }
2408  else
2409  {
2410  FIXME("Unhandled Extension Positioning Format %i\n",GET_BE_WORD(ext->PosFormat));
2411  }
2412  }
2413  else
2414  {
2415  WARN("lookup type is Extension Positioning but no extension subtable exists\n");
2416  }
2417  }
2418  switch (type)
2419  {
2421  {
2422  double devX, devY;
2423  POINT adjust = {0,0};
2424  POINT advance = {0,0};
2425  GPOS_apply_SingleAdjustment(look, analysis, glyphs, glyph_index, glyph_count, ppem, &adjust, &advance);
2426  if (adjust.x || adjust.y)
2427  {
2428  GPOS_convert_design_units_to_device(lpotm, lplogfont, adjust.x, adjust.y, &devX, &devY);
2429  pGoffset[glyph_index].du += round(devX);
2430  pGoffset[glyph_index].dv += round(devY);
2431  }
2432  if (advance.x || advance.y)
2433  {
2434  GPOS_convert_design_units_to_device(lpotm, lplogfont, advance.x, advance.y, &devX, &devY);
2435  piAdvance[glyph_index] += round(devX);
2436  if (advance.y)
2437  FIXME("Unhandled adjustment to Y advancement\n");
2438  }
2439  break;
2440  }
2441 
2443  {
2444  POINT advance[2]= {{0,0},{0,0}};
2445  POINT adjust[2]= {{0,0},{0,0}};
2446  double devX, devY;
2447  int index_offset;
2448  int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
2449  int offset_sign = (analysis->fRTL && analysis->fLogicalOrder) ? -1 : 1;
2450 
2451  index_offset = GPOS_apply_PairAdjustment(look, analysis, glyphs,
2452  glyph_index, glyph_count, ppem, adjust, advance);
2453  if (adjust[0].x || adjust[0].y)
2454  {
2455  GPOS_convert_design_units_to_device(lpotm, lplogfont, adjust[0].x, adjust[0].y, &devX, &devY);
2456  pGoffset[glyph_index].du += round(devX) * offset_sign;
2457  pGoffset[glyph_index].dv += round(devY);
2458  }
2459  if (advance[0].x || advance[0].y)
2460  {
2461  GPOS_convert_design_units_to_device(lpotm, lplogfont, advance[0].x, advance[0].y, &devX, &devY);
2462  piAdvance[glyph_index] += round(devX);
2463  }
2464  if (adjust[1].x || adjust[1].y)
2465  {
2466  GPOS_convert_design_units_to_device(lpotm, lplogfont, adjust[1].x, adjust[1].y, &devX, &devY);
2467  pGoffset[glyph_index + write_dir].du += round(devX) * offset_sign;
2468  pGoffset[glyph_index + write_dir].dv += round(devY);
2469  }
2470  if (advance[1].x || advance[1].y)
2471  {
2472  GPOS_convert_design_units_to_device(lpotm, lplogfont, advance[1].x, advance[1].y, &devX, &devY);
2473  piAdvance[glyph_index + write_dir] += round(devX);
2474  }
2475  return index_offset;
2476  }
2477 
2479  {
2480  POINT desU = {0,0};
2481  double devX, devY;
2482  int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
2483 
2484  GPOS_apply_CursiveAttachment(look, analysis, glyphs, glyph_index, glyph_count, ppem, &desU);
2485  if (desU.x || desU.y)
2486  {
2487  GPOS_convert_design_units_to_device(lpotm, lplogfont, desU.x, desU.y, &devX, &devY);
2488  /* Windows does not appear to apply X offsets here */
2489  pGoffset[glyph_index].dv = round(devY) + pGoffset[glyph_index+write_dir].dv;
2490  }
2491  break;
2492  }
2493 
2495  {
2496  double devX, devY;
2497  POINT desU = {0,0};
2498  int base_index = GPOS_apply_MarkToBase(script_cache, look, analysis,
2499  glyphs, glyph_index, glyph_count, ppem, &desU);
2500  if (base_index != -1)
2501  {
2502  GPOS_convert_design_units_to_device(lpotm, lplogfont, desU.x, desU.y, &devX, &devY);
2503  if (!analysis->fRTL) pGoffset[glyph_index].du = round(devX) - piAdvance[base_index];
2504  else
2505  {
2506  if (analysis->fLogicalOrder) devX *= -1;
2507  pGoffset[glyph_index].du = round(devX);
2508  }
2509  pGoffset[glyph_index].dv = round(devY);
2510  }
2511  break;
2512  }
2513 
2515  {
2516  double devX, devY;
2517  POINT desU = {0,0};
2518  GPOS_apply_MarkToLigature(look, analysis, glyphs, glyph_index, glyph_count, ppem, &desU);
2519  if (desU.x || desU.y)
2520  {
2521  GPOS_convert_design_units_to_device(lpotm, lplogfont, desU.x, desU.y, &devX, &devY);
2522  pGoffset[glyph_index].du = (round(devX) - piAdvance[glyph_index-1]);
2523  pGoffset[glyph_index].dv = round(devY);
2524  }
2525  break;
2526  }
2527 
2529  {
2530  double devX, devY;
2531  POINT desU = {0,0};
2532  int write_dir = (analysis->fRTL && !analysis->fLogicalOrder) ? -1 : 1;
2533  if (GPOS_apply_MarkToMark(look, analysis, glyphs, glyph_index, glyph_count, ppem, &desU))
2534  {
2535  GPOS_convert_design_units_to_device(lpotm, lplogfont, desU.x, desU.y, &devX, &devY);
2536  if (analysis->fRTL && analysis->fLogicalOrder) devX *= -1;
2537  pGoffset[glyph_index].du = round(devX) + pGoffset[glyph_index - write_dir].du;
2538  pGoffset[glyph_index].dv = round(devY) + pGoffset[glyph_index - write_dir].dv;
2539  }
2540  break;
2541  }
2542 
2544  return GPOS_apply_ContextPos(script_cache, lpotm, lplogfont, analysis, piAdvance,
2545  lookup, look, glyphs, glyph_index, glyph_count, pGoffset);
2546 
2548  return GPOS_apply_ChainContextPos(script_cache, lpotm, lplogfont, analysis, piAdvance,
2549  lookup, look, glyphs, glyph_index, glyph_count, pGoffset);
2550 
2551  default:
2552  FIXME("Unhandled GPOS lookup type %#x.\n", type);
2553  }
2554  return 1;
2555 }
2556 
2557 unsigned int OpenType_apply_GPOS_lookup(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *otm,
2558  const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, unsigned int lookup_index,
2559  const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, GOFFSET *goffset)
2560 {
2561  const GPOS_Header *header = (const GPOS_Header *)script_cache->GPOS_Table;
2562  const OT_LookupList *lookup = (const OT_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
2563 
2564  return GPOS_apply_lookup(script_cache, otm, logfont, analysis, advance, lookup,
2565  lookup_index, glyphs, glyph_index, glyph_count, goffset);
2566 }
2567 
2569 {
2571 
2572  if (!usp10_array_reserve((void **)&script_cache->scripts, &script_cache->scripts_size,
2573  script_cache->script_count + 1, sizeof(*script_cache->scripts)))
2574  {
2575  ERR("Failed to grow scripts array.\n");
2576  return NULL;
2577  }
2578 
2579  script = &script_cache->scripts[script_cache->script_count++];
2580  script->tag = tag;
2581 
2582  return script;
2583 }
2584 
2586 {
2587  size_t i;
2588 
2589  for (i = 0; i < script_cache->script_count; ++i)
2590  {
2591  if (script_cache->scripts[i].tag == tag)
2592  return &script_cache->scripts[i];
2593  }
2594 
2595  return NULL;
2596 }
2597 
2600 {
2601  SIZE_T initial_count, count, i;
2603  OPENTYPE_TAG tag;
2604 
2605  TRACE("script_cache %p, table %#x, list %p.\n", script_cache, table, list);
2606 
2607  if (!(count = GET_BE_WORD(list->ScriptCount)))
2608  return;
2609 
2610  TRACE("Adding %lu scripts.\n", count);
2611 
2612  initial_count = script_cache->script_count;
2613  for (i = 0; i < count; ++i)
2614  {
2615  tag = MS_MAKE_TAG(list->ScriptRecord[i].ScriptTag[0],
2616  list->ScriptRecord[i].ScriptTag[1],
2617  list->ScriptRecord[i].ScriptTag[2],
2618  list->ScriptRecord[i].ScriptTag[3]);
2619 
2620  if (!(initial_count && (script = usp10_script_cache_get_script(script_cache, tag)))
2621  && !(script = usp10_script_cache_add_script(script_cache, tag)))
2622  return;
2623 
2624  script->table[table] = (const BYTE *)list + GET_BE_WORD(list->ScriptRecord[i].Script);
2625  }
2626 }
2627 
2628 static void _initialize_script_cache(ScriptCache *script_cache)
2629 {
2630  const GPOS_Header *gpos_header;
2631  const GSUB_Header *gsub_header;
2632 
2633  if (script_cache->scripts_initialized)
2634  return;
2635 
2636  if ((gsub_header = script_cache->GSUB_Table))
2638  (const OT_ScriptList *)((const BYTE *)gsub_header + GET_BE_WORD(gsub_header->ScriptList)));
2639 
2640  if ((gpos_header = script_cache->GPOS_Table))
2642  (const OT_ScriptList *)((const BYTE *)gpos_header + GET_BE_WORD(gpos_header->ScriptList)));
2643 
2644  script_cache->scripts_initialized = TRUE;
2645 }
2646 
2648 {
2649  int i;
2650  const LoadedScript *script;
2651  HRESULT rc = S_OK;
2652 
2654 
2655  *pcTags = psc->script_count;
2656 
2657  if (searchingFor)
2658  {
2659  if (!(script = usp10_script_cache_get_script(psc, searchingFor)))
2660  return USP_E_SCRIPT_NOT_IN_FONT;
2661 
2662  *pScriptTags = script->tag;
2663  *pcTags = 1;
2664  return S_OK;
2665  }
2666 
2667  if (cMaxTags < *pcTags)
2668  rc = E_OUTOFMEMORY;
2669 
2670  cMaxTags = min(cMaxTags, psc->script_count);
2671  for (i = 0; i < cMaxTags; ++i)
2672  {
2673  pScriptTags[i] = psc->scripts[i].tag;
2674  }
2675  return rc;
2676 }
2677 
2679 {
2680  LoadedLanguage *language;
2681 
2682  if (!usp10_array_reserve((void **)&script->languages, &script->languages_size,
2683  script->language_count + 1, sizeof(*script->languages)))
2684  {
2685  ERR("Failed to grow languages array.\n");
2686  return NULL;
2687  }
2688 
2689  language = &script->languages[script->language_count++];
2690  language->tag = tag;
2691 
2692  return language;
2693 }
2694 
2696 {
2697  size_t i;
2698 
2699  for (i = 0; i < script->language_count; ++i)
2700  {
2701  if (script->languages[i].tag == tag)
2702  return &script->languages[i];
2703  }
2704 
2705  return NULL;
2706 }
2707 
2710 {
2711  SIZE_T initial_count, count, i;
2712  LoadedLanguage *language;
2713  OPENTYPE_TAG tag;
2714  DWORD offset;
2715 
2716  TRACE("script %p, table %#x, list %p.\n", script, table, list);
2717 
2718  if ((offset = GET_BE_WORD(list->DefaultLangSys)))
2719  {
2720  script->default_language.tag = MS_MAKE_TAG('d','f','l','t');
2721  script->default_language.table[table] = (const BYTE *)list + offset;
2722  TRACE("Default language %p.\n", script->default_language.table[table]);
2723  }
2724 
2725  if (!(count = GET_BE_WORD(list->LangSysCount)))
2726  return;
2727 
2728  TRACE("Adding %lu languages.\n", count);
2729 
2730  initial_count = script->language_count;
2731  for (i = 0; i < count; ++i)
2732  {
2733  tag = MS_MAKE_TAG(list->LangSysRecord[i].LangSysTag[0],
2734  list->LangSysRecord[i].LangSysTag[1],
2735  list->LangSysRecord[i].LangSysTag[2],
2736  list->LangSysRecord[i].LangSysTag[3]);
2737 
2738  if (!(initial_count && (language = usp10_script_get_language(script, tag)))
2739  && !(language = usp10_script_add_language(script, tag)))
2740  return;
2741 
2742  language->table[table] = (const BYTE *)list + GET_BE_WORD(list->LangSysRecord[i].LangSys);
2743  }
2744 }
2745 
2747 {
2748  const OT_Script *list;
2749 
2750  if (script->languages_initialized)
2751  return;
2752 
2753  if ((list = script->table[USP10_SCRIPT_TABLE_GSUB]))
2755  if ((list = script->table[USP10_SCRIPT_TABLE_GPOS]))
2757 
2758  script->languages_initialized = TRUE;
2759 }
2760 
2762 {
2763  int i;
2764  HRESULT rc = S_OK;
2766 
2768  if (!(script = usp10_script_cache_get_script(psc, script_tag)))
2769  return E_INVALIDARG;
2770 
2772 
2773  if (!searchingFor && cMaxTags < script->language_count)
2774  rc = E_OUTOFMEMORY;
2775  else if (searchingFor)
2776  rc = E_INVALIDARG;
2777 
2778  *pcTags = script->language_count;
2779 
2780  for (i = 0; i < script->language_count; i++)
2781  {
2782  if (i < cMaxTags)
2783  pLanguageTags[i] = script->languages[i].tag;
2784 
2785  if (searchingFor)
2786  {
2787  if (searchingFor == script->languages[i].tag)
2788  {
2789  pLanguageTags[0] = script->languages[i].tag;
2790  *pcTags = 1;
2791  rc = S_OK;
2792  break;
2793  }
2794  }
2795  }
2796 
2797  if (script->default_language.table[USP10_LANGUAGE_TABLE_GSUB])
2798  {
2799  if (i < cMaxTags)
2800  pLanguageTags[i] = script->default_language.tag;
2801 
2802  if (searchingFor && FAILED(rc))
2803  {
2804  pLanguageTags[0] = script->default_language.tag;
2805  }
2806  i++;
2807  *pcTags = (*pcTags) + 1;
2808  }
2809 
2810  return rc;
2811 }
2812 
2813 static void usp10_language_add_feature_list(LoadedLanguage *language, char table_type,
2814  const OT_LangSys *lang, const OT_FeatureList *feature_list)
2815 {
2816  unsigned int count = GET_BE_WORD(lang->FeatureCount);
2817  unsigned int i, j;
2818 
2819  TRACE("table_type %#x, %u features.\n", table_type, count);
2820 
2821  if (!count || !usp10_array_reserve((void **)&language->features, &language->features_size,
2822  language->feature_count + count, sizeof(*language->features)))
2823  return;
2824 
2825  for (i = 0; i < count; ++i)
2826  {
2827  const OT_FeatureRecord *record;
2828  LoadedFeature *loaded_feature;
2829  const OT_Feature *feature;
2830 
2831  record = &feature_list->FeatureRecord[GET_BE_WORD(lang->FeatureIndex[i])];
2832  feature = (const OT_Feature *)((const BYTE *)feature_list + GET_BE_WORD(record->Feature));
2833 
2834  loaded_feature = &language->features[language->feature_count + i];
2835  loaded_feature->tag = MS_MAKE_TAG(record->FeatureTag[0], record->FeatureTag[1],
2836  record->FeatureTag[2], record->FeatureTag[3]);
2837  loaded_feature->tableType = table_type;
2838  loaded_feature->feature = feature;
2839  loaded_feature->lookup_count = GET_BE_WORD(feature->LookupCount);
2840  loaded_feature->lookups = heap_calloc(loaded_feature->lookup_count, sizeof(*loaded_feature->lookups));
2841  for (j = 0; j < loaded_feature->lookup_count; ++j)
2842  loaded_feature->lookups[j] = GET_BE_WORD(feature->LookupListIndex[j]);
2843  }
2844  language->feature_count += count;
2845 }
2846 
2848 {
2849  const GSUB_Header *gsub_header = psc->GSUB_Table;
2850  const GPOS_Header *gpos_header = psc->GPOS_Table;
2851  const OT_FeatureList *feature_list;
2852  const OT_LangSys *lang;
2853 
2854  if (language->features_initialized)
2855  return;
2856 
2857  if ((lang = language->table[USP10_LANGUAGE_TABLE_GSUB]))
2858  {
2859  feature_list = (const OT_FeatureList *)((const BYTE *)gsub_header + GET_BE_WORD(gsub_header->FeatureList));
2860  usp10_language_add_feature_list(language, FEATURE_GSUB_TABLE, lang, feature_list);
2861  }
2862 
2863  if ((lang = language->table[USP10_LANGUAGE_TABLE_GPOS]))
2864  {
2865  feature_list = (const OT_FeatureList *)((const BYTE *)gpos_header + GET_BE_WORD(gpos_header->FeatureList));
2866  usp10_language_add_feature_list(language, FEATURE_GPOS_TABLE, lang, feature_list);
2867  }
2868 
2869  language->features_initialized = TRUE;
2870 }
2871 
2873 {
2874  int i;
2875  LoadedLanguage *language;
2877  HRESULT rc = S_OK;
2878 
2880  if (!(script = usp10_script_cache_get_script(psc, script_tag)))
2881  {
2882  *pcTags = 0;
2883  if (!filtered)
2884  return S_OK;
2885  else
2886  return E_INVALIDARG;
2887  }
2888 
2890 
2891  language = &script->default_language;
2892  if (language->tag != language_tag || (!language->table[USP10_LANGUAGE_TABLE_GSUB]
2893  && !language->table[USP10_LANGUAGE_TABLE_GPOS]))
2894  language = usp10_script_get_language(script, language_tag);
2895 
2896  if (!language)
2897  {
2898  *pcTags = 0;
2899  return S_OK;
2900  }
2901 
2902  _initialize_feature_cache(psc, language);
2903 
2904  if (tableType)
2905  {
2906  *pcTags = 0;
2907  for (i = 0; i < language->feature_count; i++)
2908  if (language->features[i].tableType == tableType)
2909  *pcTags = (*pcTags)+1;
2910  }
2911  else
2912  *pcTags = language->feature_count;
2913 
2914  if (!searchingFor && cMaxTags < *pcTags)
2915  rc = E_OUTOFMEMORY;
2916  else if (searchingFor)
2917  rc = E_INVALIDARG;
2918 
2919  for (i = 0; i < language->feature_count; i++)
2920  {
2921  if (i < cMaxTags)
2922  {
2923  if (!tableType || language->features[i].tableType == tableType)
2924  pFeatureTags[i] = language->features[i].tag;
2925  }
2926 
2927  if (searchingFor)
2928  {
2929  if ((searchingFor == language->features[i].tag) &&
2930  (!tableType || language->features[i].tableType == tableType))
2931  {
2932  pFeatureTags[0] = language->features[i].tag;
2933  *pcTags = 1;
2934  if (feature)
2935  *feature = &language->features[i];
2936  rc = S_OK;
2937  break;
2938  }
2939  }
2940  }
2941  return rc;
2942 }
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble * u
Definition: glfuncs.h:240
#define GET_BE_WORD(x)
Definition: opentype.c:43
GPOS_PosLookupRecord PosLookupRecord[1]
Definition: opentype.c:593
_In_opt_ ULONG _Out_ PULONG Value
Definition: rtlfuncs.h:2327
WORD LookupCount
Definition: opentype.c:183
INTERNETFEATURELIST feature
Definition: misc.c:1689
#define CMAP_TAG
Definition: opentype.c:50
static void GPOS_get_value_record_offsets(const BYTE *head, GPOS_ValueRecord *ValueRecord, WORD ValueFormat, unsigned int ppem, POINT *ptPlacement, POINT *ptAdvance)
Definition: opentype.c:1662
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
LoadedFeature * features
#define TRUE
Definition: types.h:120
SCRIPT_VISATTR sva
Definition: usp10.h:215
WINE_DEFAULT_DEBUG_CHANNEL(uniscribe)
WORD SubClassRuleCnt
Definition: opentype.c:297
HRESULT OpenType_GetFontFeatureTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG language_tag, BOOL filtered, OPENTYPE_TAG searchingFor, char tableType, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags, LoadedFeature **feature)
Definition: opentype.c:2872
#define USP_E_SCRIPT_NOT_IN_FONT
Definition: usp10.h:71
static int GPOS_apply_MarkToBase(const ScriptCache *script_cache, const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *pt)
Definition: opentype.c:1900
WORD DefaultLangSys
Definition: opentype.c:159
long y
Definition: polytest.cpp:48
SIZE_T scripts_size
static const BYTE * GPOS_get_subtable(const OT_LookupTable *look, int index)
Definition: opentype.c:1676
static SCRIPT_CACHE SCRIPT_ANALYSIS OPENTYPE_TAG OPENTYPE_TAG int TEXTRANGE_PROPERTIES int const WCHAR int int WORD * pwLogClust
Definition: usp10.c:64
OT_FeatureRecord FeatureRecord[1]
Definition: opentype.c:178
DWORD version
Definition: opentype.c:395
WORD SubstCount
Definition: opentype.c:280
GSUB_SubstLookupRecord SubstLookupRecord[1]
Definition: opentype.c:308
static void _initialize_language_cache(LoadedScript *script)
Definition: opentype.c:2746
long x
Definition: polytest.cpp:48
WORD MarkCount
Definition: opentype.c:523
struct outqueuenode * head
Definition: adnsresfilter.c:66
WORD ScriptList
Definition: opentype.c:396
#define pt(x, y)
Definition: drawing.c:79
HRESULT OpenType_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags)
Definition: opentype.c:2647
static INT GSUB_apply_ChainContextSubst(const OT_LookupList *lookup, const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
Definition: opentype.c:1245
GLuint GLuint GLsizei count
Definition: gl.h:1545
static int GPOS_apply_PairAdjustment(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *adjust, POINT *advance)
Definition: opentype.c:1770
char CHAR
Definition: xmlstorage.h:175
_In_ FONTOBJ _In_ ULONG _In_ ULONG cGlyphs
Definition: winddi.h:3799
#define WARN(fmt,...)
Definition: debug.h:111
static void usp10_language_add_feature_list(LoadedLanguage *language, char table_type, const OT_LangSys *lang, const OT_FeatureList *feature_list)
Definition: opentype.c:2813
static int int const SCRIPT_CONTROL const SCRIPT_STATE SCRIPT_ITEM ULONG * pScriptTags
Definition: usp10.c:62
WORD ScriptList
Definition: opentype.c:138
static HDC
Definition: imagelist.c:92
GLintptr offset
Definition: glext.h:5920
static INT GSUB_apply_lookup(const OT_LookupList *lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
Definition: opentype.c:1485
void * GSUB_Table
Definition: arc.h:84
WORD Substitute[1]
Definition: opentype.c:239
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
Definition: ecma_167.h:138
static LoadedLanguage * usp10_script_add_language(LoadedScript *script, OPENTYPE_TAG tag)
Definition: opentype.c:2678
GLenum GLsizei GLenum GLenum const GLvoid * table
Definition: glext.h:5644
static ULONG lookup[16]
Definition: vga.c:46
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
WORD ScriptCount
Definition: opentype.c:149
#define MS_MAKE_TAG(ch0, ch1, ch2, ch3)
Definition: font.c:113
LONG du
Definition: usp10.h:200
static void _initialize_script_cache(ScriptCache *script_cache)
Definition: opentype.c:2628
GSUB_SubstLookupRecord SubstLookupRecord[1]
Definition: opentype.c:350
static int GSUB_is_glyph_covered(const void *table, unsigned int glyph)
Definition: opentype.c:819
WORD GlyphClassDef
Definition: opentype.c:109
LONG tmDescent
Definition: wingdi.h:2363
LONG tmAscent
Definition: wingdi.h:2362
LONG tmInternalLeading
Definition: wingdi.h:2364
WORD PosClassRule[1]
Definition: opentype.c:583
void OpenType_GDEF_UpdateGlyphProps(ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD *pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
Definition: opentype.c:751
WORD LookupOrder
Definition: opentype.c:165
static void * heap_calloc(SIZE_T count, SIZE_T size)
Definition: heap.h:49
static UINT UINT LPWORD glyphs
Definition: font.c:44
WORD numTables
Definition: opentype.c:85
BOOL usp10_array_reserve(void **elements, SIZE_T *capacity, SIZE_T count, SIZE_T size)
Definition: usp10.c:728
static LoadedScript * usp10_script_cache_get_script(ScriptCache *script_cache, OPENTYPE_TAG tag)
Definition: opentype.c:2585
WORD FeatureCount
Definition: opentype.c:167
int32_t INT
Definition: typedefs.h:56
static WORD OT_get_glyph_class(const void *table, WORD glyph)
Definition: opentype.c:714
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
static void * heap_alloc(size_t len)
Definition: appwiz.h:65
WORD DeltaFormat
Definition: opentype.c:404
static void GPOS_apply_CursiveAttachment(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *pt)
Definition: opentype.c:1858
int OpenType_apply_GSUB_lookup(const void *table, unsigned int lookup_index, WORD *glyphs, unsigned int glyph_index, int write_dir, int *glyph_count)
Definition: opentype.c:1540
WORD ReqFeatureIndex
Definition: opentype.c:166
OPENTYPE_TAG tag
int USP10_FindGlyphInLogClust(const WORD *pwLogClust, int cChars, WORD target)
Definition: usp10.c:1042
static void usp10_script_cache_add_script_list(ScriptCache *script_cache, enum usp10_script_table table, const OT_ScriptList *list)
Definition: opentype.c:2598
WORD SubRule[1]
Definition: opentype.c:275
static void Lookup(RTF_Info *, char *)
Definition: reader.c:2228
void ls(int argc, const char *argv[])
Definition: cmds.c:1136
static INT GSUB_apply_AlternateSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
Definition: opentype.c:978
static INT GSUB_apply_ContextSubst(const OT_LookupList *lookup, const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
Definition: opentype.c:1074
unsigned short(__cdecl typeof(TIFFCurrentDirectory))(struct tiff *)
Definition: typeof.h:93
OT_RangeRecord RangeRecord[1]
Definition: opentype.c:214
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
unsigned int component_count
GLenum GLint GLuint mask
Definition: glext.h:6028
DWORD WINAPI GetFontData(HDC hdc, DWORD dwTable, DWORD dwOffset, LPVOID lpvBuffer, DWORD cbData)
Definition: font.c:2667
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
static INT GSUB_apply_LigatureSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
Definition: opentype.c:1011
GLsizei GLuint * groups
Definition: glext.h:11113
unsigned int BOOL
Definition: ntddk_ex.h:94
usp10_script_table
WORD BaseCount
Definition: opentype.c:513
#define a
Definition: ke_i.h:78
WORD SubRuleCount
Definition: opentype.c:274
LoadedScript * scripts
CMAP_EncodingRecord tables[1]
Definition: opentype.c:86
#define FIXME(fmt,...)
Definition: debug.h:110
unsigned int OpenType_apply_GPOS_lookup(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *otm, const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, unsigned int lookup_index, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, GOFFSET *goffset)
Definition: opentype.c:2557
WORD FeatureCount
Definition: opentype.c:177
OPENTYPE_TAG tag
#define E_INVALIDARG
Definition: ddrawi.h:101
GPOS_PosLookupRecord PosLookupRecord[1]
Definition: opentype.c:614
WORD LigatureAttach[1]
Definition: opentype.c:538
LONG lfWidth
Definition: dimm.idl:60
smooth NULL
Definition: ftsmooth.c:416
char ext[3]
Definition: mkdosfs.c:358
OT_ClassRangeRecord ClassRangeRecord[1]
Definition: opentype.c:131
WORD PosClassRuleCnt
Definition: opentype.c:582
WORD LangSysCount
Definition: opentype.c:160
script
Definition: msipriv.h:374
LONG dv
Definition: usp10.h:201
DWORD Version
Definition: opentype.c:108
GLuint index
Definition: glext.h:6031
GSUB_SubstLookupRecord SubstLookupRecord[1]
Definition: opentype.c:285
#define b
Definition: ke_i.h:79
unsigned int component_size
WORD StartSize
Definition: opentype.c:402
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
BOOL scripts_initialized
static void GPOS_apply_MarkToLigature(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *pt)
Definition: opentype.c:1985
r l[0]
Definition: byte_order.h:167
static const WCHAR lang[]
Definition: wbemdisp.c:287
GLboolean GLuint group
Definition: glext.h:11120
static SCRIPT_CACHE SCRIPT_ANALYSIS OPENTYPE_TAG OPENTYPE_TAG int TEXTRANGE_PROPERTIES int const WCHAR int cChars
Definition: usp10.c:64
WORD Component[1]
Definition: opentype.c:257
static INT GPOS_get_device_table_value(const OT_DeviceTable *DeviceTable, WORD ppem)
Definition: opentype.c:1557
GLboolean GLboolean g
Definition: glext.h:6204
const char * wine_dbgstr_point(const POINT *guid)
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
#define TRACE(s)
Definition: solgame.cpp:4
GPOS_EntryExitRecord EntryExitRecord[1]
Definition: opentype.c:496
GLsizeiptr size
Definition: glext.h:5919
GPOS_ComponentRecord ComponentRecord[1]
Definition: opentype.c:547
WORD fClusterStart
Definition: usp10.h:179
void * GDEF_Table
WORD CompCount
Definition: opentype.c:256
static void apply_pair_value(const void *pos_table, WORD val_fmt1, WORD val_fmt2, const WORD *pair, INT ppem, POINT *adjust, POINT *advance)
Definition: opentype.c:1746
if(!(yy_init))
Definition: macro.lex.yy.c:714
static void _initialize_feature_cache(ScriptCache *psc, LoadedLanguage *language)
Definition: opentype.c:2847
__wchar_t WCHAR
Definition: xmlstorage.h:180
WORD FeatureList
Definition: opentype.c:139
static INT GPOS_get_value_record(WORD ValueFormat, const WORD data[], GPOS_ValueRecord *record)
Definition: opentype.c:1648
LONG HRESULT
Definition: typedefs.h:77
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
const void * table[USP10_LANGUAGE_TABLE_COUNT]
GPOS_MarkRecord MarkRecord[1]
Definition: opentype.c:524
static BOOL GPOS_apply_MarkToMark(const OT_LookupTable *look, const SCRIPT_ANALYSIS *analysis, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, unsigned int ppem, POINT *pt)
Definition: opentype.c:2075
#define round(x)
Definition: opentype.c:47
static void usp10_script_add_language_list(LoadedScript *script, enum usp10_language_table table, const OT_Script *list)
Definition: opentype.c:2708
unsigned short WORD
Definition: ntddk_ex.h:93
#define for
Definition: utility.h:88
unsigned long DWORD
Definition: ntddk_ex.h:95
WORD LigatureAnchor[1]
Definition: opentype.c:542
static VOID * load_CMAP_format12_table(HDC hdc, ScriptCache *psc)
Definition: opentype.c:627
static LoadedLanguage * usp10_script_get_language(LoadedScript *script, OPENTYPE_TAG tag)
Definition: opentype.c:2695
WORD PairSetOffset[1]
Definition: opentype.c:461
static int compare_group(const void *a, const void *b)
Definition: opentype.c:661
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
WORD GlyphCount
Definition: opentype.c:238
#define GGI_MARK_NONEXISTING_GLYPHS
Definition: wingdi.h:1067
GLbitfield flags
Definition: glext.h:7161
static SCRIPT_CACHE SCRIPT_ANALYSIS OPENTYPE_TAG OPENTYPE_TAG int OPENTYPE_TAG * pFeatureTags
Definition: usp10.c:68
WORD SubTable[1]
Definition: opentype.c:196
#define GET_BE_DWORD(x)
Definition: opentype.c:44
WORD SubTableCount
Definition: opentype.c:195
#define index(s, c)
Definition: various.h:29
usp10_language_table
HDC hdc
Definition: main.c:9
WORD FeatureList
Definition: opentype.c:397
WORD LookupList
Definition: opentype.c:398
WORD LookupList
Definition: opentype.c:140
ROSDATA LIGATURE2 Ligature[]
Definition: kbda1.c:343
unsigned char BYTE
Definition: mem.h:68
Definition: _list.h:228
static unsigned int GPOS_apply_ChainContextPos(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *otm, const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, const OT_LookupList *lookup, const OT_LookupTable *look, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, GOFFSET *goffset)
Definition: opentype.c:2261
_STLP_MOVE_TO_STD_NAMESPACE void _STLP_CALL advance(_InputIterator &__i, _Distance __n)
WORD Class1Record[1]
Definition: opentype.c:473
WORD StartCoverageIndex
Definition: opentype.c:208
static unsigned int GPOS_apply_lookup(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *otm, const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, const OT_LookupList *lookup, unsigned int lookup_index, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, GOFFSET *goffset)
Definition: opentype.c:2382
GLsizei const GLfloat * value
Definition: glext.h:6069
int chr(char *serport)
Definition: gdblib.c:152
WORD LigCaretList
Definition: opentype.c:111
static LoadedScript * usp10_script_cache_add_script(ScriptCache *script_cache, OPENTYPE_TAG tag)
Definition: opentype.c:2568
GPOS_PairValueRecord PairValueRecord[1]
Definition: opentype.c:484
#define ERR(fmt,...)
Definition: debug.h:109
DWORD OpenType_CMAP_GetGlyphIndex(HDC hdc, ScriptCache *psc, DWORD utf32c, WORD *glyph_index, DWORD flags)
Definition: opentype.c:673
static SCRIPT_CACHE SCRIPT_ANALYSIS int cMaxTags
Definition: usp10.c:66
ULONG_PTR SIZE_T
Definition: typedefs.h:78
#define GSUB_E_NOGLYPH
WORD LookupType
Definition: opentype.c:193
#define S_OK
Definition: intsafe.h:59
WORD SubClassRule[1]
Definition: opentype.c:298
WORD ChainSubClassRule[1]
Definition: opentype.c:330
WORD LigGlyph
Definition: opentype.c:255
WORD PairValueCount
Definition: opentype.c:483
static unsigned __int64 next
Definition: rand_nt.c:6
GLenum GLenum GLenum input
Definition: glext.h:9031
WORD LigatureCount
Definition: opentype.c:250
static SCRIPT_CACHE * psc
Definition: usp10.c:64
#define FEATURE_GPOS_TABLE
static void GPOS_convert_design_units_to_device(const OUTLINETEXTMETRICW *otm, const LOGFONTW *logfont, int desX, int desY, double *devX, double *devY)
Definition: opentype.c:1636
WORD GlyphArray[1]
Definition: opentype.c:202
void * GPOS_Table
WORD Alternate[1]
Definition: opentype.c:383
#define list
Definition: rosglue.h:35
#define min(a, b)
Definition: monoChain.cc:55
Definition: _pair.h:47
GSUB_SubstLookupRecord SubstLookupRecord[1]
Definition: opentype.c:371
WORD fLogicalOrder
Definition: usp10.h:144
TEXTMETRICW otmTextMetrics
Definition: wingdi.h:2492
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
WORD AttachList
Definition: opentype.c:110
SIZE_T script_count
static INT GSUB_apply_MultipleSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
Definition: opentype.c:928
static void GPOS_get_anchor_values(const void *table, POINT *pt, WORD ppem)
Definition: opentype.c:1584
DWORD WINAPI GetGlyphIndicesW(_In_ HDC hdc, _In_reads_(c) LPCWSTR lpstr, _In_ int c, _Out_writes_(c) LPWORD pgi, _In_ DWORD fl)
OPENTYPE_TAG tag
struct nls_table * tables
Definition: nls_base.c:22
WORD version
Definition: opentype.c:84
WORD Input[1]
Definition: opentype.c:281
GLdouble GLdouble GLdouble GLdouble top
Definition: glext.h:10859
const void * feature
gsub_lookup_type
Definition: opentype.c:65
HRESULT OpenType_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pLanguageTags, int *pcTags)
Definition: opentype.c:2761
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
WORD LookupFlag
Definition: opentype.c:194
WORD MarkAttachClassDef
Definition: opentype.c:112
static unsigned int GPOS_apply_ContextPos(const ScriptCache *script_cache, const OUTLINETEXTMETRICW *otm, const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, const OT_LookupList *lookup, const OT_LookupTable *look, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, GOFFSET *goffset)
Definition: opentype.c:2142
gpos_lookup_type
Definition: opentype.c:52
WORD LookupCount
Definition: opentype.c:188
#define GDI_ERROR
Definition: wingdi.h:1291
WORD GlyphCount
Definition: opentype.c:279
#define TRACE_ON(x)
Definition: compat.h:65
static const BYTE * GSUB_get_subtable(const OT_LookupTable *look, int index)
Definition: opentype.c:863
int k
Definition: mpi.c:3369
WORD DeltaValue[1]
Definition: opentype.c:405
DWORD version
Definition: opentype.c:137
ULONG OPENTYPE_TAG
Definition: usp10.h:205
struct CFHEADER header
Definition: fdi.c:109
static SCRIPT_CACHE SCRIPT_ANALYSIS int OPENTYPE_TAG int * pcTags
Definition: usp10.c:66
WORD FeatureParams
Definition: opentype.c:182
#define FEATURE_GSUB_TABLE
static INT GSUB_apply_SingleSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
Definition: opentype.c:882
static VOID Substitute(_Out_writes_bytes_(BufferSize) PWCHAR Buffer, _In_ ULONG BufferSize, _In_ PCWSTR Template, _In_ PCWSTR SystemDriveName, _In_ PCWSTR SystemRootName)
Definition: IoFilesystem.c:231
WORD Value[1]
Definitio