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 /* These are all structures needed for the cmap format 12 table */
47 #define CMAP_TAG MS_MAKE_TAG('c', 'm', 'a', 'p')
53 } CMAP_EncodingRecord
;
58 CMAP_EncodingRecord tables
[1];
65 } CMAP_SegmentedCoverage_group
;
73 CMAP_SegmentedCoverage_group groups
[1];
74 } CMAP_SegmentedCoverage
;
76 /* These are all structures needed for the GDEF table */
77 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
79 enum {BaseGlyph
=1, LigatureGlyph
, MarkGlyph
, ComponentGlyph
};
86 WORD MarkAttachClassDef
;
93 WORD ClassValueArray
[1];
94 } GDEF_ClassDefFormat1
;
100 } GDEF_ClassRangeRecord
;
104 WORD ClassRangeCount
;
105 GDEF_ClassRangeRecord ClassRangeRecord
[1];
106 } GDEF_ClassDefFormat2
;
108 /* These are all structures needed for the GSUB table */
124 OT_ScriptRecord ScriptRecord
[1];
135 OT_LangSysRecord LangSysRecord
[1];
139 WORD LookupOrder
; /* Reserved */
140 WORD ReqFeatureIndex
;
142 WORD FeatureIndex
[1];
152 OT_FeatureRecord FeatureRecord
[1];
156 WORD FeatureParams
; /* Reserved */
158 WORD LookupListIndex
[1];
177 } OT_CoverageFormat1
;
182 WORD StartCoverageIndex
;
188 OT_RangeRecord RangeRecord
[1];
189 } OT_CoverageFormat2
;
192 WORD SubstFormat
; /* = 1 */
195 } GSUB_SingleSubstFormat1
;
198 WORD SubstFormat
; /* = 2 */
202 }GSUB_SingleSubstFormat2
;
205 WORD SubstFormat
; /* = 1 */
209 }GSUB_MultipleSubstFormat1
;
217 WORD SubstFormat
; /* = 1 */
221 }GSUB_LigatureSubstFormat1
;
236 WORD LookupListIndex
;
238 }GSUB_SubstLookupRecord
;
241 WORD SubstFormat
; /* = 1 */
243 WORD ChainSubRuleSetCount
;
244 WORD ChainSubRuleSet
[1];
245 }GSUB_ChainContextSubstFormat1
;
248 WORD SubstFormat
; /* = 3 */
249 WORD BacktrackGlyphCount
;
251 }GSUB_ChainContextSubstFormat3_1
;
254 WORD InputGlyphCount
;
256 }GSUB_ChainContextSubstFormat3_2
;
259 WORD LookaheadGlyphCount
;
261 }GSUB_ChainContextSubstFormat3_3
;
265 GSUB_SubstLookupRecord SubstLookupRecord
[1];
266 }GSUB_ChainContextSubstFormat3_4
;
269 WORD SubstFormat
; /* = 1 */
271 WORD AlternateSetCount
;
272 WORD AlternateSet
[1];
273 } GSUB_AlternateSubstFormat1
;
280 /* These are all structures needed for the GPOS table */
293 static VOID
*load_CMAP_format12_table(HDC hdc
, ScriptCache
*psc
)
295 CMAP_Header
*CMAP_Table
= NULL
;
299 if (!psc
->CMAP_Table
)
301 length
= GetFontData(hdc
, CMAP_TAG
, 0, NULL
, 0);
302 if (length
!= GDI_ERROR
)
304 psc
->CMAP_Table
= HeapAlloc(GetProcessHeap(),0,length
);
305 GetFontData(hdc
, CMAP_TAG
, 0, psc
->CMAP_Table
, length
);
306 TRACE("Loaded cmap table of %i bytes\n",length
);
312 CMAP_Table
= psc
->CMAP_Table
;
314 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
); i
++)
316 if ( (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) == 3) &&
317 (GET_BE_WORD(CMAP_Table
->tables
[i
].encodingID
) == 10) )
319 CMAP_SegmentedCoverage
*format
= (CMAP_SegmentedCoverage
*)(((BYTE
*)CMAP_Table
) + GET_BE_DWORD(CMAP_Table
->tables
[i
].offset
));
320 if (GET_BE_WORD(format
->format
) == 12)
327 static int compare_group(const void *a
, const void* b
)
329 const DWORD
*chr
= a
;
330 const CMAP_SegmentedCoverage_group
*group
= b
;
332 if (*chr
< GET_BE_DWORD(group
->startCharCode
))
334 if (*chr
> GET_BE_DWORD(group
->endCharCode
))
339 DWORD
OpenType_CMAP_GetGlyphIndex(HDC hdc
, ScriptCache
*psc
, DWORD utf32c
, LPWORD pgi
, DWORD flags
)
341 /* BMP: use gdi32 for ease */
342 if (utf32c
< 0x10000)
345 return GetGlyphIndicesW(hdc
,&ch
, 1, pgi
, flags
);
348 if (!psc
->CMAP_format12_Table
)
349 psc
->CMAP_format12_Table
= load_CMAP_format12_table(hdc
, psc
);
351 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
356 if (psc
->CMAP_format12_Table
)
358 CMAP_SegmentedCoverage
*format
= NULL
;
359 CMAP_SegmentedCoverage_group
*group
= NULL
;
361 format
= (CMAP_SegmentedCoverage
*)psc
->CMAP_format12_Table
;
363 group
= bsearch(&utf32c
, format
->groups
, GET_BE_DWORD(format
->nGroups
),
364 sizeof(CMAP_SegmentedCoverage_group
), compare_group
);
368 DWORD offset
= utf32c
- GET_BE_DWORD(group
->startCharCode
);
369 *pgi
= GET_BE_DWORD(group
->startGlyphID
) + offset
;
380 static WORD
GDEF_get_glyph_class(const GDEF_Header
*header
, WORD glyph
)
384 const GDEF_ClassDefFormat1
*cf1
;
389 offset
= GET_BE_WORD(header
->GlyphClassDef
);
393 cf1
= (GDEF_ClassDefFormat1
*)(((BYTE
*)header
)+offset
);
394 if (GET_BE_WORD(cf1
->ClassFormat
) == 1)
396 if (glyph
>= GET_BE_WORD(cf1
->StartGlyph
))
398 int index
= glyph
- GET_BE_WORD(cf1
->StartGlyph
);
399 if (index
< GET_BE_WORD(cf1
->GlyphCount
))
400 class = GET_BE_WORD(cf1
->ClassValueArray
[index
]);
403 else if (GET_BE_WORD(cf1
->ClassFormat
) == 2)
405 const GDEF_ClassDefFormat2
*cf2
= (GDEF_ClassDefFormat2
*)cf1
;
407 top
= GET_BE_WORD(cf2
->ClassRangeCount
);
408 for (i
= 0; i
< top
; i
++)
410 if (glyph
>= GET_BE_WORD(cf2
->ClassRangeRecord
[i
].Start
) &&
411 glyph
<= GET_BE_WORD(cf2
->ClassRangeRecord
[i
].End
))
413 class = GET_BE_WORD(cf2
->ClassRangeRecord
[i
].Class
);
419 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1
->ClassFormat
));
424 static VOID
*load_gdef_table(HDC hdc
)
426 VOID
* GDEF_Table
= NULL
;
427 int length
= GetFontData(hdc
, GDEF_TAG
, 0, NULL
, 0);
428 if (length
!= GDI_ERROR
)
430 GDEF_Table
= HeapAlloc(GetProcessHeap(),0,length
);
431 GetFontData(hdc
, GDEF_TAG
, 0, GDEF_Table
, length
);
432 TRACE("Loaded GDEF table of %i bytes\n",length
);
437 void OpenType_GDEF_UpdateGlyphProps(HDC hdc
, ScriptCache
*psc
, const WORD
*pwGlyphs
, const WORD cGlyphs
, WORD
* pwLogClust
, const WORD cChars
, SCRIPT_GLYPHPROP
*pGlyphProp
)
441 if (!psc
->GDEF_Table
)
442 psc
->GDEF_Table
= load_gdef_table(hdc
);
444 for (i
= 0; i
< cGlyphs
; i
++)
450 k
= USP10_FindGlyphInLogClust(pwLogClust
, cChars
, i
);
453 for (; k
< cChars
&& pwLogClust
[k
] == i
; k
++)
457 class = GDEF_get_glyph_class(psc
->GDEF_Table
, pwGlyphs
[i
]);
463 pGlyphProp
[i
].sva
.fClusterStart
= 1;
464 pGlyphProp
[i
].sva
.fDiacritic
= 0;
465 pGlyphProp
[i
].sva
.fZeroWidth
= 0;
468 pGlyphProp
[i
].sva
.fClusterStart
= 1;
469 pGlyphProp
[i
].sva
.fDiacritic
= 0;
470 pGlyphProp
[i
].sva
.fZeroWidth
= 0;
473 pGlyphProp
[i
].sva
.fClusterStart
= 0;
474 pGlyphProp
[i
].sva
.fDiacritic
= 1;
475 pGlyphProp
[i
].sva
.fZeroWidth
= 1;
478 pGlyphProp
[i
].sva
.fClusterStart
= 0;
479 pGlyphProp
[i
].sva
.fDiacritic
= 0;
480 pGlyphProp
[i
].sva
.fZeroWidth
= 0;
483 ERR("Unknown glyph class %i\n",class);
484 pGlyphProp
[i
].sva
.fClusterStart
= 1;
485 pGlyphProp
[i
].sva
.fDiacritic
= 0;
486 pGlyphProp
[i
].sva
.fZeroWidth
= 0;
490 pGlyphProp
[i
].sva
.fClusterStart
= 0;
497 static INT
GSUB_apply_lookup(const OT_LookupList
* lookup
, INT lookup_index
, WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT
*glyph_count
);
499 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
501 const OT_CoverageFormat1
* cf1
;
505 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
507 int count
= GET_BE_WORD(cf1
->GlyphCount
);
509 TRACE("Coverage Format 1, %i glyphs\n",count
);
510 for (i
= 0; i
< count
; i
++)
511 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
515 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
517 const OT_CoverageFormat2
* cf2
;
520 cf2
= (const OT_CoverageFormat2
*)cf1
;
522 count
= GET_BE_WORD(cf2
->RangeCount
);
523 TRACE("Coverage Format 2, %i ranges\n",count
);
524 for (i
= 0; i
< count
; i
++)
526 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
528 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
529 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
531 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
532 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
538 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
543 static INT
GSUB_apply_SingleSubst(const OT_LookupTable
*look
, WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT
*glyph_count
)
546 TRACE("Single Substitution Subtable\n");
548 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
551 const GSUB_SingleSubstFormat1
*ssf1
;
552 offset
= GET_BE_WORD(look
->SubTable
[j
]);
553 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
554 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
556 int offset
= GET_BE_WORD(ssf1
->Coverage
);
557 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
558 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyphs
[glyph_index
]) != -1)
560 TRACE(" Glyph 0x%x ->",glyphs
[glyph_index
]);
561 glyphs
[glyph_index
] = glyphs
[glyph_index
] + GET_BE_WORD(ssf1
->DeltaGlyphID
);
562 TRACE(" 0x%x\n",glyphs
[glyph_index
]);
563 return glyph_index
+ write_dir
;
568 const GSUB_SingleSubstFormat2
*ssf2
;
572 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
573 offset
= GET_BE_WORD(ssf1
->Coverage
);
574 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
575 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyphs
[glyph_index
]);
576 TRACE(" Coverage index %i\n",index
);
579 if (glyphs
[glyph_index
] == GET_BE_WORD(ssf2
->Substitute
[index
]))
580 return GSUB_E_NOGLYPH
;
582 TRACE(" Glyph is 0x%x ->",glyphs
[glyph_index
]);
583 glyphs
[glyph_index
] = GET_BE_WORD(ssf2
->Substitute
[index
]);
584 TRACE("0x%x\n",glyphs
[glyph_index
]);
585 return glyph_index
+ write_dir
;
589 return GSUB_E_NOGLYPH
;
592 static INT
GSUB_apply_MultipleSubst(const OT_LookupTable
*look
, WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT
*glyph_count
)
595 TRACE("Multiple Substitution Subtable\n");
597 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
600 const GSUB_MultipleSubstFormat1
*msf1
;
601 offset
= GET_BE_WORD(look
->SubTable
[j
]);
602 msf1
= (const GSUB_MultipleSubstFormat1
*)((const BYTE
*)look
+offset
);
604 offset
= GET_BE_WORD(msf1
->Coverage
);
605 index
= GSUB_is_glyph_covered((const BYTE
*)msf1
+offset
, glyphs
[glyph_index
]);
608 const GSUB_Sequence
*seq
;
611 offset
= GET_BE_WORD(msf1
->Sequence
[index
]);
612 seq
= (const GSUB_Sequence
*)((const BYTE
*)msf1
+offset
);
613 sub_count
= GET_BE_WORD(seq
->GlyphCount
);
614 TRACE(" Glyph 0x%x (+%i)->",glyphs
[glyph_index
],(sub_count
-1));
616 for (j
= (*glyph_count
)+(sub_count
-1); j
> glyph_index
; j
--)
617 glyphs
[j
] =glyphs
[j
-(sub_count
-1)];
619 for (j
= 0; j
< sub_count
; j
++)
621 glyphs
[glyph_index
+ (sub_count
-1) - j
] = GET_BE_WORD(seq
->Substitute
[j
]);
623 glyphs
[glyph_index
+ j
] = GET_BE_WORD(seq
->Substitute
[j
]);
625 *glyph_count
= *glyph_count
+ (sub_count
- 1);
627 if (TRACE_ON(uniscribe
))
629 for (j
= 0; j
< sub_count
; j
++)
630 TRACE(" 0x%x",glyphs
[glyph_index
+j
]);
634 return glyph_index
+ (sub_count
* write_dir
);
637 return GSUB_E_NOGLYPH
;
640 static INT
GSUB_apply_AlternateSubst(const OT_LookupTable
*look
, WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT
*glyph_count
)
643 TRACE("Alternate Substitution Subtable\n");
645 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
648 const GSUB_AlternateSubstFormat1
*asf1
;
651 offset
= GET_BE_WORD(look
->SubTable
[j
]);
652 asf1
= (const GSUB_AlternateSubstFormat1
*)((const BYTE
*)look
+offset
);
653 offset
= GET_BE_WORD(asf1
->Coverage
);
655 index
= GSUB_is_glyph_covered((const BYTE
*)asf1
+offset
, glyphs
[glyph_index
]);
658 const GSUB_AlternateSet
*as
;
659 offset
= GET_BE_WORD(asf1
->AlternateSet
[index
]);
660 as
= (const GSUB_AlternateSet
*)((const BYTE
*)asf1
+offset
);
661 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as
->GlyphCount
));
662 if (glyphs
[glyph_index
] == GET_BE_WORD(as
->Alternate
[0]))
663 return GSUB_E_NOGLYPH
;
665 TRACE(" Glyph 0x%x ->",glyphs
[glyph_index
]);
666 glyphs
[glyph_index
] = GET_BE_WORD(as
->Alternate
[0]);
667 TRACE(" 0x%x\n",glyphs
[glyph_index
]);
668 return glyph_index
+ write_dir
;
671 return GSUB_E_NOGLYPH
;
674 static INT
GSUB_apply_LigatureSubst(const OT_LookupTable
*look
, WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT
*glyph_count
)
678 TRACE("Ligature Substitution Subtable\n");
679 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
681 const GSUB_LigatureSubstFormat1
*lsf1
;
684 offset
= GET_BE_WORD(look
->SubTable
[j
]);
685 lsf1
= (const GSUB_LigatureSubstFormat1
*)((const BYTE
*)look
+offset
);
686 offset
= GET_BE_WORD(lsf1
->Coverage
);
687 index
= GSUB_is_glyph_covered((const BYTE
*)lsf1
+offset
, glyphs
[glyph_index
]);
688 TRACE(" Coverage index %i\n",index
);
691 const GSUB_LigatureSet
*ls
;
694 offset
= GET_BE_WORD(lsf1
->LigatureSet
[index
]);
695 ls
= (const GSUB_LigatureSet
*)((const BYTE
*)lsf1
+offset
);
696 count
= GET_BE_WORD(ls
->LigatureCount
);
697 TRACE(" LigatureSet has %i members\n",count
);
698 for (k
= 0; k
< count
; k
++)
700 const GSUB_Ligature
*lig
;
701 int CompCount
,l
,CompIndex
;
703 offset
= GET_BE_WORD(ls
->Ligature
[k
]);
704 lig
= (const GSUB_Ligature
*)((const BYTE
*)ls
+offset
);
705 CompCount
= GET_BE_WORD(lig
->CompCount
) - 1;
706 CompIndex
= glyph_index
+write_dir
;
707 for (l
= 0; l
< CompCount
&& CompIndex
>= 0 && CompIndex
< *glyph_count
; l
++)
710 CompGlyph
= GET_BE_WORD(lig
->Component
[l
]);
711 if (CompGlyph
!= glyphs
[CompIndex
])
713 CompIndex
+= write_dir
;
717 int replaceIdx
= glyph_index
;
719 replaceIdx
= glyph_index
- CompCount
;
721 TRACE(" Glyph is 0x%x (+%i) ->",glyphs
[glyph_index
],CompCount
);
722 glyphs
[replaceIdx
] = GET_BE_WORD(lig
->LigGlyph
);
723 TRACE("0x%x\n",glyphs
[replaceIdx
]);
727 for (j
= replaceIdx
+ 1; j
< *glyph_count
; j
++)
728 glyphs
[j
] =glyphs
[j
+CompCount
];
729 *glyph_count
= *glyph_count
- CompCount
;
731 return replaceIdx
+ write_dir
;
736 return GSUB_E_NOGLYPH
;
739 static INT
GSUB_apply_ChainContextSubst(const OT_LookupList
* lookup
, const OT_LookupTable
*look
, WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT
*glyph_count
)
744 TRACE("Chaining Contextual Substitution Subtable\n");
745 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
) && !done
; j
++)
747 const GSUB_ChainContextSubstFormat1
*ccsf1
;
749 int dirLookahead
= write_dir
;
750 int dirBacktrack
= -1 * write_dir
;
752 offset
= GET_BE_WORD(look
->SubTable
[j
]);
753 ccsf1
= (const GSUB_ChainContextSubstFormat1
*)((const BYTE
*)look
+offset
);
754 if (GET_BE_WORD(ccsf1
->SubstFormat
) == 1)
756 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
759 else if (GET_BE_WORD(ccsf1
->SubstFormat
) == 2)
761 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
764 else if (GET_BE_WORD(ccsf1
->SubstFormat
) == 3)
768 const GSUB_ChainContextSubstFormat3_1
*ccsf3_1
;
769 const GSUB_ChainContextSubstFormat3_2
*ccsf3_2
;
770 const GSUB_ChainContextSubstFormat3_3
*ccsf3_3
;
771 const GSUB_ChainContextSubstFormat3_4
*ccsf3_4
;
772 int newIndex
= glyph_index
;
774 ccsf3_1
= (const GSUB_ChainContextSubstFormat3_1
*)ccsf1
;
776 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
778 for (k
= 0; k
< GET_BE_WORD(ccsf3_1
->BacktrackGlyphCount
); k
++)
780 offset
= GET_BE_WORD(ccsf3_1
->Coverage
[k
]);
781 if (GSUB_is_glyph_covered((const BYTE
*)ccsf3_1
+offset
, glyphs
[glyph_index
+ (dirBacktrack
* (k
+1))]) == -1)
784 if (k
!= GET_BE_WORD(ccsf3_1
->BacktrackGlyphCount
))
786 TRACE("Matched Backtrack\n");
788 ccsf3_2
= (const GSUB_ChainContextSubstFormat3_2
*)(((LPBYTE
)ccsf1
)+sizeof(GSUB_ChainContextSubstFormat3_1
) + (sizeof(WORD
) * (GET_BE_WORD(ccsf3_1
->BacktrackGlyphCount
)-1)));
790 indexGlyphs
= GET_BE_WORD(ccsf3_2
->InputGlyphCount
);
791 for (k
= 0; k
< indexGlyphs
; k
++)
793 offset
= GET_BE_WORD(ccsf3_2
->Coverage
[k
]);
794 if (GSUB_is_glyph_covered((const BYTE
*)ccsf3_1
+offset
, glyphs
[glyph_index
+ (write_dir
* k
)]) == -1)
797 if (k
!= indexGlyphs
)
799 TRACE("Matched IndexGlyphs\n");
801 ccsf3_3
= (const GSUB_ChainContextSubstFormat3_3
*)(((LPBYTE
)ccsf3_2
)+sizeof(GSUB_ChainContextSubstFormat3_2
) + (sizeof(WORD
) * (GET_BE_WORD(ccsf3_2
->InputGlyphCount
)-1)));
803 for (k
= 0; k
< GET_BE_WORD(ccsf3_3
->LookaheadGlyphCount
); k
++)
805 offset
= GET_BE_WORD(ccsf3_3
->Coverage
[k
]);
806 if (GSUB_is_glyph_covered((const BYTE
*)ccsf3_1
+offset
, glyphs
[glyph_index
+ (dirLookahead
* (indexGlyphs
+ k
))]) == -1)
809 if (k
!= GET_BE_WORD(ccsf3_3
->LookaheadGlyphCount
))
811 TRACE("Matched LookAhead\n");
813 ccsf3_4
= (const GSUB_ChainContextSubstFormat3_4
*)(((LPBYTE
)ccsf3_3
)+sizeof(GSUB_ChainContextSubstFormat3_3
) + (sizeof(WORD
) * (GET_BE_WORD(ccsf3_3
->LookaheadGlyphCount
)-1)));
815 if (GET_BE_WORD(ccsf3_4
->SubstCount
))
817 for (k
= 0; k
< GET_BE_WORD(ccsf3_4
->SubstCount
); k
++)
819 int lookupIndex
= GET_BE_WORD(ccsf3_4
->SubstLookupRecord
[k
].LookupListIndex
);
820 int SequenceIndex
= GET_BE_WORD(ccsf3_4
->SubstLookupRecord
[k
].SequenceIndex
) * write_dir
;
822 TRACE("SUBST: %i -> %i %i\n",k
, SequenceIndex
, lookupIndex
);
823 newIndex
= GSUB_apply_lookup(lookup
, lookupIndex
, glyphs
, glyph_index
+ SequenceIndex
, write_dir
, glyph_count
);
826 ERR("Chain failed to generate a glyph\n");
832 else return GSUB_E_NOGLYPH
;
838 static INT
GSUB_apply_lookup(const OT_LookupList
* lookup
, INT lookup_index
, WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT
*glyph_count
)
841 const OT_LookupTable
*look
;
843 offset
= GET_BE_WORD(lookup
->Lookup
[lookup_index
]);
844 look
= (const OT_LookupTable
*)((const BYTE
*)lookup
+ offset
);
845 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
846 switch(GET_BE_WORD(look
->LookupType
))
849 return GSUB_apply_SingleSubst(look
, glyphs
, glyph_index
, write_dir
, glyph_count
);
851 return GSUB_apply_MultipleSubst(look
, glyphs
, glyph_index
, write_dir
, glyph_count
);
853 return GSUB_apply_AlternateSubst(look
, glyphs
, glyph_index
, write_dir
, glyph_count
);
855 return GSUB_apply_LigatureSubst(look
, glyphs
, glyph_index
, write_dir
, glyph_count
);
857 return GSUB_apply_ChainContextSubst(lookup
, look
, glyphs
, glyph_index
, write_dir
, glyph_count
);
859 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look
->LookupType
));
861 return GSUB_E_NOGLYPH
;
864 INT
OpenType_apply_GSUB_lookup(LPCVOID table
, INT lookup_index
, WORD
*glyphs
, INT glyph_index
, INT write_dir
, INT
*glyph_count
)
866 const GSUB_Header
*header
= (const GSUB_Header
*)table
;
867 const OT_LookupList
*lookup
= (const OT_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
869 return GSUB_apply_lookup(lookup
, lookup_index
, glyphs
, glyph_index
, write_dir
, glyph_count
);
872 static void GSUB_initialize_script_cache(ScriptCache
*psc
)
878 const OT_ScriptList
*script
;
879 const GSUB_Header
* header
= (const GSUB_Header
*)psc
->GSUB_Table
;
880 script
= (const OT_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
881 psc
->script_count
= GET_BE_WORD(script
->ScriptCount
);
882 TRACE("initializing %i scripts in this font\n",psc
->script_count
);
883 if (psc
->script_count
)
885 psc
->scripts
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(LoadedScript
) * psc
->script_count
);
886 for (i
= 0; i
< psc
->script_count
; i
++)
888 int offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
889 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]);
890 psc
->scripts
[i
].gsub_table
= ((const BYTE
*)script
+ offset
);
896 static void GPOS_expand_script_cache(ScriptCache
*psc
)
899 const OT_ScriptList
*script
;
900 const GPOS_Header
* header
= (const GPOS_Header
*)psc
->GPOS_Table
;
905 script
= (const OT_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
906 count
= GET_BE_WORD(script
->ScriptCount
);
908 if (!psc
->script_count
)
910 psc
->script_count
= count
;
911 TRACE("initializing %i scripts in this font\n",psc
->script_count
);
912 if (psc
->script_count
)
914 psc
->scripts
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(LoadedScript
) * psc
->script_count
);
915 for (i
= 0; i
< psc
->script_count
; i
++)
917 int offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
918 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]);
919 psc
->scripts
[i
].gpos_table
= ((const BYTE
*)script
+ offset
);
925 for (i
= 0; i
< count
; i
++)
928 int offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
929 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]);
930 for (j
= 0; j
< psc
->script_count
; j
++)
932 if (psc
->scripts
[j
].tag
== tag
)
934 psc
->scripts
[j
].gpos_table
= ((const BYTE
*)script
+ offset
);
938 if (j
== psc
->script_count
)
941 psc
->scripts
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,psc
->scripts
, sizeof(LoadedScript
) * psc
->script_count
);
942 psc
->scripts
[j
].tag
= tag
;
943 psc
->scripts
[j
].gpos_table
= ((const BYTE
*)script
+ offset
);
949 static void _initialize_script_cache(ScriptCache
*psc
)
951 if (!psc
->script_count
)
953 GSUB_initialize_script_cache(psc
);
954 GPOS_expand_script_cache(psc
);
958 HRESULT
OpenType_GetFontScriptTags(ScriptCache
*psc
, OPENTYPE_TAG searchingFor
, int cMaxTags
, OPENTYPE_TAG
*pScriptTags
, int *pcTags
)
963 _initialize_script_cache(psc
);
965 *pcTags
= psc
->script_count
;
967 if (!searchingFor
&& cMaxTags
< *pcTags
)
969 else if (searchingFor
)
970 rc
= USP_E_SCRIPT_NOT_IN_FONT
;
972 for (i
= 0; i
< psc
->script_count
; i
++)
975 pScriptTags
[i
] = psc
->scripts
[i
].tag
;
979 if (searchingFor
== psc
->scripts
[i
].tag
)
981 pScriptTags
[0] = psc
->scripts
[i
].tag
;
991 static void GSUB_initialize_language_cache(LoadedScript
*script
)
995 if (!script
->language_count
&& script
->gsub_table
)
998 const OT_Script
* table
= script
->gsub_table
;
999 script
->language_count
= GET_BE_WORD(table
->LangSysCount
);
1000 offset
= GET_BE_WORD(table
->DefaultLangSys
);
1003 script
->default_language
.tag
= MS_MAKE_TAG('d','f','l','t');
1004 script
->default_language
.table
= (const BYTE
*)table
+ offset
;
1007 if (script
->language_count
)
1009 TRACE("Deflang %p, LangCount %i\n",script
->default_language
.table
, script
->language_count
);
1011 script
->languages
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(LoadedLanguage
) * script
->language_count
);
1013 for (i
= 0; i
< script
->language_count
; i
++)
1015 int offset
= GET_BE_WORD(table
->LangSysRecord
[i
].LangSys
);
1016 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]);
1017 script
->languages
[i
].table
= ((const BYTE
*)table
+ offset
);
1023 HRESULT
OpenType_GSUB_GetFontLanguageTags(ScriptCache
*psc
, OPENTYPE_TAG script_tag
, OPENTYPE_TAG searchingFor
, int cMaxTags
, OPENTYPE_TAG
*pLanguageTags
, int *pcTags
, LPCVOID
* language_table
)
1027 LoadedScript
*script
= NULL
;
1029 _initialize_script_cache(psc
);
1031 for (i
= 0; i
< psc
->script_count
; i
++)
1033 if (psc
->scripts
[i
].tag
== script_tag
)
1035 script
= &psc
->scripts
[i
];
1041 return E_INVALIDARG
;
1043 GSUB_initialize_language_cache(script
);
1045 if (!searchingFor
&& cMaxTags
< script
->language_count
)
1047 else if (searchingFor
)
1050 *pcTags
= script
->language_count
;
1052 for (i
= 0; i
< script
->language_count
; i
++)
1055 pLanguageTags
[i
] = script
->languages
[i
].tag
;
1059 if (searchingFor
== script
->languages
[i
].tag
)
1061 pLanguageTags
[0] = script
->languages
[i
].tag
;
1064 *language_table
= script
->languages
[i
].table
;
1071 if (script
->default_language
.table
)
1074 pLanguageTags
[i
] = script
->default_language
.tag
;
1076 if (searchingFor
&& FAILED(rc
))
1078 pLanguageTags
[0] = script
->default_language
.tag
;
1080 *language_table
= script
->default_language
.table
;
1083 *pcTags
= (*pcTags
) + 1;
1090 static void GSUB_initialize_feature_cache(LPCVOID table
, LoadedLanguage
*language
)
1094 if (!language
->feature_count
)
1096 const OT_LangSys
*lang
= language
->table
;
1097 const GSUB_Header
*header
= (const GSUB_Header
*)table
;
1098 const OT_FeatureList
*feature_list
;
1100 language
->feature_count
= GET_BE_WORD(lang
->FeatureCount
);
1101 TRACE("%i features\n",language
->feature_count
);
1103 if (language
->feature_count
)
1105 language
->features
= HeapAlloc(GetProcessHeap(),0,sizeof(LoadedFeature
)*language
->feature_count
);
1107 feature_list
= (const OT_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
1109 for (i
= 0; i
< language
->feature_count
; i
++)
1111 const OT_Feature
*feature
;
1113 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
1115 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]);
1116 language
->features
[i
].feature
= ((const BYTE
*)feature_list
+ GET_BE_WORD(feature_list
->FeatureRecord
[index
].Feature
));
1117 feature
= (const OT_Feature
*)language
->features
[i
].feature
;
1118 language
->features
[i
].lookup_count
= GET_BE_WORD(feature
->LookupCount
);
1119 language
->features
[i
].lookups
= HeapAlloc(GetProcessHeap(),0,sizeof(WORD
) * language
->features
[i
].lookup_count
);
1120 for (j
= 0; j
< language
->features
[i
].lookup_count
; j
++)
1121 language
->features
[i
].lookups
[j
] = GET_BE_WORD(feature
->LookupListIndex
[j
]);
1127 HRESULT
OpenType_GSUB_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
)
1131 LoadedScript
*script
= NULL
;
1132 LoadedLanguage
*language
= NULL
;
1134 _initialize_script_cache(psc
);
1136 for (i
= 0; i
< psc
->script_count
; i
++)
1138 if (psc
->scripts
[i
].tag
== script_tag
)
1140 script
= &psc
->scripts
[i
];
1151 return E_INVALIDARG
;
1154 GSUB_initialize_language_cache(script
);
1156 if (script
->default_language
.table
&& script
->default_language
.tag
== language_tag
)
1157 language
= &script
->default_language
;
1160 for (i
= 0; i
< script
->language_count
; i
++)
1162 if (script
->languages
[i
].tag
== language_tag
)
1164 language
= &script
->languages
[i
];
1176 GSUB_initialize_feature_cache(psc
->GSUB_Table
, language
);
1178 *pcTags
= language
->feature_count
;
1180 if (!searchingFor
&& cMaxTags
< *pcTags
)
1182 else if (searchingFor
)
1185 for (i
= 0; i
< language
->feature_count
; i
++)
1188 pFeatureTags
[i
] = language
->features
[i
].tag
;
1192 if (searchingFor
== language
->features
[i
].tag
)
1194 pFeatureTags
[0] = language
->features
[i
].tag
;
1197 *feature
= &language
->features
[i
];