2 * Opentype font interfaces for the Uniscribe Script Processor (usp10.dll)
4 * Copyright 2012 CodeWeavers, Aric Stewart
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.
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.
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
32 #include "usp10_internal.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe
);
38 #ifdef WORDS_BIGENDIAN
39 #define GET_BE_WORD(x) (x)
40 #define GET_BE_DWORD(x) (x)
42 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
43 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
46 #define round(x) (((x) < 0) ? (int)((x) - 0.5) : (int)((x) + 0.5))
48 /* These are all structures needed for the cmap format 12 table */
49 #define CMAP_TAG MS_MAKE_TAG('c', 'm', 'a', 'p')
55 } CMAP_EncodingRecord
;
60 CMAP_EncodingRecord tables
[1];
67 } CMAP_SegmentedCoverage_group
;
75 CMAP_SegmentedCoverage_group groups
[1];
76 } CMAP_SegmentedCoverage
;
78 /* These are all structures needed for the GDEF table */
79 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
81 enum {BaseGlyph
=1, LigatureGlyph
, MarkGlyph
, ComponentGlyph
};
88 WORD MarkAttachClassDef
;
95 WORD ClassValueArray
[1];
96 } GDEF_ClassDefFormat1
;
102 } GDEF_ClassRangeRecord
;
106 WORD ClassRangeCount
;
107 GDEF_ClassRangeRecord ClassRangeRecord
[1];
108 } GDEF_ClassDefFormat2
;
110 /* These are all structures needed for the GSUB table */
126 OT_ScriptRecord ScriptRecord
[1];
137 OT_LangSysRecord LangSysRecord
[1];
141 WORD LookupOrder
; /* Reserved */
142 WORD ReqFeatureIndex
;
144 WORD FeatureIndex
[1];
154 OT_FeatureRecord FeatureRecord
[1];
158 WORD FeatureParams
; /* Reserved */
160 WORD LookupListIndex
[1];
179 } OT_CoverageFormat1
;
184 WORD StartCoverageIndex
;
190 OT_RangeRecord RangeRecord
[1];
191 } OT_CoverageFormat2
;
194 WORD SubstFormat
; /* = 1 */
197 } GSUB_SingleSubstFormat1
;
200 WORD SubstFormat
; /* = 2 */
204 }GSUB_SingleSubstFormat2
;
207 WORD SubstFormat
; /* = 1 */
211 }GSUB_MultipleSubstFormat1
;
219 WORD SubstFormat
; /* = 1 */
223 }GSUB_LigatureSubstFormat1
;
238 WORD LookupListIndex
;
240 }GSUB_SubstLookupRecord
;
243 WORD SubstFormat
; /* = 1 */
245 WORD ChainSubRuleSetCount
;
246 WORD ChainSubRuleSet
[1];
247 }GSUB_ChainContextSubstFormat1
;
250 WORD SubstFormat
; /* = 3 */
251 WORD BacktrackGlyphCount
;
253 }GSUB_ChainContextSubstFormat3_1
;
256 WORD InputGlyphCount
;
258 }GSUB_ChainContextSubstFormat3_2
;
261 WORD LookaheadGlyphCount
;
263 }GSUB_ChainContextSubstFormat3_3
;
267 GSUB_SubstLookupRecord SubstLookupRecord
[1];
268 }GSUB_ChainContextSubstFormat3_4
;
271 WORD SubstFormat
; /* = 1 */
273 WORD AlternateSetCount
;
274 WORD AlternateSet
[1];
275 } GSUB_AlternateSubstFormat1
;
282 /* These are all structures needed for the GPOS table */
302 } GPOS_AnchorFormat1
;
309 } GPOS_AnchorFormat2
;
317 } GPOS_AnchorFormat3
;
335 } GPOS_SinglePosFormat1
;
343 } GPOS_SinglePosFormat2
;
351 WORD PairSetOffset
[1];
352 } GPOS_PairPosFormat1
;
358 } GPOS_PairValueRecord
;
362 GPOS_PairValueRecord PairValueRecord
[1];
372 } GPOS_MarkBasePosFormat1
;
380 GPOS_BaseRecord BaseRecord
[1];
390 GPOS_MarkRecord MarkRecord
[1];
400 } GPOS_MarkMarkPosFormat1
;
408 GPOS_Mark2Record Mark2Record
[1];
413 WORD LookupListIndex
;
414 } GPOS_PosLookupRecord
;
418 WORD BacktrackGlyphCount
;
420 } GPOS_ChainContextPosFormat3_1
;
423 WORD InputGlyphCount
;
425 } GPOS_ChainContextPosFormat3_2
;
428 WORD LookaheadGlyphCount
;
430 } GPOS_ChainContextPosFormat3_3
;
434 GPOS_PosLookupRecord PosLookupRecord
[1];
435 } GPOS_ChainContextPosFormat3_4
;
441 static VOID
*load_CMAP_format12_table(HDC hdc
, ScriptCache
*psc
)
443 CMAP_Header
*CMAP_Table
= NULL
;
447 if (!psc
->CMAP_Table
)
449 length
= GetFontData(hdc
, CMAP_TAG
, 0, NULL
, 0);
450 if (length
!= GDI_ERROR
)
452 psc
->CMAP_Table
= HeapAlloc(GetProcessHeap(),0,length
);
453 GetFontData(hdc
, CMAP_TAG
, 0, psc
->CMAP_Table
, length
);
454 TRACE("Loaded cmap table of %i bytes\n",length
);
460 CMAP_Table
= psc
->CMAP_Table
;
462 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
); i
++)
464 if ( (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) == 3) &&
465 (GET_BE_WORD(CMAP_Table
->tables
[i
].encodingID
) == 10) )
467 CMAP_SegmentedCoverage
*format
= (CMAP_SegmentedCoverage
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
468 if (GET_BE_WORD(format
->format
) == 12)
475 static int compare_group(const void *a
, const void* b
)
477 const DWORD
*chr
= a
;
478 const CMAP_SegmentedCoverage_group
*group
= b
;
480 if (*chr
< GET_BE_DWORD(group
->startCharCode
))
482 if (*chr
> GET_BE_DWORD(group
->endCharCode
))
487 DWORD
OpenType_CMAP_GetGlyphIndex(HDC hdc
, ScriptCache
*psc
, DWORD utf32c
, LPWORD pgi
, DWORD flags
)
489 /* BMP: use gdi32 for ease */
490 if (utf32c
< 0x10000)
493 return GetGlyphIndicesW(hdc
,&ch
, 1, pgi
, flags
);
496 if (!psc
->CMAP_format12_Table
)
497 psc
->CMAP_format12_Table
= load_CMAP_format12_table(hdc
, psc
);
499 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
504 if (psc
->CMAP_format12_Table
)
506 CMAP_SegmentedCoverage
*format
= NULL
;
507 CMAP_SegmentedCoverage_group
*group
= NULL
;
509 format
= (CMAP_SegmentedCoverage
*)psc
->CMAP_format12_Table
;
511 group
= bsearch(&utf32c
, format
->groups
, GET_BE_DWORD(format
->nGroups
),
512 sizeof(CMAP_SegmentedCoverage_group
), compare_group
);
516 DWORD offset
= utf32c
- GET_BE_DWORD(group
->startCharCode
);
517 *pgi
= GET_BE_DWORD(group
->startGlyphID
) + offset
;
528 static WORD
GDEF_get_glyph_class(const GDEF_Header
*header
, WORD glyph
)
532 const GDEF_ClassDefFormat1
*cf1
;
537 offset
= GET_BE_WORD(header
->GlyphClassDef
);
541 cf1
= (GDEF_ClassDefFormat1
*)(((BYTE
*)header
)+offset
);
542 if (GET_BE_WORD(cf1
->ClassFormat
) == 1)
544 if (glyph
>= GET_BE_WORD(cf1
->StartGlyph
))
546 int index
= glyph
- GET_BE_WORD(cf1
->StartGlyph
);
547 if (index
< GET_BE_WORD(cf1
->GlyphCount
))
548 class = GET_BE_WORD(cf1
->ClassValueArray
[index
]);
551 else if (GET_BE_WORD(cf1
->ClassFormat
) == 2)
553 const GDEF_ClassDefFormat2
*cf2
= (GDEF_ClassDefFormat2
*)cf1
;
555 top
= GET_BE_WORD(cf2
->ClassRangeCount
);
556 for (i
= 0; i
< top
; i
++)
558 if (glyph
>= GET_BE_WORD(cf2
->ClassRangeRecord
[i
].Start
) &&
559 glyph
<= GET_BE_WORD(cf2
->ClassRangeRecord
[i
].End
))
561 class = GET_BE_WORD(cf2
->ClassRangeRecord
[i
].Class
);
567 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1
->ClassFormat
));
572 static VOID
*load_gdef_table(HDC hdc
)
574 VOID
* GDEF_Table
= NULL
;
575 int length
= GetFontData(hdc
, GDEF_TAG
, 0, NULL
, 0);
576 if (length
!= GDI_ERROR
)
578 GDEF_Table
= HeapAlloc(GetProcessHeap(),0,length
);
579 GetFontData(hdc
, GDEF_TAG
, 0, GDEF_Table
, length
);
580 TRACE("Loaded GDEF table of %i bytes\n",length
);
585 void OpenType_GDEF_UpdateGlyphProps(HDC hdc
, ScriptCache
*psc
, const WORD
*pwGlyphs
, const WORD cGlyphs
, WORD
* pwLogClust
, const WORD cChars
, SCRIPT_GLYPHPROP
*pGlyphProp
)
589 if (!psc
->GDEF_Table
)
590 psc
->GDEF_Table
= load_gdef_table(hdc
);
592 for (i
= 0; i
< cGlyphs
; i
++)
598 k
= USP10_FindGlyphInLogClust(pwLogClust
, cChars
, i
);
601 for (; k
< cChars
&& pwLogClust
[k
] == i
; k
++)
605 class = GDEF_get_glyph_class(psc
->GDEF_Table
, pwGlyphs
[i
]);
611 pGlyphProp
[i
].sva
.fClusterStart
= 1;
612 pGlyphProp
[i
].sva
.fDiacritic
= 0;
613 pGlyphProp
[i
].sva
.fZeroWidth
= 0;
616 pGlyphProp
[i
].sva
.fClusterStart
= 1;
617 pGlyphProp
[i
].sva
.fDiacritic
= 0;
618 pGlyphProp
[i
].sva
.fZeroWidth
= 0;
621 pGlyphProp
[i
].sva
.fClusterStart
= 0;
622 pGlyphProp
[i
].sva
.fDiacritic
= 1;
623 pGlyphProp
[i
].sva
.fZeroWidth
= 1;
626 pGlyphProp
[i
].sva
.fClusterStart
= 0;
627 pGlyphProp
[i
].sva
.fDiacritic
= 0;
628 pGlyphProp
[i
].sva
.fZeroWidth
= 0;
631 ERR("Unknown glyph class %i\n",class);
632 pGlyphProp
[i
].sva
.fClusterStart
= 1;
633 pGlyphProp
[i
].sva
.fDiacritic
= 0;
634 pGlyphProp
[i
].sva
.fZeroWidth
= 0;
638 pGlyphProp
[i
].sva
.fClusterStart
= 0;
645 static INT
GSUB_apply_lookup(const OT_LookupList
* lookup
, INT lookup_index
, WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT
*glyph_count
);
647 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
649 const OT_CoverageFormat1
* cf1
;
653 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
655 int count
= GET_BE_WORD(cf1
->GlyphCount
);
657 TRACE("Coverage Format 1, %i glyphs\n",count
);
658 for (i
= 0; i
< count
; i
++)
659 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
663 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
665 const OT_CoverageFormat2
* cf2
;
668 cf2
= (const OT_CoverageFormat2
*)cf1
;
670 count
= GET_BE_WORD(cf2
->RangeCount
);
671 TRACE("Coverage Format 2, %i ranges\n",count
);
672 for (i
= 0; i
< count
; i
++)
674 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
676 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
677 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
679 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
680 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
686 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
691 static INT
GSUB_apply_SingleSubst(const OT_LookupTable
*look
, WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT
*glyph_count
)
694 TRACE("Single Substitution Subtable\n");
696 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
699 const GSUB_SingleSubstFormat1
*ssf1
;
700 offset
= GET_BE_WORD(look
->SubTable
[j
]);
701 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
702 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
704 int offset
= GET_BE_WORD(ssf1
->Coverage
);
705 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
706 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyphs
[glyph_index
]) != -1)
708 TRACE(" Glyph 0x%x ->",glyphs
[glyph_index
]);
709 glyphs
[glyph_index
] = glyphs
[glyph_index
] + GET_BE_WORD(ssf1
->DeltaGlyphID
);
710 TRACE(" 0x%x\n",glyphs
[glyph_index
]);
711 return glyph_index
+ write_dir
;
716 const GSUB_SingleSubstFormat2
*ssf2
;
720 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
721 offset
= GET_BE_WORD(ssf1
->Coverage
);
722 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
723 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyphs
[glyph_index
]);
724 TRACE(" Coverage index %i\n",index
);
727 if (glyphs
[glyph_index
] == GET_BE_WORD(ssf2
->Substitute
[index
]))
728 return GSUB_E_NOGLYPH
;
730 TRACE(" Glyph is 0x%x ->",glyphs
[glyph_index
]);
731 glyphs
[glyph_index
] = GET_BE_WORD(ssf2
->Substitute
[index
]);
732 TRACE("0x%x\n",glyphs
[glyph_index
]);
733 return glyph_index
+ write_dir
;
737 return GSUB_E_NOGLYPH
;
740 static INT
GSUB_apply_MultipleSubst(const OT_LookupTable
*look
, WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT
*glyph_count
)
743 TRACE("Multiple Substitution Subtable\n");
745 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
748 const GSUB_MultipleSubstFormat1
*msf1
;
749 offset
= GET_BE_WORD(look
->SubTable
[j
]);
750 msf1
= (const GSUB_MultipleSubstFormat1
*)((const BYTE
*)look
+offset
);
752 offset
= GET_BE_WORD(msf1
->Coverage
);
753 index
= GSUB_is_glyph_covered((const BYTE
*)msf1
+offset
, glyphs
[glyph_index
]);
756 const GSUB_Sequence
*seq
;
759 offset
= GET_BE_WORD(msf1
->Sequence
[index
]);
760 seq
= (const GSUB_Sequence
*)((const BYTE
*)msf1
+offset
);
761 sub_count
= GET_BE_WORD(seq
->GlyphCount
);
762 TRACE(" Glyph 0x%x (+%i)->",glyphs
[glyph_index
],(sub_count
-1));
764 for (j
= (*glyph_count
)+(sub_count
-1); j
> glyph_index
; j
--)
765 glyphs
[j
] =glyphs
[j
-(sub_count
-1)];
767 for (j
= 0; j
< sub_count
; j
++)
769 glyphs
[glyph_index
+ (sub_count
-1) - j
] = GET_BE_WORD(seq
->Substitute
[j
]);
771 glyphs
[glyph_index
+ j
] = GET_BE_WORD(seq
->Substitute
[j
]);
773 *glyph_count
= *glyph_count
+ (sub_count
- 1);
775 if (TRACE_ON(uniscribe
))
777 for (j
= 0; j
< sub_count
; j
++)
778 TRACE(" 0x%x",glyphs
[glyph_index
+j
]);
782 return glyph_index
+ (sub_count
* write_dir
);
785 return GSUB_E_NOGLYPH
;
788 static INT
GSUB_apply_AlternateSubst(const OT_LookupTable
*look
, WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT
*glyph_count
)
791 TRACE("Alternate Substitution Subtable\n");
793 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
796 const GSUB_AlternateSubstFormat1
*asf1
;
799 offset
= GET_BE_WORD(look
->SubTable
[j
]);
800 asf1
= (const GSUB_AlternateSubstFormat1
*)((const BYTE
*)look
+offset
);
801 offset
= GET_BE_WORD(asf1
->Coverage
);
803 index
= GSUB_is_glyph_covered((const BYTE
*)asf1
+offset
, glyphs
[glyph_index
]);
806 const GSUB_AlternateSet
*as
;
807 offset
= GET_BE_WORD(asf1
->AlternateSet
[index
]);
808 as
= (const GSUB_AlternateSet
*)((const BYTE
*)asf1
+offset
);
809 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as
->GlyphCount
));
810 if (glyphs
[glyph_index
] == GET_BE_WORD(as
->Alternate
[0]))
811 return GSUB_E_NOGLYPH
;
813 TRACE(" Glyph 0x%x ->",glyphs
[glyph_index
]);
814 glyphs
[glyph_index
] = GET_BE_WORD(as
->Alternate
[0]);
815 TRACE(" 0x%x\n",glyphs
[glyph_index
]);
816 return glyph_index
+ write_dir
;
819 return GSUB_E_NOGLYPH
;
822 static INT
GSUB_apply_LigatureSubst(const OT_LookupTable
*look
, WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT
*glyph_count
)
826 TRACE("Ligature Substitution Subtable\n");
827 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
829 const GSUB_LigatureSubstFormat1
*lsf1
;
832 offset
= GET_BE_WORD(look
->SubTable
[j
]);
833 lsf1
= (const GSUB_LigatureSubstFormat1
*)((const BYTE
*)look
+offset
);
834 offset
= GET_BE_WORD(lsf1
->Coverage
);
835 index
= GSUB_is_glyph_covered((const BYTE
*)lsf1
+offset
, glyphs
[glyph_index
]);
836 TRACE(" Coverage index %i\n",index
);
839 const GSUB_LigatureSet
*ls
;
842 offset
= GET_BE_WORD(lsf1
->LigatureSet
[index
]);
843 ls
= (const GSUB_LigatureSet
*)((const BYTE
*)lsf1
+offset
);
844 count
= GET_BE_WORD(ls
->LigatureCount
);
845 TRACE(" LigatureSet has %i members\n",count
);
846 for (k
= 0; k
< count
; k
++)
848 const GSUB_Ligature
*lig
;
849 int CompCount
,l
,CompIndex
;
851 offset
= GET_BE_WORD(ls
->Ligature
[k
]);
852 lig
= (const GSUB_Ligature
*)((const BYTE
*)ls
+offset
);
853 CompCount
= GET_BE_WORD(lig
->CompCount
) - 1;
854 CompIndex
= glyph_index
+write_dir
;
855 for (l
= 0; l
< CompCount
&& CompIndex
>= 0 && CompIndex
< *glyph_count
; l
++)
858 CompGlyph
= GET_BE_WORD(lig
->Component
[l
]);
859 if (CompGlyph
!= glyphs
[CompIndex
])
861 CompIndex
+= write_dir
;
865 int replaceIdx
= glyph_index
;
867 replaceIdx
= glyph_index
- CompCount
;
869 TRACE(" Glyph is 0x%x (+%i) ->",glyphs
[glyph_index
],CompCount
);
870 glyphs
[replaceIdx
] = GET_BE_WORD(lig
->LigGlyph
);
871 TRACE("0x%x\n",glyphs
[replaceIdx
]);
875 for (j
= replaceIdx
+ 1; j
< *glyph_count
; j
++)
876 glyphs
[j
] =glyphs
[j
+CompCount
];
877 *glyph_count
= *glyph_count
- CompCount
;
879 return replaceIdx
+ write_dir
;
884 return GSUB_E_NOGLYPH
;
887 static INT
GSUB_apply_ChainContextSubst(const OT_LookupList
* lookup
, const OT_LookupTable
*look
, WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT
*glyph_count
)
892 TRACE("Chaining Contextual Substitution Subtable\n");
893 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
) && !done
; j
++)
895 const GSUB_ChainContextSubstFormat1
*ccsf1
;
897 int dirLookahead
= write_dir
;
898 int dirBacktrack
= -1 * write_dir
;
900 offset
= GET_BE_WORD(look
->SubTable
[j
]);
901 ccsf1
= (const GSUB_ChainContextSubstFormat1
*)((const BYTE
*)look
+offset
);
902 if (GET_BE_WORD(ccsf1
->SubstFormat
) == 1)
904 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
907 else if (GET_BE_WORD(ccsf1
->SubstFormat
) == 2)
909 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
912 else if (GET_BE_WORD(ccsf1
->SubstFormat
) == 3)
916 const GSUB_ChainContextSubstFormat3_1
*ccsf3_1
;
917 const GSUB_ChainContextSubstFormat3_2
*ccsf3_2
;
918 const GSUB_ChainContextSubstFormat3_3
*ccsf3_3
;
919 const GSUB_ChainContextSubstFormat3_4
*ccsf3_4
;
920 int newIndex
= glyph_index
;
922 ccsf3_1
= (const GSUB_ChainContextSubstFormat3_1
*)ccsf1
;
924 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
926 for (k
= 0; k
< GET_BE_WORD(ccsf3_1
->BacktrackGlyphCount
); k
++)
928 offset
= GET_BE_WORD(ccsf3_1
->Coverage
[k
]);
929 if (GSUB_is_glyph_covered((const BYTE
*)ccsf3_1
+offset
, glyphs
[glyph_index
+ (dirBacktrack
* (k
+1))]) == -1)
932 if (k
!= GET_BE_WORD(ccsf3_1
->BacktrackGlyphCount
))
934 TRACE("Matched Backtrack\n");
936 ccsf3_2
= (const GSUB_ChainContextSubstFormat3_2
*)(((LPBYTE
)ccsf1
)+sizeof(GSUB_ChainContextSubstFormat3_1
) + (sizeof(WORD
) * (GET_BE_WORD(ccsf3_1
->BacktrackGlyphCount
)-1)));
938 indexGlyphs
= GET_BE_WORD(ccsf3_2
->InputGlyphCount
);
939 for (k
= 0; k
< indexGlyphs
; k
++)
941 offset
= GET_BE_WORD(ccsf3_2
->Coverage
[k
]);
942 if (GSUB_is_glyph_covered((const BYTE
*)ccsf3_1
+offset
, glyphs
[glyph_index
+ (write_dir
* k
)]) == -1)
945 if (k
!= indexGlyphs
)
947 TRACE("Matched IndexGlyphs\n");
949 ccsf3_3
= (const GSUB_ChainContextSubstFormat3_3
*)(((LPBYTE
)ccsf3_2
)+sizeof(GSUB_ChainContextSubstFormat3_2
) + (sizeof(WORD
) * (GET_BE_WORD(ccsf3_2
->InputGlyphCount
)-1)));
951 for (k
= 0; k
< GET_BE_WORD(ccsf3_3
->LookaheadGlyphCount
); k
++)
953 offset
= GET_BE_WORD(ccsf3_3
->Coverage
[k
]);
954 if (GSUB_is_glyph_covered((const BYTE
*)ccsf3_1
+offset
, glyphs
[glyph_index
+ (dirLookahead
* (indexGlyphs
+ k
))]) == -1)
957 if (k
!= GET_BE_WORD(ccsf3_3
->LookaheadGlyphCount
))
959 TRACE("Matched LookAhead\n");
961 ccsf3_4
= (const GSUB_ChainContextSubstFormat3_4
*)(((LPBYTE
)ccsf3_3
)+sizeof(GSUB_ChainContextSubstFormat3_3
) + (sizeof(WORD
) * (GET_BE_WORD(ccsf3_3
->LookaheadGlyphCount
)-1)));
963 if (GET_BE_WORD(ccsf3_4
->SubstCount
))
965 for (k
= 0; k
< GET_BE_WORD(ccsf3_4
->SubstCount
); k
++)
967 int lookupIndex
= GET_BE_WORD(ccsf3_4
->SubstLookupRecord
[k
].LookupListIndex
);
968 int SequenceIndex
= GET_BE_WORD(ccsf3_4
->SubstLookupRecord
[k
].SequenceIndex
) * write_dir
;
970 TRACE("SUBST: %i -> %i %i\n",k
, SequenceIndex
, lookupIndex
);
971 newIndex
= GSUB_apply_lookup(lookup
, lookupIndex
, glyphs
, glyph_index
+ SequenceIndex
, write_dir
, glyph_count
);
974 ERR("Chain failed to generate a glyph\n");
980 else return GSUB_E_NOGLYPH
;
986 static INT
GSUB_apply_lookup(const OT_LookupList
* lookup
, INT lookup_index
, WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT
*glyph_count
)
989 const OT_LookupTable
*look
;
991 offset
= GET_BE_WORD(lookup
->Lookup
[lookup_index
]);
992 look
= (const OT_LookupTable
*)((const BYTE
*)lookup
+ offset
);
993 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
994 switch(GET_BE_WORD(look
->LookupType
))
997 return GSUB_apply_SingleSubst(look
, glyphs
, glyph_index
, write_dir
, glyph_count
);
999 return GSUB_apply_MultipleSubst(look
, glyphs
, glyph_index
, write_dir
, glyph_count
);
1001 return GSUB_apply_AlternateSubst(look
, glyphs
, glyph_index
, write_dir
, glyph_count
);
1003 return GSUB_apply_LigatureSubst(look
, glyphs
, glyph_index
, write_dir
, glyph_count
);
1005 return GSUB_apply_ChainContextSubst(lookup
, look
, glyphs
, glyph_index
, write_dir
, glyph_count
);
1007 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look
->LookupType
));
1009 return GSUB_E_NOGLYPH
;
1012 INT
OpenType_apply_GSUB_lookup(LPCVOID table
, INT lookup_index
, WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT
*glyph_count
)
1014 const GSUB_Header
*header
= (const GSUB_Header
*)table
;
1015 const OT_LookupList
*lookup
= (const OT_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
1017 return GSUB_apply_lookup(lookup
, lookup_index
, glyphs
, glyph_index
, write_dir
, glyph_count
);
1023 static INT
GPOS_apply_lookup(LPOUTLINETEXTMETRICW lpotm
, LPLOGFONTW lplogfont
, INT
* piAdvance
, const OT_LookupList
* lookup
, INT lookup_index
, const WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT glyph_count
, GOFFSET
*pGoffset
);
1025 static INT
GPOS_get_device_table_value(const OT_DeviceTable
*DeviceTable
, WORD ppem
)
1027 static const WORD mask
[3] = {3,0xf,0xff};
1028 if (DeviceTable
&& ppem
>= GET_BE_WORD(DeviceTable
->StartSize
) && ppem
<= GET_BE_WORD(DeviceTable
->EndSize
))
1030 int format
= GET_BE_WORD(DeviceTable
->DeltaFormat
);
1031 int index
= ppem
- GET_BE_WORD(DeviceTable
->StartSize
);
1033 TRACE("device table, format %i, index %i\n",format
, index
);
1034 index
= index
<< format
;
1035 value
= (DeviceTable
->DeltaValue
[index
/sizeof(WORD
)] << (index
%sizeof(WORD
)))&mask
[format
-1];
1036 TRACE("offset %i, value %i\n",index
, value
);
1037 if (value
> mask
[format
-1]/2)
1038 value
= -1 * ((mask
[format
-1]+1) - value
);
1044 static VOID
GPOS_get_anchor_values(LPCVOID table
, LPPOINT pt
, WORD ppem
)
1046 const GPOS_AnchorFormat1
* anchor1
= (const GPOS_AnchorFormat1
*)table
;
1048 switch (GET_BE_WORD(anchor1
->AnchorFormat
))
1052 TRACE("Anchor Format 1\n");
1053 pt
->x
= (short)GET_BE_WORD(anchor1
->XCoordinate
);
1054 pt
->y
= (short)GET_BE_WORD(anchor1
->YCoordinate
);
1059 const GPOS_AnchorFormat2
* anchor2
= (const GPOS_AnchorFormat2
*)table
;
1060 TRACE("Anchor Format 2\n");
1061 pt
->x
= (short)GET_BE_WORD(anchor2
->XCoordinate
);
1062 pt
->y
= (short)GET_BE_WORD(anchor2
->YCoordinate
);
1068 const GPOS_AnchorFormat3
* anchor3
= (const GPOS_AnchorFormat3
*)table
;
1069 TRACE("Anchor Format 3\n");
1070 pt
->x
= (short)GET_BE_WORD(anchor3
->XCoordinate
);
1071 pt
->y
= (short)GET_BE_WORD(anchor3
->YCoordinate
);
1072 offset
= GET_BE_WORD(anchor3
->XDeviceTable
);
1073 TRACE("ppem %i\n",ppem
);
1076 const OT_DeviceTable
* DeviceTableX
= NULL
;
1077 DeviceTableX
= (const OT_DeviceTable
*)((const BYTE
*)anchor3
+ offset
);
1078 pt
->x
+= GPOS_get_device_table_value(DeviceTableX
, ppem
);
1080 offset
= GET_BE_WORD(anchor3
->YDeviceTable
);
1083 const OT_DeviceTable
* DeviceTableY
= NULL
;
1084 DeviceTableY
= (const OT_DeviceTable
*)((const BYTE
*)anchor3
+ offset
);
1085 pt
->y
+= GPOS_get_device_table_value(DeviceTableY
, ppem
);
1090 ERR("Unknown Anchor Format %i\n",GET_BE_WORD(anchor1
->AnchorFormat
));
1096 static void GPOS_convert_design_units_to_device(LPOUTLINETEXTMETRICW lpotm
, LPLOGFONTW lplogfont
, int desX
, int desY
, double *devX
, double *devY
)
1098 int emHeight
= lpotm
->otmTextMetrics
.tmAscent
+ lpotm
->otmTextMetrics
.tmDescent
- lpotm
->otmTextMetrics
.tmInternalLeading
;
1100 TRACE("emHeight %i lfWidth %i\n",emHeight
, lplogfont
->lfWidth
);
1101 *devX
= (desX
* emHeight
) / (double)lpotm
->otmEMSquare
;
1102 *devY
= (desY
* emHeight
) / (double)lpotm
->otmEMSquare
;
1103 if (lplogfont
->lfWidth
)
1104 FIXME("Font with lfWidth set no handled properly\n");
1107 static INT
GPOS_get_value_record(WORD ValueFormat
, const WORD data
[], GPOS_ValueRecord
*record
)
1110 if (ValueFormat
& 0x0001) record
->XPlacement
= GET_BE_WORD(data
[offset
++]);
1111 if (ValueFormat
& 0x0002) record
->YPlacement
= GET_BE_WORD(data
[offset
++]);
1112 if (ValueFormat
& 0x0004) record
->XAdvance
= GET_BE_WORD(data
[offset
++]);
1113 if (ValueFormat
& 0x0008) record
->YAdvance
= GET_BE_WORD(data
[offset
++]);
1114 if (ValueFormat
& 0x0010) record
->XPlaDevice
= GET_BE_WORD(data
[offset
++]);
1115 if (ValueFormat
& 0x0020) record
->YPlaDevice
= GET_BE_WORD(data
[offset
++]);
1116 if (ValueFormat
& 0x0040) record
->XAdvDevice
= GET_BE_WORD(data
[offset
++]);
1117 if (ValueFormat
& 0x0080) record
->YAdvDevice
= GET_BE_WORD(data
[offset
++]);
1121 static VOID
GPOS_get_value_record_offsets(const BYTE
* head
, GPOS_ValueRecord
*ValueRecord
, WORD ValueFormat
, INT ppem
, LPPOINT ptPlacement
, LPPOINT ptAdvance
)
1123 if (ValueFormat
& 0x0001) ptPlacement
->x
+= (short)ValueRecord
->XPlacement
;
1124 if (ValueFormat
& 0x0002) ptPlacement
->y
+= (short)ValueRecord
->YPlacement
;
1125 if (ValueFormat
& 0x0004) ptAdvance
->x
+= (short)ValueRecord
->XAdvance
;
1126 if (ValueFormat
& 0x0008) ptAdvance
->y
+= (short)ValueRecord
->YAdvance
;
1127 if (ValueFormat
& 0x0010) ptPlacement
->x
+= GPOS_get_device_table_value((const OT_DeviceTable
*)(head
+ ValueRecord
->XPlaDevice
), ppem
);
1128 if (ValueFormat
& 0x0020) ptPlacement
->y
+= GPOS_get_device_table_value((const OT_DeviceTable
*)(head
+ ValueRecord
->YPlaDevice
), ppem
);
1129 if (ValueFormat
& 0x0040) ptAdvance
->x
+= GPOS_get_device_table_value((const OT_DeviceTable
*)(head
+ ValueRecord
->XAdvDevice
), ppem
);
1130 if (ValueFormat
& 0x0080) ptAdvance
->y
+= GPOS_get_device_table_value((const OT_DeviceTable
*)(head
+ ValueRecord
->YAdvDevice
), ppem
);
1131 if (ValueFormat
& 0xFF00) FIXME("Unhandled Value Format %x\n",ValueFormat
&0xFF00);
1134 static VOID
GPOS_apply_SingleAdjustment(const OT_LookupTable
*look
, const WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT glyph_count
, INT ppem
, LPPOINT ptAdjust
, LPPOINT ptAdvance
)
1138 TRACE("Single Adjustment Positioning Subtable\n");
1140 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
1142 const GPOS_SinglePosFormat1
*spf1
;
1143 WORD offset
= GET_BE_WORD(look
->SubTable
[j
]);
1144 spf1
= (const GPOS_SinglePosFormat1
*)((const BYTE
*)look
+offset
);
1145 if (GET_BE_WORD(spf1
->PosFormat
) == 1)
1147 offset
= GET_BE_WORD(spf1
->Coverage
);
1148 if (GSUB_is_glyph_covered((const BYTE
*)spf1
+offset
, glyphs
[glyph_index
]) != -1)
1150 GPOS_ValueRecord ValueRecord
= {0,0,0,0,0,0,0,0};
1151 WORD ValueFormat
= GET_BE_WORD(spf1
->ValueFormat
);
1152 GPOS_get_value_record(ValueFormat
, spf1
->Value
, &ValueRecord
);
1153 GPOS_get_value_record_offsets((const BYTE
*)spf1
, &ValueRecord
, ValueFormat
, ppem
, ptAdjust
, ptAdvance
);
1154 TRACE("Glyph Adjusted by %i,%i\n",ValueRecord
.XPlacement
,ValueRecord
.YPlacement
);
1157 else if (GET_BE_WORD(spf1
->PosFormat
) == 2)
1160 const GPOS_SinglePosFormat2
*spf2
;
1161 spf2
= (const GPOS_SinglePosFormat2
*)spf1
;
1162 offset
= GET_BE_WORD(spf2
->Coverage
);
1163 index
= GSUB_is_glyph_covered((const BYTE
*)spf2
+offset
, glyphs
[glyph_index
]);
1167 GPOS_ValueRecord ValueRecord
= {0,0,0,0,0,0,0,0};
1168 WORD ValueFormat
= GET_BE_WORD(spf2
->ValueFormat
);
1169 size
= GPOS_get_value_record(ValueFormat
, spf2
->Value
, &ValueRecord
);
1172 offset
= size
* index
;
1173 GPOS_get_value_record(ValueFormat
, &spf2
->Value
[offset
], &ValueRecord
);
1175 GPOS_get_value_record_offsets((const BYTE
*)spf2
, &ValueRecord
, ValueFormat
, ppem
, ptAdjust
, ptAdvance
);
1176 TRACE("Glyph Adjusted by %i,%i\n",ValueRecord
.XPlacement
,ValueRecord
.YPlacement
);
1180 FIXME("Single Adjustment Positioning: Format %i Unhandled\n",GET_BE_WORD(spf1
->PosFormat
));
1184 static INT
GPOS_apply_PairAdjustment(const OT_LookupTable
*look
, const WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT glyph_count
, INT ppem
, LPPOINT ptAdjust
, LPPOINT ptAdvance
)
1188 TRACE("Pair Adjustment Positioning Subtable\n");
1190 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
1192 const GPOS_PairPosFormat1
*ppf1
;
1193 WORD offset
= GET_BE_WORD(look
->SubTable
[j
]);
1194 ppf1
= (const GPOS_PairPosFormat1
*)((const BYTE
*)look
+offset
);
1195 if (GET_BE_WORD(ppf1
->PosFormat
) == 1)
1198 offset
= GET_BE_WORD(ppf1
->Coverage
);
1199 index
= GSUB_is_glyph_covered((const BYTE
*)ppf1
+offset
, glyphs
[glyph_index
]);
1200 if (index
!= -1 && index
< GET_BE_WORD(ppf1
->PairSetCount
))
1204 const GPOS_PairSet
*ps
;
1205 offset
= GET_BE_WORD(ppf1
->PairSetOffset
[index
]);
1206 ps
= (const GPOS_PairSet
*)((const BYTE
*)ppf1
+offset
);
1207 pair_count
= GET_BE_WORD(ps
->PairValueCount
);
1208 for (k
= 0; k
< pair_count
; k
++)
1210 WORD second_glyph
= GET_BE_WORD(ps
->PairValueRecord
[k
].SecondGlyph
);
1211 if (glyphs
[glyph_index
+write_dir
] == second_glyph
)
1214 GPOS_ValueRecord ValueRecord1
= {0,0,0,0,0,0,0,0};
1215 GPOS_ValueRecord ValueRecord2
= {0,0,0,0,0,0,0,0};
1216 WORD ValueFormat1
= GET_BE_WORD(ppf1
->ValueFormat1
);
1217 WORD ValueFormat2
= GET_BE_WORD(ppf1
->ValueFormat2
);
1219 TRACE("Format 1: Found Pair %x,%x\n",glyphs
[glyph_index
],glyphs
[glyph_index
+write_dir
]);
1221 offset
= GPOS_get_value_record(ValueFormat1
, ps
->PairValueRecord
[k
].Value1
, &ValueRecord1
);
1222 GPOS_get_value_record(ValueFormat2
, (WORD
*)((const BYTE
*)(ps
->PairValueRecord
[k
].Value2
)+offset
), &ValueRecord2
);
1225 GPOS_get_value_record_offsets((const BYTE
*)ppf1
, &ValueRecord1
, ValueFormat1
, ppem
, &ptAdjust
[0], &ptAdvance
[0]);
1226 TRACE("Glyph 1 resulting cumulative offset is %i,%i design units\n",ptAdjust
[0].x
,ptAdjust
[0].y
);
1227 TRACE("Glyph 1 resulting cumulative advance is %i,%i design units\n",ptAdvance
[0].x
,ptAdvance
[0].y
);
1231 GPOS_get_value_record_offsets((const BYTE
*)ppf1
, &ValueRecord2
, ValueFormat2
, ppem
, &ptAdjust
[1], &ptAdvance
[1]);
1232 TRACE("Glyph 2 resulting cumulative offset is %i,%i design units\n",ptAdjust
[1].x
,ptAdjust
[1].y
);
1233 TRACE("Glyph 2 resulting cumulative advance is %i,%i design units\n",ptAdvance
[1].x
,ptAdvance
[1].y
);
1237 return glyph_index
+ next
;
1243 FIXME("Pair Adjustment Positioning: Format %i Unhandled\n",GET_BE_WORD(ppf1
->PosFormat
));
1245 return glyph_index
+1;
1248 static VOID
GPOS_apply_MarkToBase(const OT_LookupTable
*look
, const WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT glyph_count
, INT ppem
, LPPOINT pt
)
1252 TRACE("MarkToBase Attachment Positioning Subtable\n");
1254 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
1257 const GPOS_MarkBasePosFormat1
*mbpf1
;
1258 offset
= GET_BE_WORD(look
->SubTable
[j
]);
1259 mbpf1
= (const GPOS_MarkBasePosFormat1
*)((const BYTE
*)look
+offset
);
1260 if (GET_BE_WORD(mbpf1
->PosFormat
) == 1)
1262 int offset
= GET_BE_WORD(mbpf1
->MarkCoverage
);
1264 mark_index
= GSUB_is_glyph_covered((const BYTE
*)mbpf1
+offset
, glyphs
[glyph_index
]);
1265 if (mark_index
!= -1)
1268 offset
= GET_BE_WORD(mbpf1
->BaseCoverage
);
1269 base_index
= GSUB_is_glyph_covered((const BYTE
*)mbpf1
+offset
, glyphs
[glyph_index
- write_dir
]);
1270 if (base_index
!= -1)
1272 const GPOS_MarkArray
*ma
;
1273 const GPOS_MarkRecord
*mr
;
1274 const GPOS_BaseArray
*ba
;
1275 const GPOS_BaseRecord
*br
;
1277 int class_count
= GET_BE_WORD(mbpf1
->ClassCount
);
1278 int baserecord_size
;
1281 TRACE("Mark %x(%i) and base %x(%i)\n",glyphs
[glyph_index
], mark_index
, glyphs
[glyph_index
- write_dir
], base_index
);
1282 offset
= GET_BE_WORD(mbpf1
->MarkArray
);
1283 ma
= (const GPOS_MarkArray
*)((const BYTE
*)mbpf1
+ offset
);
1284 if (mark_index
> GET_BE_WORD(ma
->MarkCount
))
1286 ERR("Mark index exeeded mark count\n");
1289 mr
= &ma
->MarkRecord
[mark_index
];
1290 mark_class
= GET_BE_WORD(mr
->Class
);
1291 TRACE("Mark Class %i total classes %i\n",mark_class
,class_count
);
1292 offset
= GET_BE_WORD(mbpf1
->BaseArray
);
1293 ba
= (const GPOS_BaseArray
*)((const BYTE
*)mbpf1
+ offset
);
1294 baserecord_size
= class_count
* sizeof(WORD
);
1295 br
= (const GPOS_BaseRecord
*)((const BYTE
*)ba
+ sizeof(WORD
) + (baserecord_size
* base_index
));
1296 offset
= GET_BE_WORD(br
->BaseAnchor
[mark_class
]);
1297 GPOS_get_anchor_values((const BYTE
*)ba
+ offset
, &base_pt
, ppem
);
1298 offset
= GET_BE_WORD(mr
->MarkAnchor
);
1299 GPOS_get_anchor_values((const BYTE
*)ma
+ offset
, &mark_pt
, ppem
);
1300 TRACE("Offset on base is %i,%i design units\n",base_pt
.x
,base_pt
.y
);
1301 TRACE("Offset on mark is %i,%i design units\n",mark_pt
.x
, mark_pt
.y
);
1302 pt
->x
+= base_pt
.x
- mark_pt
.x
;
1303 pt
->y
+= base_pt
.y
- mark_pt
.y
;
1304 TRACE("Resulting cumulative offset is %i,%i design units\n",pt
->x
,pt
->y
);
1309 FIXME("Unhandled Mark To Base Format %i\n",GET_BE_WORD(mbpf1
->PosFormat
));
1313 static VOID
GPOS_apply_MarkToMark(const OT_LookupTable
*look
, const WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT glyph_count
, INT ppem
, LPPOINT pt
)
1317 TRACE("MarkToMark Attachment Positioning Subtable\n");
1319 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
1322 const GPOS_MarkMarkPosFormat1
*mmpf1
;
1323 offset
= GET_BE_WORD(look
->SubTable
[j
]);
1324 mmpf1
= (const GPOS_MarkMarkPosFormat1
*)((const BYTE
*)look
+offset
);
1325 if (GET_BE_WORD(mmpf1
->PosFormat
) == 1)
1327 int offset
= GET_BE_WORD(mmpf1
->Mark1Coverage
);
1329 mark_index
= GSUB_is_glyph_covered((const BYTE
*)mmpf1
+offset
, glyphs
[glyph_index
]);
1330 if (mark_index
!= -1)
1333 offset
= GET_BE_WORD(mmpf1
->Mark2Coverage
);
1334 mark2_index
= GSUB_is_glyph_covered((const BYTE
*)mmpf1
+offset
, glyphs
[glyph_index
- write_dir
]);
1335 if (mark2_index
!= -1)
1337 const GPOS_MarkArray
*ma
;
1338 const GPOS_MarkRecord
*mr
;
1339 const GPOS_Mark2Array
*m2a
;
1340 const GPOS_Mark2Record
*m2r
;
1342 int class_count
= GET_BE_WORD(mmpf1
->ClassCount
);
1343 int mark2record_size
;
1346 TRACE("Mark %x(%i) and Mark2 %x(%i)\n",glyphs
[glyph_index
], mark_index
, glyphs
[glyph_index
- write_dir
], mark2_index
);
1347 offset
= GET_BE_WORD(mmpf1
->Mark1Array
);
1348 ma
= (const GPOS_MarkArray
*)((const BYTE
*)mmpf1
+ offset
);
1349 if (mark_index
> GET_BE_WORD(ma
->MarkCount
))
1351 ERR("Mark index exeeded mark count\n");
1354 mr
= &ma
->MarkRecord
[mark_index
];
1355 mark_class
= GET_BE_WORD(mr
->Class
);
1356 TRACE("Mark Class %i total classes %i\n",mark_class
,class_count
);
1357 offset
= GET_BE_WORD(mmpf1
->Mark2Array
);
1358 m2a
= (const GPOS_Mark2Array
*)((const BYTE
*)mmpf1
+ offset
);
1359 mark2record_size
= class_count
* sizeof(WORD
);
1360 m2r
= (const GPOS_Mark2Record
*)((const BYTE
*)m2a
+ sizeof(WORD
) + (mark2record_size
* mark2_index
));
1361 offset
= GET_BE_WORD(m2r
->Mark2Anchor
[mark_class
]);
1362 GPOS_get_anchor_values((const BYTE
*)m2a
+ offset
, &mark2_pt
, ppem
);
1363 offset
= GET_BE_WORD(mr
->MarkAnchor
);
1364 GPOS_get_anchor_values((const BYTE
*)ma
+ offset
, &mark_pt
, ppem
);
1365 TRACE("Offset on mark2 is %i,%i design units\n",mark2_pt
.x
,mark2_pt
.y
);
1366 TRACE("Offset on mark is %i,%i design units\n",mark_pt
.x
, mark_pt
.y
);
1367 pt
->x
+= mark2_pt
.x
- mark_pt
.x
;
1368 pt
->y
+= mark2_pt
.y
- mark_pt
.y
;
1369 TRACE("Resulting cumulative offset is %i,%i design units\n",pt
->x
,pt
->y
);
1374 FIXME("Unhandled Mark To Mark Format %i\n",GET_BE_WORD(mmpf1
->PosFormat
));
1378 static INT
GPOS_apply_ChainContextPos(LPOUTLINETEXTMETRICW lpotm
, LPLOGFONTW lplogfont
, INT
* piAdvance
, const OT_LookupList
*lookup
, const OT_LookupTable
*look
, const WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT glyph_count
, INT ppem
, GOFFSET
*pGoffset
)
1382 TRACE("Chaining Contextual Positioning Subtable\n");
1384 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
1387 const GPOS_ChainContextPosFormat3_1
*ccpf3
;
1388 int dirLookahead
= write_dir
;
1389 int dirBacktrack
= -1 * write_dir
;
1391 offset
= GET_BE_WORD(look
->SubTable
[j
]);
1392 ccpf3
= (const GPOS_ChainContextPosFormat3_1
*)((const BYTE
*)look
+offset
);
1394 if (GET_BE_WORD(ccpf3
->PosFormat
) == 1)
1396 FIXME(" TODO: subtype 1 (Simple Chaining Context Glyph Positioning)\n");
1399 else if (GET_BE_WORD(ccpf3
->PosFormat
) == 2)
1401 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Positioning)\n");
1404 else if (GET_BE_WORD(ccpf3
->PosFormat
) == 3)
1408 const GPOS_ChainContextPosFormat3_2
*ccpf3_2
;
1409 const GPOS_ChainContextPosFormat3_3
*ccpf3_3
;
1410 const GPOS_ChainContextPosFormat3_4
*ccpf3_4
;
1412 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Positioning)\n");
1414 for (k
= 0; k
< GET_BE_WORD(ccpf3
->BacktrackGlyphCount
); k
++)
1416 offset
= GET_BE_WORD(ccpf3
->Coverage
[k
]);
1417 if (GSUB_is_glyph_covered((const BYTE
*)ccpf3
+offset
, glyphs
[glyph_index
+ (dirBacktrack
* (k
+1))]) == -1)
1420 if (k
!= GET_BE_WORD(ccpf3
->BacktrackGlyphCount
))
1422 TRACE("Matched Backtrack\n");
1424 ccpf3_2
= (const GPOS_ChainContextPosFormat3_2
*)(((LPBYTE
)ccpf3
)+sizeof(GPOS_ChainContextPosFormat3_1
) + (sizeof(WORD
) * (GET_BE_WORD(ccpf3
->BacktrackGlyphCount
)-1)));
1426 indexGlyphs
= GET_BE_WORD(ccpf3_2
->InputGlyphCount
);
1427 for (k
= 0; k
< indexGlyphs
; k
++)
1429 offset
= GET_BE_WORD(ccpf3_2
->Coverage
[k
]);
1430 if (GSUB_is_glyph_covered((const BYTE
*)ccpf3
+offset
, glyphs
[glyph_index
+ (write_dir
* k
)]) == -1)
1433 if (k
!= indexGlyphs
)
1435 TRACE("Matched IndexGlyphs\n");
1437 ccpf3_3
= (const GPOS_ChainContextPosFormat3_3
*)(((LPBYTE
)ccpf3_2
)+sizeof(GPOS_ChainContextPosFormat3_2
) + (sizeof(WORD
) * (GET_BE_WORD(ccpf3_2
->InputGlyphCount
)-1)));
1439 for (k
= 0; k
< GET_BE_WORD(ccpf3_3
->LookaheadGlyphCount
); k
++)
1441 offset
= GET_BE_WORD(ccpf3_3
->Coverage
[k
]);
1442 if (GSUB_is_glyph_covered((const BYTE
*)ccpf3
+offset
, glyphs
[glyph_index
+ (dirLookahead
* (indexGlyphs
+ k
))]) == -1)
1445 if (k
!= GET_BE_WORD(ccpf3_3
->LookaheadGlyphCount
))
1447 TRACE("Matched LookAhead\n");
1449 ccpf3_4
= (const GPOS_ChainContextPosFormat3_4
*)(((LPBYTE
)ccpf3_3
)+sizeof(GPOS_ChainContextPosFormat3_3
) + (sizeof(WORD
) * (GET_BE_WORD(ccpf3_3
->LookaheadGlyphCount
)-1)));
1451 if (GET_BE_WORD(ccpf3_4
->PosCount
))
1453 for (k
= 0; k
< GET_BE_WORD(ccpf3_4
->PosCount
); k
++)
1455 int lookupIndex
= GET_BE_WORD(ccpf3_4
->PosLookupRecord
[k
].LookupListIndex
);
1456 int SequenceIndex
= GET_BE_WORD(ccpf3_4
->PosLookupRecord
[k
].SequenceIndex
) * write_dir
;
1458 TRACE("Position: %i -> %i %i\n",k
, SequenceIndex
, lookupIndex
);
1459 GPOS_apply_lookup(lpotm
, lplogfont
, piAdvance
, lookup
, lookupIndex
, glyphs
, glyph_index
+ SequenceIndex
, write_dir
, glyph_count
, pGoffset
);
1461 return glyph_index
+ indexGlyphs
+ GET_BE_WORD(ccpf3_3
->LookaheadGlyphCount
);
1463 else return glyph_index
+ 1;
1466 FIXME("Unhandled Chaining Contextual Positioning Format %i\n",GET_BE_WORD(ccpf3
->PosFormat
));
1468 return glyph_index
+ 1;
1471 static INT
GPOS_apply_lookup(LPOUTLINETEXTMETRICW lpotm
, LPLOGFONTW lplogfont
, INT
* piAdvance
, const OT_LookupList
* lookup
, INT lookup_index
, const WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT glyph_count
, GOFFSET
*pGoffset
)
1474 const OT_LookupTable
*look
;
1475 int ppem
= lpotm
->otmTextMetrics
.tmAscent
+ lpotm
->otmTextMetrics
.tmDescent
- lpotm
->otmTextMetrics
.tmInternalLeading
;
1477 offset
= GET_BE_WORD(lookup
->Lookup
[lookup_index
]);
1478 look
= (const OT_LookupTable
*)((const BYTE
*)lookup
+ offset
);
1479 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
1480 switch(GET_BE_WORD(look
->LookupType
))
1485 POINT adjust
= {0,0};
1486 POINT advance
= {0,0};
1487 GPOS_apply_SingleAdjustment(look
, glyphs
, glyph_index
, write_dir
, glyph_count
, ppem
, &adjust
, &advance
);
1488 if (adjust
.x
|| adjust
.y
)
1490 GPOS_convert_design_units_to_device(lpotm
, lplogfont
, adjust
.x
, adjust
.y
, &devX
, &devY
);
1491 pGoffset
[glyph_index
].du
+= round(devX
);
1492 pGoffset
[glyph_index
].dv
+= round(devY
);
1494 if (advance
.x
|| advance
.y
)
1496 GPOS_convert_design_units_to_device(lpotm
, lplogfont
, advance
.x
, advance
.y
, &devX
, &devY
);
1497 piAdvance
[glyph_index
] += round(devX
);
1499 FIXME("Unhandled adjustment to Y advancement\n");
1504 POINT advance
[2]= {{0,0},{0,0}};
1505 POINT adjust
[2]= {{0,0},{0,0}};
1508 index
= GPOS_apply_PairAdjustment(look
, glyphs
, glyph_index
, write_dir
, glyph_count
, ppem
, adjust
, advance
);
1509 if (adjust
[0].x
|| adjust
[0].y
)
1511 GPOS_convert_design_units_to_device(lpotm
, lplogfont
, adjust
[0].x
, adjust
[0].y
, &devX
, &devY
);
1512 pGoffset
[glyph_index
].du
+= round(devX
);
1513 pGoffset
[glyph_index
].dv
+= round(devY
);
1515 if (advance
[0].x
|| advance
[0].y
)
1517 GPOS_convert_design_units_to_device(lpotm
, lplogfont
, advance
[0].x
, advance
[0].y
, &devX
, &devY
);
1518 piAdvance
[glyph_index
] += round(devX
);
1520 if (adjust
[1].x
|| adjust
[1].y
)
1522 GPOS_convert_design_units_to_device(lpotm
, lplogfont
, adjust
[1].x
, adjust
[1].y
, &devX
, &devY
);
1523 pGoffset
[glyph_index
+ write_dir
].du
+= round(devX
);
1524 pGoffset
[glyph_index
+ write_dir
].dv
+= round(devY
);
1526 if (advance
[1].x
|| advance
[1].y
)
1528 GPOS_convert_design_units_to_device(lpotm
, lplogfont
, advance
[1].x
, advance
[1].y
, &devX
, &devY
);
1529 piAdvance
[glyph_index
+ write_dir
] += round(devX
);
1537 GPOS_apply_MarkToBase(look
, glyphs
, glyph_index
, write_dir
, glyph_count
, ppem
, &desU
);
1538 if (desU
.x
|| desU
.y
)
1540 GPOS_convert_design_units_to_device(lpotm
, lplogfont
, desU
.x
, desU
.y
, &devX
, &devY
);
1541 pGoffset
[glyph_index
].du
+= (round(devX
) - piAdvance
[glyph_index
-1]);
1542 pGoffset
[glyph_index
].dv
+= round(devY
);
1550 GPOS_apply_MarkToMark(look
, glyphs
, glyph_index
, write_dir
, glyph_count
, ppem
, &desU
);
1551 if (desU
.x
|| desU
.y
)
1553 GPOS_convert_design_units_to_device(lpotm
, lplogfont
, desU
.x
, desU
.y
, &devX
, &devY
);
1554 pGoffset
[glyph_index
].du
+= round(devX
) + pGoffset
[glyph_index
-1].du
;
1555 pGoffset
[glyph_index
].dv
+= round(devY
) + pGoffset
[glyph_index
-1].dv
;
1561 return GPOS_apply_ChainContextPos(lpotm
, lplogfont
, piAdvance
, lookup
, look
, glyphs
, glyph_index
, write_dir
, glyph_count
, ppem
, pGoffset
);
1564 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look
->LookupType
));
1566 return glyph_index
+1;
1569 INT
OpenType_apply_GPOS_lookup(LPOUTLINETEXTMETRICW lpotm
, LPLOGFONTW lplogfont
, INT
* piAdvance
, LPCVOID table
, INT lookup_index
, const WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT glyph_count
, GOFFSET
*pGoffset
)
1571 const GPOS_Header
*header
= (const GPOS_Header
*)table
;
1572 const OT_LookupList
*lookup
= (const OT_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
1574 return GPOS_apply_lookup(lpotm
, lplogfont
, piAdvance
, lookup
, lookup_index
, glyphs
, glyph_index
, write_dir
, glyph_count
, pGoffset
);
1577 static void GSUB_initialize_script_cache(ScriptCache
*psc
)
1581 if (psc
->GSUB_Table
)
1583 const OT_ScriptList
*script
;
1584 const GSUB_Header
* header
= (const GSUB_Header
*)psc
->GSUB_Table
;
1585 script
= (const OT_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
1586 psc
->script_count
= GET_BE_WORD(script
->ScriptCount
);
1587 TRACE("initializing %i scripts in this font\n",psc
->script_count
);
1588 if (psc
->script_count
)
1590 psc
->scripts
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(LoadedScript
) * psc
->script_count
);
1591 for (i
= 0; i
< psc
->script_count
; i
++)
1593 int offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
1594 psc
->scripts
[i
].tag
= MS_MAKE_TAG(script
->ScriptRecord
[i
].ScriptTag
[0], script
->ScriptRecord
[i
].ScriptTag
[1], script
->ScriptRecord
[i
].ScriptTag
[2], script
->ScriptRecord
[i
].ScriptTag
[3]);
1595 psc
->scripts
[i
].gsub_table
= ((const BYTE
*)script
+ offset
);
1601 static void GPOS_expand_script_cache(ScriptCache
*psc
)
1604 const OT_ScriptList
*script
;
1605 const GPOS_Header
* header
= (const GPOS_Header
*)psc
->GPOS_Table
;
1610 script
= (const OT_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
1611 count
= GET_BE_WORD(script
->ScriptCount
);
1613 if (!psc
->script_count
)
1615 psc
->script_count
= count
;
1616 TRACE("initializing %i scripts in this font\n",psc
->script_count
);
1617 if (psc
->script_count
)
1619 psc
->scripts
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(LoadedScript
) * psc
->script_count
);
1620 for (i
= 0; i
< psc
->script_count
; i
++)
1622 int offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
1623 psc
->scripts
[i
].tag
= MS_MAKE_TAG(script
->ScriptRecord
[i
].ScriptTag
[0], script
->ScriptRecord
[i
].ScriptTag
[1], script
->ScriptRecord
[i
].ScriptTag
[2], script
->ScriptRecord
[i
].ScriptTag
[3]);
1624 psc
->scripts
[i
].gpos_table
= ((const BYTE
*)script
+ offset
);
1630 for (i
= 0; i
< count
; i
++)
1633 int offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
1634 OPENTYPE_TAG tag
= MS_MAKE_TAG(script
->ScriptRecord
[i
].ScriptTag
[0], script
->ScriptRecord
[i
].ScriptTag
[1], script
->ScriptRecord
[i
].ScriptTag
[2], script
->ScriptRecord
[i
].ScriptTag
[3]);
1635 for (j
= 0; j
< psc
->script_count
; j
++)
1637 if (psc
->scripts
[j
].tag
== tag
)
1639 psc
->scripts
[j
].gpos_table
= ((const BYTE
*)script
+ offset
);
1643 if (j
== psc
->script_count
)
1645 psc
->script_count
++;
1646 psc
->scripts
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,psc
->scripts
, sizeof(LoadedScript
) * psc
->script_count
);
1647 psc
->scripts
[j
].tag
= tag
;
1648 psc
->scripts
[j
].gpos_table
= ((const BYTE
*)script
+ offset
);
1654 static void _initialize_script_cache(ScriptCache
*psc
)
1656 if (!psc
->script_count
)
1658 GSUB_initialize_script_cache(psc
);
1659 GPOS_expand_script_cache(psc
);
1663 HRESULT
OpenType_GetFontScriptTags(ScriptCache
*psc
, OPENTYPE_TAG searchingFor
, int cMaxTags
, OPENTYPE_TAG
*pScriptTags
, int *pcTags
)
1668 _initialize_script_cache(psc
);
1670 *pcTags
= psc
->script_count
;
1672 if (!searchingFor
&& cMaxTags
< *pcTags
)
1674 else if (searchingFor
)
1675 rc
= USP_E_SCRIPT_NOT_IN_FONT
;
1677 for (i
= 0; i
< psc
->script_count
; i
++)
1680 pScriptTags
[i
] = psc
->scripts
[i
].tag
;
1684 if (searchingFor
== psc
->scripts
[i
].tag
)
1686 pScriptTags
[0] = psc
->scripts
[i
].tag
;
1696 static void GSUB_initialize_language_cache(LoadedScript
*script
)
1700 if (script
->gsub_table
)
1703 const OT_Script
* table
= script
->gsub_table
;
1704 script
->language_count
= GET_BE_WORD(table
->LangSysCount
);
1705 offset
= GET_BE_WORD(table
->DefaultLangSys
);
1708 script
->default_language
.tag
= MS_MAKE_TAG('d','f','l','t');
1709 script
->default_language
.gsub_table
= (const BYTE
*)table
+ offset
;
1712 if (script
->language_count
)
1714 TRACE("Deflang %p, LangCount %i\n",script
->default_language
.gsub_table
, script
->language_count
);
1716 script
->languages
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(LoadedLanguage
) * script
->language_count
);
1718 for (i
= 0; i
< script
->language_count
; i
++)
1720 int offset
= GET_BE_WORD(table
->LangSysRecord
[i
].LangSys
);
1721 script
->languages
[i
].tag
= MS_MAKE_TAG(table
->LangSysRecord
[i
].LangSysTag
[0], table
->LangSysRecord
[i
].LangSysTag
[1], table
->LangSysRecord
[i
].LangSysTag
[2], table
->LangSysRecord
[i
].LangSysTag
[3]);
1722 script
->languages
[i
].gsub_table
= ((const BYTE
*)table
+ offset
);
1728 static void GPOS_expand_language_cache(LoadedScript
*script
)
1731 const OT_Script
* table
= script
->gpos_table
;
1737 offset
= GET_BE_WORD(table
->DefaultLangSys
);
1739 script
->default_language
.gpos_table
= (const BYTE
*)table
+ offset
;
1741 count
= GET_BE_WORD(table
->LangSysCount
);
1743 TRACE("Deflang %p, LangCount %i\n",script
->default_language
.gpos_table
, count
);
1744 if (!script
->language_count
)
1747 script
->language_count
= count
;
1749 script
->languages
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(LoadedLanguage
) * script
->language_count
);
1751 for (i
= 0; i
< script
->language_count
; i
++)
1753 int offset
= GET_BE_WORD(table
->LangSysRecord
[i
].LangSys
);
1754 script
->languages
[i
].tag
= MS_MAKE_TAG(table
->LangSysRecord
[i
].LangSysTag
[0], table
->LangSysRecord
[i
].LangSysTag
[1], table
->LangSysRecord
[i
].LangSysTag
[2], table
->LangSysRecord
[i
].LangSysTag
[3]);
1755 script
->languages
[i
].gpos_table
= ((const BYTE
*)table
+ offset
);
1761 for (i
= 0; i
< count
; i
++)
1763 int offset
= GET_BE_WORD(table
->LangSysRecord
[i
].LangSys
);
1764 OPENTYPE_TAG tag
= MS_MAKE_TAG(table
->LangSysRecord
[i
].LangSysTag
[0], table
->LangSysRecord
[i
].LangSysTag
[1], table
->LangSysRecord
[i
].LangSysTag
[2], table
->LangSysRecord
[i
].LangSysTag
[3]);
1766 for (j
= 0; j
< script
->language_count
; j
++)
1768 if (script
->languages
[j
].tag
== tag
)
1770 script
->languages
[j
].gpos_table
= ((const BYTE
*)table
+ offset
);
1774 if (j
== script
->language_count
)
1776 script
->language_count
++;
1777 script
->languages
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,script
->languages
, sizeof(LoadedLanguage
) * script
->language_count
);
1778 script
->languages
[j
].tag
= tag
;
1779 script
->languages
[j
].gpos_table
= ((const BYTE
*)table
+ offset
);
1785 static void _initialize_language_cache(LoadedScript
*script
)
1787 if (!script
->language_count
)
1789 GSUB_initialize_language_cache(script
);
1790 GPOS_expand_language_cache(script
);
1794 HRESULT
OpenType_GetFontLanguageTags(ScriptCache
*psc
, OPENTYPE_TAG script_tag
, OPENTYPE_TAG searchingFor
, int cMaxTags
, OPENTYPE_TAG
*pLanguageTags
, int *pcTags
)
1798 LoadedScript
*script
= NULL
;
1800 _initialize_script_cache(psc
);
1802 for (i
= 0; i
< psc
->script_count
; i
++)
1804 if (psc
->scripts
[i
].tag
== script_tag
)
1806 script
= &psc
->scripts
[i
];
1812 return E_INVALIDARG
;
1814 _initialize_language_cache(script
);
1816 if (!searchingFor
&& cMaxTags
< script
->language_count
)
1818 else if (searchingFor
)
1821 *pcTags
= script
->language_count
;
1823 for (i
= 0; i
< script
->language_count
; i
++)
1826 pLanguageTags
[i
] = script
->languages
[i
].tag
;
1830 if (searchingFor
== script
->languages
[i
].tag
)
1832 pLanguageTags
[0] = script
->languages
[i
].tag
;
1840 if (script
->default_language
.gsub_table
)
1843 pLanguageTags
[i
] = script
->default_language
.tag
;
1845 if (searchingFor
&& FAILED(rc
))
1847 pLanguageTags
[0] = script
->default_language
.tag
;
1850 *pcTags
= (*pcTags
) + 1;
1857 static void GSUB_initialize_feature_cache(LPCVOID table
, LoadedLanguage
*language
)
1861 if (language
->gsub_table
)
1863 const OT_LangSys
*lang
= language
->gsub_table
;
1864 const GSUB_Header
*header
= (const GSUB_Header
*)table
;
1865 const OT_FeatureList
*feature_list
;
1867 language
->feature_count
= GET_BE_WORD(lang
->FeatureCount
);
1868 TRACE("%i features\n",language
->feature_count
);
1870 if (language
->feature_count
)
1872 language
->features
= HeapAlloc(GetProcessHeap(),0,sizeof(LoadedFeature
)*language
->feature_count
);
1874 feature_list
= (const OT_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
1876 for (i
= 0; i
< language
->feature_count
; i
++)
1878 const OT_Feature
*feature
;
1880 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
1882 language
->features
[i
].tag
= MS_MAKE_TAG(feature_list
->FeatureRecord
[index
].FeatureTag
[0], feature_list
->FeatureRecord
[index
].FeatureTag
[1], feature_list
->FeatureRecord
[index
].FeatureTag
[2], feature_list
->FeatureRecord
[index
].FeatureTag
[3]);
1883 language
->features
[i
].feature
= ((const BYTE
*)feature_list
+ GET_BE_WORD(feature_list
->FeatureRecord
[index
].Feature
));
1884 feature
= (const OT_Feature
*)language
->features
[i
].feature
;
1885 language
->features
[i
].lookup_count
= GET_BE_WORD(feature
->LookupCount
);
1886 language
->features
[i
].lookups
= HeapAlloc(GetProcessHeap(),0,sizeof(WORD
) * language
->features
[i
].lookup_count
);
1887 for (j
= 0; j
< language
->features
[i
].lookup_count
; j
++)
1888 language
->features
[i
].lookups
[j
] = GET_BE_WORD(feature
->LookupListIndex
[j
]);
1894 static void GPOS_expand_feature_cache(LPCVOID table
, LoadedLanguage
*language
)
1897 const OT_LangSys
*lang
= language
->gpos_table
;
1898 const GPOS_Header
*header
= (const GPOS_Header
*)table
;
1899 const OT_FeatureList
*feature_list
;
1904 count
= GET_BE_WORD(lang
->FeatureCount
);
1905 feature_list
= (const OT_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
1907 TRACE("%i features\n",count
);
1908 if (!language
->feature_count
)
1910 language
->feature_count
= count
;
1912 if (language
->feature_count
)
1914 language
->features
= HeapAlloc(GetProcessHeap(),0,sizeof(LoadedFeature
)*language
->feature_count
);
1916 for (i
= 0; i
< language
->feature_count
; i
++)
1918 const OT_Feature
*feature
;
1920 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
1922 language
->features
[i
].tag
= MS_MAKE_TAG(feature_list
->FeatureRecord
[index
].FeatureTag
[0], feature_list
->FeatureRecord
[index
].FeatureTag
[1], feature_list
->FeatureRecord
[index
].FeatureTag
[2], feature_list
->FeatureRecord
[index
].FeatureTag
[3]);
1923 language
->features
[i
].feature
= ((const BYTE
*)feature_list
+ GET_BE_WORD(feature_list
->FeatureRecord
[index
].Feature
));
1924 feature
= (const OT_Feature
*)language
->features
[i
].feature
;
1925 language
->features
[i
].lookup_count
= GET_BE_WORD(feature
->LookupCount
);
1926 language
->features
[i
].lookups
= HeapAlloc(GetProcessHeap(),0,sizeof(WORD
) * language
->features
[i
].lookup_count
);
1927 for (j
= 0; j
< language
->features
[i
].lookup_count
; j
++)
1928 language
->features
[i
].lookups
[j
] = GET_BE_WORD(feature
->LookupListIndex
[j
]);
1934 language
->features
= HeapReAlloc(GetProcessHeap(),0,language
->features
, sizeof(LoadedFeature
)*(language
->feature_count
+ count
));
1936 for (i
= 0; i
< count
; i
++)
1938 const OT_Feature
*feature
;
1940 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
1941 int idx
= language
->feature_count
+ i
;
1943 language
->features
[idx
].tag
= MS_MAKE_TAG(feature_list
->FeatureRecord
[index
].FeatureTag
[0], feature_list
->FeatureRecord
[index
].FeatureTag
[1], feature_list
->FeatureRecord
[index
].FeatureTag
[2], feature_list
->FeatureRecord
[index
].FeatureTag
[3]);
1944 language
->features
[idx
].feature
= ((const BYTE
*)feature_list
+ GET_BE_WORD(feature_list
->FeatureRecord
[index
].Feature
));
1945 feature
= (const OT_Feature
*)language
->features
[idx
].feature
;
1946 language
->features
[idx
].lookup_count
= GET_BE_WORD(feature
->LookupCount
);
1947 language
->features
[idx
].lookups
= HeapAlloc(GetProcessHeap(),0,sizeof(WORD
) * language
->features
[idx
].lookup_count
);
1948 for (j
= 0; j
< language
->features
[idx
].lookup_count
; j
++)
1949 language
->features
[idx
].lookups
[j
] = GET_BE_WORD(feature
->LookupListIndex
[j
]);
1951 language
->feature_count
+= count
;
1955 static void _initialize_feature_cache(ScriptCache
*psc
, LoadedLanguage
*language
)
1957 if (!language
->feature_count
)
1959 GSUB_initialize_feature_cache(psc
->GSUB_Table
, language
);
1960 GPOS_expand_feature_cache(psc
->GPOS_Table
, language
);
1964 HRESULT
OpenType_GetFontFeatureTags(ScriptCache
*psc
, OPENTYPE_TAG script_tag
, OPENTYPE_TAG language_tag
, BOOL filtered
, OPENTYPE_TAG searchingFor
, int cMaxTags
, OPENTYPE_TAG
*pFeatureTags
, int *pcTags
, LoadedFeature
** feature
)
1968 LoadedScript
*script
= NULL
;
1969 LoadedLanguage
*language
= NULL
;
1971 _initialize_script_cache(psc
);
1973 for (i
= 0; i
< psc
->script_count
; i
++)
1975 if (psc
->scripts
[i
].tag
== script_tag
)
1977 script
= &psc
->scripts
[i
];
1988 return E_INVALIDARG
;
1991 _initialize_language_cache(script
);
1993 if ((script
->default_language
.gsub_table
|| script
->default_language
.gpos_table
) && script
->default_language
.tag
== language_tag
)
1994 language
= &script
->default_language
;
1997 for (i
= 0; i
< script
->language_count
; i
++)
1999 if (script
->languages
[i
].tag
== language_tag
)
2001 language
= &script
->languages
[i
];
2013 _initialize_feature_cache(psc
, language
);
2015 *pcTags
= language
->feature_count
;
2017 if (!searchingFor
&& cMaxTags
< *pcTags
)
2019 else if (searchingFor
)
2022 for (i
= 0; i
< language
->feature_count
; i
++)
2025 pFeatureTags
[i
] = language
->features
[i
].tag
;
2029 if (searchingFor
== language
->features
[i
].tag
)
2031 pFeatureTags
[0] = language
->features
[i
].tag
;
2034 *feature
= &language
->features
[i
];