GlyphSubstitutionClass.cs 126 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Runtime.InteropServices;
  5. using FastReport.Fonts.LinqExts;
  6. #pragma warning disable CS3001, CS3002, CS3003, CS1591 // Missing XML comment for publicly visible type or member
  7. namespace FastReport.Fonts
  8. {
  9. /// <summary>
  10. /// GlyphSubstitution table
  11. /// </summary>
  12. public class GlyphSubstitutionClass : TrueTypeTable
  13. {
  14. #region "Structure definition"
  15. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  16. public struct GSUB_Header
  17. {
  18. [FieldOffset(0)]
  19. public uint Version; // Version of the GSUB table-initially set to 0x00010000
  20. [FieldOffset(4)]
  21. public ushort ScriptList; // Offset to ScriptList table-from beginning of GSUB table
  22. [FieldOffset(6)]
  23. public ushort FeatureList; // Offset to FeatureList table-from beginning of GSUB table
  24. [FieldOffset(8)]
  25. public ushort LookupList; // Offset to LookupList table-from beginning of GSUB table
  26. }
  27. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  28. public struct ScriptListTable
  29. {
  30. [FieldOffset(0)]
  31. public ushort CountScripts; // Count of ScriptListRecord
  32. }
  33. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  34. public struct ScriptListRecord
  35. {
  36. [FieldOffset(0)]
  37. public uint ScriptTag; // 4-byte ScriptTag identifier
  38. [FieldOffset(4)]
  39. public ushort ScriptOffset; // Offset to Script table-from beginning of ScriptList
  40. }
  41. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  42. public struct ScriptTable
  43. {
  44. [FieldOffset(0)]
  45. public ushort DefaultLangSysOffset; // Offset to DefaultLangSys table-from beginning of Script table-may be NULL
  46. [FieldOffset(2)]
  47. public ushort LangSysCount; // Number of LangSysRecords for this script-excluding the DefaultLangSys
  48. }
  49. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  50. public struct LangSysRecord
  51. {
  52. [FieldOffset(0)]
  53. public uint LangSysTag; // 4-byte LangSysTag identifier
  54. [FieldOffset(4)]
  55. public ushort LangSysOffset; // Offset to LangSys table-from beginning of Script table
  56. }
  57. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  58. public struct LangSysTable
  59. {
  60. [FieldOffset(0)]
  61. public ushort LookupOrder; // = NULL (reserved for an offset to a reordering table)
  62. [FieldOffset(2)]
  63. public ushort ReqFeatureIndex; // Index of a feature required for this language system- if no required features = 0xFFFF
  64. [FieldOffset(4)]
  65. public ushort FeatureCount; // Number of FeatureIndex values for this language system-excludes the required feature
  66. }
  67. // Related to feature table
  68. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  69. public struct FeaturesListTable
  70. {
  71. [FieldOffset(0)]
  72. public ushort CountFeatures; // Count of FeaturesListRecord
  73. }
  74. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  75. public struct FeatureRecord
  76. {
  77. [FieldOffset(0)]
  78. public uint FeatureTag; // 4-byte feature identification tag
  79. [FieldOffset(4)]
  80. public ushort Feature; // Offset to Feature table-from beginning of FeatureList
  81. }
  82. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  83. public struct FeatureTable
  84. {
  85. [FieldOffset(0)]
  86. public ushort FeatureParams;
  87. [FieldOffset(2)]
  88. public ushort LookupCount;
  89. }
  90. #endregion
  91. private GSUB_Header header;
  92. private uint featureVariationsOffset;
  93. private IntPtr gsub_ptr;
  94. private Hashtable script_list = new Hashtable();
  95. private LookupEntry[] lookup_list;
  96. public IEnumerable<string> Scripts
  97. {
  98. get
  99. {
  100. foreach (string script_str in script_list.Keys)
  101. yield return script_str;
  102. }
  103. }
  104. private ushort[] LoadFeature(FontStream stream, uint feature_idx, out string FeatureTag)
  105. {
  106. //IntPtr feature_list_table_ptr = Increment(gsub_ptr, (int)header.FeatureList);
  107. stream.Position = this.Offset + header.FeatureList;
  108. ushort feature_count = stream.ReadUInt16();// nSwapUInt16((ushort)Marshal.PtrToStructure(feature_list_table_ptr, typeof(ushort)));
  109. if (feature_idx >= feature_count)
  110. throw new Exception("Feature index out of bound");
  111. long feature_list_pos = stream.Position;
  112. // IntPtr feature_record_ptr = Increment(feature_list_table_ptr, (int)(sizeof(ushort) + feature_idx * 6));
  113. stream.Position = feature_list_pos + feature_idx * 6;
  114. FeatureRecord feature_record = new FeatureRecord(); // Marshal.PtrToStructure(feature_record_ptr, typeof(FeatureRecord));
  115. feature_record.FeatureTag = stream.ReadUInt32();
  116. feature_record.Feature = stream.ReadUInt16(); // SwapUInt16(feature_record.Feature);
  117. FeatureTag = "" +
  118. (char)(0xff & (feature_record.FeatureTag >> 24)) +
  119. (char)(0xff & (feature_record.FeatureTag >> 16)) +
  120. (char)(0xff & (feature_record.FeatureTag >> 8)) +
  121. (char)(0xff & feature_record.FeatureTag);
  122. // IntPtr feature_table_ptr = Increment(feature_list_table_ptr, feature_record.Feature);
  123. stream.Position = this.Offset + header.FeatureList + feature_record.Feature;
  124. FeatureTable feature_table = new FeatureTable(); // Marshal.PtrToStructure(feature_table_ptr, typeof(FeatureTable));
  125. feature_table.FeatureParams = stream.ReadUInt16();
  126. feature_table.LookupCount = stream.ReadUInt16(); // SwapUInt16(feature_table.LookupCount);
  127. // IntPtr lookup_list_ptr = Increment(feature_table_ptr, Marshal.SizeOf(feature_table));
  128. ushort[] OffsetLookupList = new ushort[feature_table.LookupCount];
  129. for (int i = 0; i < feature_table.LookupCount; i++)
  130. {
  131. ushort lookuip_index = stream.ReadUInt16(); // SwapUInt16((ushort)Marshal.PtrToStructure(lookup_list_ptr, typeof(ushort)));
  132. OffsetLookupList[i] = lookuip_index;
  133. if (lookuip_index == 30)
  134. {
  135. //to do remove
  136. }
  137. // lookup_list_ptr = Increment(lookup_list_ptr, sizeof(ushort));
  138. }
  139. return OffsetLookupList;
  140. }
  141. internal IEnumerable<string> GetFeatures(string script, string language)
  142. {
  143. if (script_list.ContainsKey(script))
  144. if ((script_list[script] as Hashtable).ContainsKey(language))
  145. {
  146. foreach (string feature_str in ((script_list[script] as Hashtable)[language] as Hashtable).Keys)
  147. yield return feature_str;
  148. }
  149. }
  150. internal IEnumerable<string> Languages(string script)
  151. {
  152. if (script_list.ContainsKey(script))
  153. {
  154. foreach (string lang_str in (script_list[script] as Hashtable).Keys)
  155. yield return lang_str;
  156. }
  157. }
  158. private Hashtable LoadLanguageSystemTable(FontStream stream /*IntPtr lang_sys_rec_ptr*/)
  159. {
  160. Hashtable Features = new Hashtable();
  161. LangSysTable lang_sys_table = new LangSysTable(); // Marshal.PtrToStructure(lang_sys_rec_ptr, typeof(LangSysTable));
  162. lang_sys_table.LookupOrder = stream.ReadUInt16(); // SwapUInt16(lang_sys_table.LookupOrder);
  163. lang_sys_table.ReqFeatureIndex = stream.ReadUInt16(); // SwapUInt16(lang_sys_table.ReqFeatureIndex);
  164. lang_sys_table.FeatureCount = stream.ReadUInt16();// SwapUInt16(lang_sys_table.FeatureCount);
  165. // IntPtr feature_index_ptr = Increment(lang_sys_rec_ptr, Marshal.SizeOf(lang_sys_table));
  166. ushort[] feature_indexes = new ushort[lang_sys_table.FeatureCount];
  167. for (int k = 0; k < lang_sys_table.FeatureCount; k++)
  168. feature_indexes[k] = stream.ReadUInt16(); // SwapUInt16((ushort)Marshal.PtrToStructure(feature_index_ptr, typeof(ushort)));
  169. for (int k = 0; k < lang_sys_table.FeatureCount; k++)
  170. {
  171. string FeatureTag;
  172. ushort[] LookupOffsets = LoadFeature(stream, feature_indexes[k], out FeatureTag);
  173. #if DEBUG_TTF
  174. Console.WriteLine("\t\t[" + k + "]: " + FeatureTag + " of " + LookupOffsets.Length);
  175. #endif
  176. if (!Features.ContainsKey(FeatureTag))
  177. Features.Add(FeatureTag, LookupOffsets);
  178. #if DEBUG_TTF
  179. else
  180. Console.WriteLine("Duplicated record " + FeatureTag);
  181. #endif
  182. // feature_index_ptr = Increment(feature_index_ptr, sizeof(ushort));
  183. }
  184. return Features;
  185. }
  186. private void LoadScriptList(FontStream stream)
  187. {
  188. //IntPtr script_list_table_ptr = Increment(gsub_ptr, (int)header.ScriptList);
  189. long ls_pos = stream.Position = this.Offset + header.ScriptList;
  190. ScriptListTable script_list_table = new ScriptListTable(); // Marshal.PtrToStructure(script_list_table_ptr, typeof(ScriptListTable));
  191. script_list_table.CountScripts = stream.ReadUInt16();
  192. ScriptListRecord[] script_record = new ScriptListRecord[script_list_table.CountScripts];
  193. for (int i = 0; i < script_list_table.CountScripts; i++)
  194. {
  195. script_record[i].ScriptTag = stream.ReadUInt32();
  196. script_record[i].ScriptOffset = stream.ReadUInt16(); // SwapUInt16(script_record.ScriptOffset);
  197. }
  198. for (int i = 0; i < script_list_table.CountScripts; i++)
  199. {
  200. string ScriptTag = "" +
  201. (char)(0xff & (script_record[i].ScriptTag >> 24)) +
  202. (char)(0xff & (script_record[i].ScriptTag >> 16)) +
  203. (char)(0xff & (script_record[i].ScriptTag >> 8)) +
  204. (char)(0xff & script_record[i].ScriptTag);
  205. #if DEBUG_TTF
  206. Console.WriteLine("[" + ScriptTag + "]");
  207. #endif
  208. Hashtable lang_sys_hash = new Hashtable();
  209. script_list.Add(ScriptTag, lang_sys_hash);
  210. stream.Position = ls_pos + script_record[i].ScriptOffset;
  211. ScriptTable script_table = new ScriptTable(); // Marshal.PtrToStructure(script_table_ptr, typeof(ScriptTable));
  212. script_table.DefaultLangSysOffset = stream.ReadUInt16(); // SwapUInt16(script_table.DefaultLangSys);
  213. script_table.LangSysCount = stream.ReadUInt16(); // SwapUInt16(script_table.LangSysCount);
  214. LangSysRecord[] lang_sys_rec = new LangSysRecord[script_table.LangSysCount];
  215. for (int j = 0; j < script_table.LangSysCount; j++)
  216. {
  217. lang_sys_rec[j].LangSysTag = stream.ReadUInt32();
  218. lang_sys_rec[j].LangSysOffset = stream.ReadUInt16(); // SwapUInt16(lang_sys_rec.LangSys);
  219. }
  220. for (int j = 0; j < script_table.LangSysCount; j++)
  221. {
  222. string LangSysTag = "" +
  223. (char)(0xff & (lang_sys_rec[j].LangSysTag >> 24)) +
  224. (char)(0xff & (lang_sys_rec[j].LangSysTag >> 16)) +
  225. (char)(0xff & (lang_sys_rec[j].LangSysTag >> 8)) +
  226. (char)(0xff & lang_sys_rec[j].LangSysTag);
  227. #if DEBUG_TTF
  228. Console.WriteLine("\t\"" + LangSysTag + "\"");
  229. #endif
  230. stream.Position = ls_pos + script_record[i].ScriptOffset + lang_sys_rec[j].LangSysOffset;
  231. lang_sys_hash.Add(LangSysTag, LoadLanguageSystemTable(stream));
  232. }
  233. if (script_table.DefaultLangSysOffset != 0)
  234. {
  235. // lang_sys_rec_ptr = Increment(script_table_ptr, script_table.DefaultLangSys);
  236. stream.Position = ls_pos + script_record[i].ScriptOffset + script_table.DefaultLangSysOffset;
  237. #if DEBUG_TTF
  238. Console.WriteLine("\t\"!DEF\"");
  239. #endif
  240. lang_sys_hash.Add("", LoadLanguageSystemTable(stream /*lang_sys_rec_ptr*/));
  241. }
  242. }
  243. }
  244. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  245. internal struct LookupTableRecordHeader
  246. {
  247. [FieldOffset(0)]
  248. public ushort LookupType; // Different enumerations for GSUB and GPOS
  249. [FieldOffset(2)]
  250. public ushort LookupFlag; // Lookup qualifiers
  251. [FieldOffset(4)]
  252. public ushort SubTableCount; // Number of SubTables for this lookup [FieldOffset(2)]
  253. }
  254. internal struct LookupEntry
  255. {
  256. public LookupTableRecordHeader record_header;
  257. public ushort[] subtable_offsets;
  258. public IntPtr[] subtable_ptrs;
  259. public Substitution[] subs;
  260. public override string ToString()
  261. {
  262. return "" + ((LookupTypes)record_header.LookupType).ToString() + " : " + record_header.LookupFlag + " [" + record_header.SubTableCount.ToString() + "]";
  263. }
  264. }
  265. public enum LookupTypes
  266. {
  267. Single = 1, // Replace one glyph with one glyph
  268. Multiple = 2, // Replace one glyph with more than one glyph
  269. Alternate = 3, // Replace one glyph with one of many glyphs
  270. Ligature = 4, // Replace multiple glyphs with one glyph
  271. Context = 5, // Replace one or more glyphs in context
  272. ChainingContext = 6, // Replace one or more glyphs in chained context
  273. ExtensionSubstitution = 7, // Extension mechanism for other substitutions (i.e. this excludes the Extension type substitution itself)
  274. ReverseChainingContextSingle = 8 // Applied in reverse order, replace single glyph in chaining context
  275. //9+ Reserved For future use (set to zero)
  276. }
  277. /// <summary>
  278. /// Stream position must point to lookup record
  279. /// </summary>
  280. /// <param name="stream"></param>
  281. /// <param name="lookup_table_header"></param>
  282. private LookupEntry LoadLookupRecord(FontStream stream, ref LookupTableRecordHeader lookup_table_header)
  283. {
  284. ushort markFilteringSet = 0;
  285. long record_pos = stream.Position;
  286. LookupEntry result = new LookupEntry();
  287. // --------------------------
  288. lookup_table_header.LookupType = stream.ReadUInt16();
  289. lookup_table_header.LookupFlag = stream.ReadUInt16();
  290. lookup_table_header.SubTableCount = stream.ReadUInt16();
  291. result.record_header = lookup_table_header;
  292. ushort[] subtableOffsets = new ushort[lookup_table_header.SubTableCount];
  293. for (int j = 0; j < subtableOffsets.Length; j++)
  294. subtableOffsets[j] = stream.ReadUInt16();
  295. if (0 != (lookup_table_header.LookupFlag & 0x0010))
  296. markFilteringSet = stream.ReadUInt16();
  297. result.subs = new Substitution[subtableOffsets.Length];
  298. ushort hold_lookup_type = lookup_table_header.LookupType;
  299. for (int j = 0; j < subtableOffsets.Length; j++)
  300. {
  301. bool infinity = false;
  302. lookup_table_header.LookupType = hold_lookup_type;
  303. stream.Position = record_pos + subtableOffsets[j];
  304. loop_extension:
  305. switch ((LookupTypes)lookup_table_header.LookupType)
  306. {
  307. case LookupTypes.Single: // Single Substitution Format
  308. result.subs[j] = LoadSingleSubstitution(stream);
  309. continue;
  310. case LookupTypes.Multiple: // Multiple Substitution Format
  311. result.subs[j] = LoadMultipleSubstitution(stream);
  312. continue;
  313. case LookupTypes.Alternate:
  314. Console.WriteLine("TTF: Alternate format not supported\n");
  315. continue;
  316. case LookupTypes.Ligature: // Ligature Substitution Format
  317. result.subs[j] = LoadLigaturesSubtable(stream);
  318. continue;
  319. case LookupTypes.Context: //
  320. result.subs[j] = LoadContextSubstitution(stream);
  321. continue;
  322. case LookupTypes.ChainingContext: // Chained Contexts Substitution
  323. result.subs[j] = LoadChainingContext(stream);
  324. continue;
  325. case LookupTypes.ExtensionSubstitution: // Extension Substitution
  326. ushort substFormat = stream.ReadUInt16();
  327. ushort extensionLookupType = stream.ReadUInt16();
  328. uint extensionOffset = stream.ReadUInt32();
  329. if (substFormat != 1)
  330. Console.WriteLine("Detected extension of Extension Substitution in Lookup record\n");
  331. if (infinity)
  332. {
  333. Console.WriteLine("Infinity loop detected");
  334. continue;
  335. }
  336. stream.Position = record_pos + subtableOffsets[j] + extensionOffset;
  337. lookup_table_header.LookupType = extensionLookupType;
  338. infinity = true;
  339. goto loop_extension;
  340. default:
  341. Console.WriteLine("Lookup type is " + lookup_table_header.LookupType);
  342. break;
  343. }
  344. }
  345. return result;
  346. }
  347. private void LoadLookupList(FontStream stream)
  348. {
  349. stream.Position = this.Offset + header.LookupList;
  350. ushort LookupListCount = stream.ReadUInt16(); // SwapUInt16((ushort)Marshal.PtrToStructure(lookup_list_table_ptr, typeof(ushort)));
  351. ushort[] lookupOffsets = new ushort[LookupListCount];
  352. for (int i = 0; i < LookupListCount; i++)
  353. lookupOffsets[i] = stream.ReadUInt16();
  354. lookup_list = new LookupEntry[LookupListCount];
  355. LookupTableRecordHeader[] lookup_table_header = new LookupTableRecordHeader[LookupListCount];
  356. for (int i = 0; i < LookupListCount; i++)
  357. {
  358. stream.Position = this.Offset + header.LookupList + lookupOffsets[i];
  359. #if DEBUG_TTF
  360. //Console.WriteLine("index is {0}", i);
  361. if (i == 21)
  362. Console.WriteLine("Debug!");
  363. #endif
  364. lookup_list[i] = LoadLookupRecord(stream, ref lookup_table_header[i]);
  365. }
  366. }
  367. private Substitution LoadContextSubstitution(FontStream stream)
  368. {
  369. long lookup_entry = stream.Position;
  370. ushort format = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(lookup_entry, typeof(ushort));
  371. switch (format)
  372. {
  373. case 1:
  374. ContextSubstFormat1 type1 = new ContextSubstFormat1(); // Marshal.PtrToStructure(lookup_entry, typeof(ContextSubstFormat1));
  375. type1.SubstFormat = 1;
  376. type1.CoverageOffset = stream.ReadUInt16();
  377. type1.SubRuleSetCount = stream.ReadUInt16();
  378. ushort[] seqRuleSetOffsets = new ushort[type1.SubRuleSetCount];
  379. for (int k = 0; k < type1.SubRuleSetCount; k++)
  380. seqRuleSetOffsets[k] = stream.ReadUInt16();
  381. Contextual1.SubRule[][] subRuleSets = new Contextual1.SubRule[type1.SubRuleSetCount][];
  382. for (int i = 0; i < type1.SubRuleSetCount; i++)
  383. {
  384. if (seqRuleSetOffsets[i] == 0)
  385. {
  386. // offsets may be NULL
  387. continue;
  388. }
  389. stream.Position = lookup_entry + seqRuleSetOffsets[i];
  390. ushort subRuleCount = stream.ReadUInt16();
  391. ushort[] subrule_offsets = new ushort[subRuleCount];
  392. for (int j = 0; j < subRuleCount; j++)
  393. subrule_offsets[j] = stream.ReadUInt16();
  394. Contextual1.SubRule[] subRuleSet = new Contextual1.SubRule[subRuleCount];
  395. for (int j = 0; j < subRuleCount; j++)
  396. {
  397. // ushort subRuleOffset = (ushort)Marshal.PtrToStructure(subrule_offsets, typeof(ushort));
  398. // IntPtr subrule_table = Increment(subruleset_offset_table, subRuleOffset);
  399. SubRuleTable subRule = new SubRuleTable(); // Marshal.PtrToStructure(subrule_table, typeof(SubRuleTable));
  400. stream.Position = lookup_entry + subrule_offsets[j];
  401. subRule.GlyphCount = stream.ReadUInt16(); // SwapUInt16(subRule.GlyphCount);
  402. subRule.SubstitutionCount = stream.ReadUInt16(); // SwapUInt16(subRule.SubstitutionCount);
  403. ushort[] glyphs = new ushort[subRule.GlyphCount - 1];
  404. // IntPtr subrule_table_arrays = Increment(subrule_table, Marshal.SizeOf(subRule));
  405. for (int k = 0; k < subRule.GlyphCount - 1; k++)
  406. glyphs[k] = stream.ReadUInt16();
  407. SubstLookupRecord[] records = new SubstLookupRecord[subRule.SubstitutionCount];
  408. for (int k = 0; k < subRule.SubstitutionCount; k++)
  409. {
  410. SubstLookupRecord record = new SubstLookupRecord(); // Marshal.PtrToStructure(subrule_table_arrays, typeof(SubstLookupRecord));
  411. record.GlyphSequenceIndex = stream.ReadUInt16(); // SwapUInt16(record.GlyphSequenceIndex);
  412. record.LookupListIndex = stream.ReadUInt16(); // SwapUInt16(record.LookupListIndex);
  413. records[k] = record;
  414. }
  415. subRuleSet[j] = new Contextual1.SubRule(glyphs, records);
  416. // subrule_offsets = Increment(subrule_offsets, Marshal.SizeOf(subRuleOffset));
  417. }
  418. subRuleSets[i] = subRuleSet;
  419. }
  420. stream.Position = lookup_entry + type1.CoverageOffset; ;
  421. return new Contextual1(this, subRuleSets, LoadCoverage(stream));
  422. case 2:
  423. ContextSubstFormat2 type2 = new ContextSubstFormat2(); // Marshal.PtrToStructure(lookup_entry, typeof(ContextSubstFormat2));
  424. type2.SubstFormat = 2; // SwapUInt16(type2.SubstFormat);
  425. type2.Coverage = stream.ReadUInt16(); // SwapUInt16(type2.Coverage);
  426. type2.ClassDefOffset = stream.ReadUInt16(); // SwapUInt16(type2.ClassDefOffset);
  427. type2.SubClassSetCount = stream.ReadUInt16(); // SwapUInt16(type2.SubClassSetCount);
  428. Contextual2.SubClassRule[][] subClassRuleSets = new Contextual2.SubClassRule[type2.SubClassSetCount][];
  429. long sub_class_set_offset = stream.Position;
  430. for (int i = 0; i < type2.SubClassSetCount; i++)
  431. {
  432. ushort offset = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(sub_class_set_offset, typeof(ushort));
  433. if (offset == 0)
  434. subClassRuleSets[i] = null;
  435. else
  436. {
  437. // offset = SwapUInt16(offset);
  438. // IntPtr sub_class_set_table = Increment(lookup_entry, offset);
  439. long sub_class_set_table = stream.Position;
  440. ushort count = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(sub_class_set_table, typeof(ushort));
  441. // IntPtr sub_class_rule_offset = Increment(sub_class_set_table, Marshal.SizeOf(count));
  442. long sub_class_rule_offset = stream.Position;
  443. Contextual2.SubClassRule[] subClassSet = new Contextual2.SubClassRule[count];
  444. for (int j = 0; j < count; j++)
  445. {
  446. ushort offset2 = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(sub_class_rule_offset, typeof(ushort));
  447. // IntPtr sub_class_rule_table = Increment(sub_class_set_table, offset2);
  448. long sub_class_rule_table = sub_class_set_table + offset2;
  449. SubClassRule subClassRule = new SubClassRule(); // Marshal.PtrToStructure(sub_class_rule_table, typeof(SubClassRule));
  450. //IntPtr subclassrule_table_arrays = Increment(sub_class_rule_table, Marshal.SizeOf(subClassRule));
  451. long subclassrule_table_arrays = sub_class_rule_table + 4;
  452. subClassRule.ClassCount = stream.ReadUInt16(); // SwapUInt16(subClassRule.ClassCount);
  453. subClassRule.SubstitutionCount = stream.ReadUInt16(); // SwapUInt16(subClassRule.SubstitutionCount);
  454. ushort[] glyphClassess = new ushort[subClassRule.ClassCount - 1];
  455. for (int k = 0; k < subClassRule.ClassCount - 1; k++)
  456. glyphClassess[k] = stream.ReadUInt16();
  457. SubstLookupRecord[] records = new SubstLookupRecord[subClassRule.SubstitutionCount];
  458. for (int k = 0; k < subClassRule.SubstitutionCount; k++)
  459. {
  460. SubstLookupRecord record = new SubstLookupRecord(); // Marshal.PtrToStructure(subclassrule_table_arrays, typeof(SubstLookupRecord));
  461. record.GlyphSequenceIndex = stream.ReadUInt16(); // SwapUInt16(record.GlyphSequenceIndex);
  462. record.LookupListIndex = stream.ReadUInt16(); // SwapUInt16(record.LookupListIndex);
  463. records[k] = record;
  464. }
  465. subClassSet[j] = new Contextual2.SubClassRule(glyphClassess, records);
  466. // sub_class_rule_offset = Increment(sub_class_rule_offset, Marshal.SizeOf(offset2));
  467. sub_class_rule_offset += 2;
  468. }
  469. subClassRuleSets[i] = subClassSet;
  470. }
  471. // sub_class_set_offset = Increment(sub_class_set_offset, Marshal.SizeOf(offset));
  472. sub_class_set_offset += 2;
  473. }
  474. stream.Position = lookup_entry + type2.Coverage;
  475. Coverage coverage = LoadCoverage(stream);
  476. stream.Position = lookup_entry + type2.ClassDefOffset;
  477. ClassDefinition class_definition = LoadClassDefinition(stream);
  478. return new Contextual2(this, subClassRuleSets, coverage, class_definition);
  479. case 3:
  480. ContextSubstFormat3 type3 = new ContextSubstFormat3(); // Marshal.PtrToStructure(lookup_entry, typeof(ContextSubstFormat3));
  481. type3.SubstFormat = 3; // SwapUInt16(type3.SubstFormat);
  482. type3.GlyphCount = stream.ReadUInt16(); // SwapUInt16(type3.GlyphCount);
  483. type3.SubstitutionCount = stream.ReadUInt16(); // SwapUInt16(type3.SubstitutionCount);
  484. Coverage[] coverages = new Coverage[type3.GlyphCount];
  485. SubstLookupRecord[] subRecords = new SubstLookupRecord[type3.SubstitutionCount];
  486. ushort[] offsets3 = new ushort[type3.GlyphCount];
  487. for (int i = 0; i < type3.GlyphCount; i++)
  488. offsets3[i] = stream.ReadUInt16();
  489. long type3_arrays = stream.Position;
  490. for (int i = 0; i < type3.GlyphCount; i++)
  491. {
  492. stream.Position = lookup_entry + offsets3[i];
  493. coverages[i] = LoadCoverage(stream);
  494. }
  495. stream.Position = type3_arrays;
  496. for (int i = 0; i < type3.SubstitutionCount; i++)
  497. {
  498. SubstLookupRecord record = new SubstLookupRecord(); // Marshal.PtrToStructure(type3_arrays, typeof(SubstLookupRecord));
  499. record.GlyphSequenceIndex = stream.ReadUInt16(); // SwapUInt16(record.GlyphSequenceIndex);
  500. record.LookupListIndex = stream.ReadUInt16(); // SwapUInt16(record.LookupListIndex);
  501. subRecords[i] = record;
  502. // type3_arrays = Increment(type3_arrays, Marshal.SizeOf(record));
  503. }
  504. return new Contextual3(this, subRecords, coverages);
  505. }
  506. return new VoidSubstitution();
  507. }
  508. private Substitution LoadMultipleSubstitution(FontStream stream)
  509. {
  510. long lookup_entry = stream.Position;
  511. MultipleSubstFormat1 type1 = new MultipleSubstFormat1(); // Marshal.PtrToStructure(lookup_entry, typeof(MultipleSubstFormat1));
  512. type1.SubstFormat = stream.ReadUInt16(); // SwapUInt16(type1.SubstFormat);
  513. type1.Coverage = stream.ReadUInt16(); // SwapUInt16(type1.Coverage);
  514. type1.SequenceCount = stream.ReadUInt16(); // SwapUInt16(type1.SequenceCount);
  515. //type1.SequenceOffset = SwapUInt16(type1.SequenceOffset);
  516. ushort[][] sequences = new ushort[type1.SequenceCount][];
  517. for (int i = 0; i < type1.SequenceCount; i++)
  518. {
  519. ushort offset = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(sequence_offset, typeof(ushort));
  520. // offset = SwapUInt16(offset);
  521. // IntPtr sequence_offset_table = Increment(lookup_entry, offset);
  522. stream.Position = lookup_entry + offset;
  523. ushort glyph_count = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(sequence_offset_table, typeof(ushort));
  524. // glyph_count = SwapUInt16(glyph_count);
  525. ushort[] glyphs = new ushort[glyph_count];
  526. for (int j = 0; j < glyph_count; j++)
  527. {
  528. glyphs[j] = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(sequence_offset_table, typeof(ushort));
  529. glyphs[j] = stream.ReadUInt16(); // SwapUInt16(glyphs[j]);
  530. // sequence_offset_table = Increment(lookup_entry, Marshal.SizeOf(glyphs[j]));
  531. }
  532. sequences[i] = glyphs;
  533. //sequence_offset = Increment(lookup_entry, Marshal.SizeOf(offset));
  534. stream.Position = lookup_entry + 2;
  535. }
  536. stream.Position = lookup_entry + type1.Coverage;
  537. return new Multiple(sequences, LoadCoverage(stream));
  538. }
  539. private Substitution LoadSingleSubstitution(FontStream stream)
  540. {
  541. long lookup_entry = stream.Position;
  542. SignleSubstitutionFormat1 type1 = new SignleSubstitutionFormat1(); // Marshal.PtrToStructure(lookup_entry, typeof(SignleSubstitutionFormat1));
  543. type1.SubstFormat = stream.ReadUInt16(); // SwapUInt16(type1.SubstFormat);
  544. type1.Coverage = stream.ReadUInt16(); // SwapUInt16(type1.Coverage);
  545. type1.DeltaGlyphID = stream.ReadInt16(); // SwapInt16(type1.DeltaGlyphID);
  546. switch (type1.SubstFormat)
  547. {
  548. case 1:
  549. stream.Position = lookup_entry + type1.Coverage;
  550. return new Single1(type1.DeltaGlyphID, LoadCoverage(stream));
  551. case 2:
  552. ushort[] substitute = new ushort[type1.DeltaGlyphID];
  553. // IntPtr lookup_entry_substitute = Increment(lookup_entry, Marshal.SizeOf(typeof(SignleSubstitutionFormat1)));
  554. for (int i = 0; i < type1.DeltaGlyphID; i++)
  555. substitute[i] = stream.ReadUInt16();
  556. stream.Position = lookup_entry + type1.Coverage;
  557. return new Single2(substitute, LoadCoverage(stream));
  558. }
  559. return new VoidSubstitution();
  560. }
  561. private ClassDefinition LoadClassDefinition(FontStream stream)
  562. {
  563. long class_definition_ptr = stream.Position;
  564. ushort class_format = stream.ReadUInt16();
  565. class_format = SwapUInt16(class_format);
  566. switch (class_format)
  567. {
  568. case 1:
  569. ClassDefFormat1 type1 = new ClassDefFormat1(); // Marshal.PtrToStructure(class_definition_ptr, typeof(ClassDefFormat1));
  570. type1.ClassFormat = stream.ReadUInt16(); // SwapUInt16(type1.ClassFormat);
  571. type1.StartGlyphID = stream.ReadUInt16(); // SwapUInt16(type1.StartGlyphID);
  572. type1.GlyphCount = stream.ReadUInt16(); // SwapUInt16(type1.GlyphCount);
  573. ushort[] classValues = new ushort[type1.GlyphCount];
  574. for (int i = 0; i < type1.GlyphCount; i++)
  575. classValues[i] = stream.ReadUInt16(); ;
  576. return new ClassDefinition1(type1.StartGlyphID, classValues);
  577. case 2:
  578. ClassDefFormat2 type2 = new ClassDefFormat2(); // Marshal.PtrToStructure(class_definition_ptr, typeof(ClassDefFormat2));
  579. type2.ClassFormat = stream.ReadUInt16();
  580. type2.ClassRangeCount = stream.ReadUInt16();
  581. ClassRangeRecord[] records = new ClassRangeRecord[type2.ClassRangeCount];
  582. for (int i = 0; i < type2.ClassRangeCount; i++)
  583. {
  584. ClassRangeRecord record = new ClassRangeRecord(); // Marshal.PtrToStructure(class_records_array, typeof(ClassRangeRecord));
  585. record.StartGlyphID = stream.ReadUInt16();
  586. record.EndGlyphID = stream.ReadUInt16();
  587. record.ClassValue = stream.ReadUInt16();
  588. records[i] = record;
  589. }
  590. return new ClassDefinition2(records);
  591. }
  592. return new VoidClassDefinition();
  593. }
  594. private Coverage LoadCoverage(FontStream stream)
  595. {
  596. CoverageHeader ch = new CoverageHeader(); // Marshal.PtrToStructure(coverage_table_ptr, typeof(CoverageHeader));
  597. ch.CoverageFormat = stream.ReadUInt16(); // SwapUInt16(ch.CoverageFormat);
  598. ch.GlyphCount = stream.ReadUInt16(); // SwapUInt16(ch.GlyphCount);
  599. switch (ch.CoverageFormat)
  600. {
  601. case 1:
  602. {
  603. ushort[] glyphs = new ushort[ch.GlyphCount];
  604. //coverage_table_ptr = Increment(coverage_table_ptr, Marshal.SizeOf(ch));
  605. for (int i = 0; i < ch.GlyphCount; i++)
  606. {
  607. glyphs[i] = stream.ReadUInt16();
  608. }
  609. /*if((new Coverage1(ch.GlyphCount, glyphs)).IsSubstituteGetIndex(296) >=0)
  610. {
  611. //to do remove
  612. }*/
  613. return new Coverage1(ch.GlyphCount, glyphs);
  614. }
  615. //break;
  616. case 2:
  617. {
  618. RangeRecord[] rrs = new RangeRecord[ch.GlyphCount];
  619. // coverage_table_ptr = Increment(coverage_table_ptr, Marshal.SizeOf(ch));
  620. for (int i = 0; i < ch.GlyphCount; i++)
  621. {
  622. rrs[i] = new RangeRecord(); // Marshal.PtrToStructure(coverage_table_ptr, typeof(RangeRecord));
  623. rrs[i].Start = stream.ReadUInt16(); // SwapUInt16(rrs[i].Start);
  624. rrs[i].End = stream.ReadUInt16(); // SwapUInt16(rrs[i].End);
  625. rrs[i].StartCoverageIndex = stream.ReadUInt16(); // SwapUInt16(rrs[i].StartCoverageIndex);
  626. // coverage_table_ptr = Increment(coverage_table_ptr, Marshal.SizeOf(rrs[i]));
  627. }
  628. /*if ((new Coverage2(ch.GlyphCount, rrs)).IsSubstituteGetIndex(296) >= 0)
  629. {
  630. //to do remove
  631. }*/
  632. return new Coverage2(ch.GlyphCount, rrs);
  633. }
  634. //break;
  635. }
  636. return new VoidCoverage();
  637. }
  638. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  639. internal struct ExtensionSubstFormat
  640. {
  641. [FieldOffset(0)]
  642. public ushort SubstFormat;
  643. [FieldOffset(2)]
  644. public ushort ExtensionLookupType;
  645. [FieldOffset(4)]
  646. public uint ExtensionOffset;
  647. public override string ToString()
  648. {
  649. return ((LookupTypes)ExtensionLookupType).ToString();
  650. }
  651. }
  652. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  653. internal struct LigatureSubst
  654. {
  655. [FieldOffset(0)]
  656. public ushort SubstFormat; // Format identifier-format = 1
  657. [FieldOffset(2)]
  658. public ushort Coverage; // Offset to Coverage table-from beginning of Substitution table
  659. [FieldOffset(4)]
  660. public ushort LigSetCount; // Number of LigatureSet tables
  661. // public ushort [LigSetCount] Array of offsets to LigatureSet tables-from beginning of Substitution table-ordered by Coverage Index
  662. }
  663. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  664. internal struct LigatureHeader
  665. {
  666. [FieldOffset(0)]
  667. public ushort LigGlyph; // GlyphID of ligature to substitute
  668. [FieldOffset(2)]
  669. public ushort CompCount; // Number of components in the ligature
  670. }
  671. internal Substitution LoadLigaturesSubtable(FontStream stream)
  672. {
  673. long lookup_entry = stream.Position;
  674. LigatureSubst type4 = new LigatureSubst(); // Marshal.PtrToStructure(lookup_entry, typeof(LigatureSubst));
  675. type4.SubstFormat = stream.ReadUInt16(); // SwapUInt16(type4.SubstFormat);
  676. type4.Coverage = stream.ReadUInt16(); // SwapUInt16(type4.Coverage);
  677. type4.LigSetCount = stream.ReadUInt16(); // SwapUInt16(type4.LigSetCount);
  678. //To do not null
  679. //LoadCoverageTable(null, Increment(lookup_entry, type4.Coverage));
  680. stream.Position = lookup_entry + type4.Coverage;
  681. Coverage coverage = LoadCoverage(stream);
  682. // Ligature Set
  683. // IntPtr ligature_set_ptr = Increment(lookup_entry, Marshal.SizeOf(type4));
  684. stream.Position = lookup_entry + 6;
  685. //IntPtr current_ptr = ligature_set_ptr;
  686. //long current_ptr = lookup_entry + 6;
  687. // IntPtr[] LigatureSet = new IntPtr[type4.LigSetCount];
  688. ushort[] LigatureSet = new ushort[type4.LigSetCount];
  689. for (int i = 0; i < type4.LigSetCount; i++)
  690. LigatureSet[i] = stream.ReadUInt16();
  691. LigatureSet[][] ligatureSets = new LigatureSet[type4.LigSetCount][];
  692. for (int i = 0; i < type4.LigSetCount; i++)
  693. {
  694. //ushort offset = stream.ReadUInt16(); // SwapUInt16((ushort)Marshal.PtrToStructure(current_ptr, typeof(ushort)));
  695. // Console.WriteLine("LigatresSet[" + i + "] at" + offset);
  696. // LigatureSet[i] = stream.ReadUInt16(); // Increment(lookup_entry, offset);
  697. // Ligature Table
  698. stream.Position = lookup_entry + LigatureSet[i];
  699. long current_ptr = stream.Position;
  700. ushort LigatureCount = stream.ReadUInt16(); // SwapUInt16((ushort)Marshal.PtrToStructure(LigatureSet[i], typeof(ushort)));
  701. // IntPtr ligature_ptr = Increment(LigatureSet[i], sizeof(ushort));
  702. IntPtr[] LigaturePtrs = new IntPtr[LigatureCount];
  703. LigatureHeader[] lh = new LigatureHeader[LigatureCount];
  704. ligatureSets[i] = new LigatureSet[LigatureCount];
  705. ushort[] lig_offsets = new ushort[LigatureCount];
  706. for (int j = 0; j < LigatureCount; j++)
  707. lig_offsets[j] = stream.ReadUInt16();
  708. for (int j = 0; j < LigatureCount; j++)
  709. {
  710. // ushort lig_offset = stream.ReadUInt16(); // SwapUInt16((ushort)Marshal.PtrToStructure(ligature_ptr, typeof(ushort)));
  711. //LigaturePtrs[j] = Increment(LigatureSet[i], lig_offset);
  712. // Console.WriteLine("\tLigature[" + j + "] at " + lig_offset);
  713. // stream.Position = current_ptr + LigatureSet[j] + lig_offsets[j];
  714. // stream.Position = lookup_entry + LigatureSet[i] + lig_offsets[j];
  715. stream.Position = current_ptr + lig_offsets[j];
  716. //// Ligature
  717. lh[j] = new LigatureHeader(); // Marshal.PtrToStructure(LigaturePtrs[j], typeof(LigatureHeader));
  718. lh[j].LigGlyph = stream.ReadUInt16(); // SwapUInt16(lh[j].LigGlyph);
  719. lh[j].CompCount = stream.ReadUInt16(); // SwapUInt16(lh[j].CompCount);
  720. ushort[] glyphs = new ushort[lh[j].CompCount - 1];
  721. for (int k = 0; k < lh[j].CompCount - 1; k++)
  722. glyphs[k] = stream.ReadUInt16(); // SwapUInt16((ushort)Marshal.PtrToStructure(ligature_array, typeof(ushort)));
  723. //// ---------
  724. ligatureSets[i][j] = new LigatureSet(lh[j].LigGlyph, glyphs);
  725. }
  726. // -----------------
  727. }
  728. return new Ligature(coverage, ligatureSets);
  729. }
  730. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  731. internal struct CoverageHeader
  732. {
  733. [FieldOffset(0)]
  734. public ushort CoverageFormat; // Format identifier-format = 1
  735. [FieldOffset(2)]
  736. public ushort GlyphCount; // Number of glyphs in the GlyphArray
  737. }
  738. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  739. public struct RangeRecord
  740. {
  741. [FieldOffset(0)]
  742. public ushort Start; // First GlyphID in the range
  743. [FieldOffset(2)]
  744. public ushort End; // Last GlyphID in the range
  745. [FieldOffset(4)]
  746. public ushort StartCoverageIndex; // Coverage Index of first GlyphID in range
  747. }
  748. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  749. internal struct SignleSubstitutionFormat1
  750. {
  751. [FieldOffset(0)]
  752. public ushort SubstFormat; // Format identifier-format = 1
  753. [FieldOffset(2)]
  754. public ushort Coverage; // Offset to Coverage table-from beginning of Substitution table
  755. [FieldOffset(4)]
  756. public short DeltaGlyphID; // Add to original GlyphID to get substitute GlyphID
  757. }
  758. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  759. internal struct MultipleSubstFormat1
  760. {
  761. [FieldOffset(0)]
  762. public ushort SubstFormat; // Format identifier-format = 1
  763. [FieldOffset(2)]
  764. public ushort Coverage; // Offset to Coverage table-from beginning of Substitution table
  765. [FieldOffset(4)]
  766. public ushort SequenceCount; // Number of Sequence table offsets in the Sequence array
  767. //[FieldOffset(6)]
  768. //public ushort SequenceOffset; // Array of offsets to Sequence tables-from beginning of Substitution table-ordered by Coverage Index
  769. }
  770. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  771. internal struct ContextSubstFormat1
  772. {
  773. [FieldOffset(0)]
  774. public ushort SubstFormat; // Format identifier-format = 1
  775. [FieldOffset(2)]
  776. public ushort CoverageOffset; // Offset to Coverage table-from beginning of Substitution table
  777. [FieldOffset(4)]
  778. public ushort SubRuleSetCount; // Number of SubRuleSet tables — must equal glyphCount in Coverage table
  779. //[FieldOffset(6)]
  780. //public ushort[] subRuleSetOffsets; // Array of offsets to SubRuleSet tables. Offsets are from beginning of substitution subtable, ordered by Coverage index
  781. }
  782. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  783. internal struct ContextSubstFormat2
  784. {
  785. [FieldOffset(0)]
  786. public ushort SubstFormat; // Format identifier-format = 1
  787. [FieldOffset(2)]
  788. public ushort Coverage; // Offset to Coverage table-from beginning of Substitution table
  789. [FieldOffset(4)]
  790. public ushort ClassDefOffset; // Offset to glyph ClassDef table, from beginning of substitution subtable
  791. [FieldOffset(6)]
  792. public ushort SubClassSetCount; // Number of SubClassSet tables
  793. //[FieldOffset(8)]
  794. //public ushort[] subClassSetOffsets; // Array of offsets to SubClassSet tables. Offsets are from beginning of substitution subtable, ordered by class (may be NULL).
  795. }
  796. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  797. internal struct ContextSubstFormat3
  798. {
  799. [FieldOffset(0)]
  800. public ushort SubstFormat; // Format identifier-format = 1
  801. [FieldOffset(2)]
  802. public ushort GlyphCount; // Number of glyphs in the input glyph sequence
  803. [FieldOffset(4)]
  804. public ushort SubstitutionCount; // Number of SubstLookupRecords
  805. /*
  806. Offset16 coverageOffsets[glyphCount] Array of offsets to Coverage tables. Offsets are from beginning of substitution subtable, in glyph sequence order.
  807. SubstLookupRecord substLookupRecords[substitutionCount] Array of SubstLookupRecords, in design order.
  808. */
  809. }
  810. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  811. internal struct SubClassRule
  812. {
  813. [FieldOffset(0)]
  814. public ushort ClassCount;//GlyphCount; // Total number of classes specified for the context in the rule — includes the first class
  815. [FieldOffset(2)]
  816. public ushort SubstitutionCount; // Number of SubstLookupRecords
  817. /*
  818. uint16 inputSequence[glyphCount - 1] Array of classes to be matched to the input glyph sequence, beginning with the second glyph position.
  819. SubstLookupRecord substLookupRecords[substitutionCount] Array of Substitution lookups, in design order.
  820. */
  821. }
  822. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  823. public struct SubstLookupRecord
  824. {
  825. [FieldOffset(0)]
  826. public ushort GlyphSequenceIndex; // Index into current glyph sequence — first glyph = 0.
  827. [FieldOffset(2)]
  828. public ushort LookupListIndex; // Lookup to apply to that position — zero-based index.
  829. }
  830. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  831. internal struct SubRuleTable
  832. {
  833. [FieldOffset(0)]
  834. public ushort GlyphCount; // Total number of glyphs in input glyph sequence — includes the first glyph.
  835. [FieldOffset(2)]
  836. public ushort SubstitutionCount; // Number of SubstLookupRecords
  837. //[FieldOffset(4)]
  838. //public ushort inputSequence; // [glyphCount - 1] Array of input glyph IDs — start with second glyph
  839. //[FieldOffset(6)]
  840. //public SubstLookupRecord[] substLookupRecords; // [substitutionCount] Array of SubstLookupRecords, in design order
  841. }
  842. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  843. internal struct SequenceFormat
  844. {
  845. [FieldOffset(0)]
  846. public ushort GlyphCount; // Number of glyph IDs in the Substitute array. This should always be greater than 0.
  847. // Substitute [GlyphCount] String of glyph IDs to substitute
  848. }
  849. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  850. internal struct ClassDefFormat1
  851. {
  852. [FieldOffset(0)]
  853. public ushort ClassFormat; // Format identifier — format = 1
  854. [FieldOffset(2)]
  855. public ushort StartGlyphID; // First glyph ID of the classValueArray
  856. [FieldOffset(4)]
  857. public ushort GlyphCount; // Size of the classValueArray
  858. //[FieldOffset(6)]
  859. //public ushort[] classValueArray; // [glyphCount] Array of Class Values — one per glyph ID
  860. }
  861. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  862. internal struct ClassDefFormat2
  863. {
  864. [FieldOffset(0)]
  865. public ushort ClassFormat; // Format identifier — format = 1
  866. [FieldOffset(2)]
  867. public ushort ClassRangeCount; // First glyph ID of the classValueArray
  868. //[FieldOffset(4)]
  869. //public ClassRangeRecord[] classRangeRecords; // Array of ClassRangeRecords — ordered by startGlyphID
  870. }
  871. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  872. public struct ClassRangeRecord
  873. {
  874. [FieldOffset(0)]
  875. public ushort StartGlyphID; // Format identifier — format = 1
  876. [FieldOffset(2)]
  877. public ushort EndGlyphID; // First glyph ID of the classValueArray
  878. [FieldOffset(4)]
  879. public ushort ClassValue; // Array of ClassRangeRecords — ordered by startGlyphID
  880. }
  881. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  882. internal struct ChainContextSubstFormat1
  883. {
  884. [FieldOffset(0)]
  885. public ushort SubstFormat; // Format identifier: format = 1
  886. [FieldOffset(2)]
  887. public ushort Coverage; // Offset to Coverage table, from beginning of substitution subtable.
  888. [FieldOffset(4)]
  889. public ushort ChainSubRuleSetCount; // Number of ChainSubRuleSet tables — must equal GlyphCount in Coverage table.
  890. /*
  891. Offset16 chainSubRuleSetOffsets[chainSubRuleSetCount] Array of offsets to ChainSubRuleSet tables. Offsets are from beginning of substitution subtable, ordered by Coverage index.
  892. */
  893. }
  894. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  895. internal struct ChainContextSubstFormat2
  896. {
  897. [FieldOffset(0)]
  898. public ushort SubstFormat; // Format identifier: format = 2
  899. [FieldOffset(2)]
  900. public ushort CoverageOffset; // Offset to Coverage table, from beginning of substitution subtable.
  901. [FieldOffset(4)]
  902. public ushort BacktrackClassDefOffset; // Offset to glyph ClassDef table containing backtrack sequence data, from beginning of substitution subtable.
  903. [FieldOffset(6)]
  904. public ushort InputClassDefOffset; // Offset to glyph ClassDef table containing input sequence data, from beginning of substitution subtable.
  905. [FieldOffset(8)]
  906. public ushort LookaheadClassDefOffset; // Offset to glyph ClassDef table containing lookahead sequence data, from beginning of substitution subtable.
  907. [FieldOffset(10)]
  908. public ushort ChainSubClassSetCount; // Number of ChainSubClassSet tables
  909. /*
  910. Offset16 chainSubClassSetOffsets[chainSubClassSetCount] Array of offsets to ChainSubClassSet tables. Offsets are from beginning of substitution subtable, ordered by input class (may be NULL)
  911. */
  912. }
  913. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  914. internal struct ChainContextSubstFormat3
  915. {
  916. [FieldOffset(0)]
  917. public ushort SubstFormat; // Format identifier: format = 3
  918. /*
  919. uint16 backtrackGlyphCount Number of glyphs in the backtracking sequence.
  920. Offset16 backtrackCoverageOffsets[backtrackGlyphCount] Array of offsets to coverage tables in backtracking sequence. Offsets are from beginning of substition subtable, in glyph sequence order.
  921. uint16 inputGlyphCount Number of glyphs in input sequence
  922. Offset16 inputCoverageOffsets[inputGlyphCount] Array of offsets to coverage tables in input sequence. Offsets are from beginning of substition subtable, in glyph sequence order.
  923. uint16 lookaheadGlyphCount Number of glyphs in lookahead sequence
  924. Offset16 lookaheadCoverageOffsets[lookaheadGlyphCount] Array of offsets to coverage tables in lookahead sequence. Offsets are from beginning of substitution subtable, in glyph sequence order.
  925. uint16 substitutionCount Number of SubstLookupRecords
  926. SubstLookupRecord substLookupRecords[substitutionCount] Array of SubstLookupRecords, in design order
  927. */
  928. }
  929. private Substitution LoadChainingContextSubstFormat1(FontStream stream)
  930. {
  931. long lookup_entry = stream.Position - 2;
  932. ChainContextSubstFormat1 type1 = new ChainContextSubstFormat1(); // Marshal.PtrToStructure(lookup_entry, typeof(ChainContextSubstFormat1));
  933. // type1.SubstFormat = stream.ReadUInt16(); // SwapUInt16(type1.SubstFormat);
  934. type1.Coverage = stream.ReadUInt16(); // SwapUInt16(type1.Coverage);
  935. type1.ChainSubRuleSetCount = stream.ReadUInt16(); // SwapUInt16(type1.ChainSubRuleSetCount);
  936. ChainingContextual1.ChainSubRule[][] chainSubRuleSets
  937. = new ChainingContextual1.ChainSubRule[type1.ChainSubRuleSetCount][];
  938. //IntPtr chain_sub_rule_set_offsets = Increment(lookup_entry, Marshal.SizeOf(type1));
  939. long chain_sub_rule_set_offsets = stream.Position;
  940. ushort[] offsets = new ushort[type1.ChainSubRuleSetCount];
  941. for (int i = 0; i < type1.ChainSubRuleSetCount; i++)
  942. offsets[i] = stream.ReadUInt16();
  943. for (int i = 0; i < type1.ChainSubRuleSetCount; i++)
  944. {
  945. long stream_position = stream.Position;
  946. stream.Position = lookup_entry + offsets[i];
  947. ushort count = stream.ReadUInt16();
  948. long chain_sub_rule_offset = stream.Position;
  949. ushort[] offset2 = new ushort[count]; // (ushort)Marshal.PtrToStructure(chain_sub_rule_offset, typeof(ushort));
  950. for (int j = 0; j < count; j++)
  951. offset2[j] = stream.ReadUInt16();
  952. //IntPtr chain_sub_rule_offset = Increment(chain_sub_rule_set_table, Marshal.SizeOf(count));
  953. ChainingContextual1.ChainSubRule[] chainSubRuleSet = new ChainingContextual1.ChainSubRule[count];
  954. for (int j = 0; j < count; j++)
  955. {
  956. stream.Position = lookup_entry + offsets[i] + offset2[j];
  957. ushort backtrackGlyphCount = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(chain_sub_rule_arrays, typeof(ushort));
  958. ushort[] backtrackSequence = new ushort[backtrackGlyphCount];
  959. for (int k = 0; k < backtrackGlyphCount; k++)
  960. backtrackSequence[k] = stream.ReadUInt16();
  961. //end array
  962. //start array
  963. ushort inputGlyphCount = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(chain_sub_rule_arrays, typeof(ushort));
  964. ushort[] inputSequence = new ushort[inputGlyphCount - 1];
  965. // chain_sub_rule_arrays = Increment(chain_sub_rule_arrays, Marshal.SizeOf(inputGlyphCount));
  966. for (int k = 0; k < inputGlyphCount - 1; k++)
  967. inputSequence[k] = stream.ReadUInt16(); ;
  968. //end array
  969. //start array
  970. ushort lookaheadGlyphCount = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(chain_sub_rule_arrays, typeof(ushort));
  971. ushort[] lookAheadSequence = new ushort[lookaheadGlyphCount];
  972. for (int k = 0; k < lookaheadGlyphCount; k++)
  973. lookAheadSequence[k] = stream.ReadUInt16();
  974. //end array
  975. //start array
  976. ushort substitutionCount = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(chain_sub_rule_arrays, typeof(ushort));
  977. SubstLookupRecord[] records = new SubstLookupRecord[substitutionCount];
  978. for (int k = 0; k < substitutionCount; k++)
  979. {
  980. SubstLookupRecord record = new SubstLookupRecord(); // Marshal.PtrToStructure(chain_sub_rule_arrays, typeof(SubstLookupRecord));
  981. record.GlyphSequenceIndex = stream.ReadUInt16(); // SwapUInt16(record.GlyphSequenceIndex);
  982. record.LookupListIndex = stream.ReadUInt16(); // SwapUInt16(record.LookupListIndex);
  983. records[k] = record;
  984. }
  985. //end array
  986. chainSubRuleSet[j] = new ChainingContextual1.ChainSubRule(backtrackSequence, inputSequence, lookAheadSequence, records);
  987. //chain_sub_rule_offset = Increment(chain_sub_rule_offset, Marshal.SizeOf(offset2));
  988. chain_sub_rule_offset += 2;
  989. }
  990. chainSubRuleSets[i] = chainSubRuleSet;
  991. // chain_sub_rule_set_offsets = Increment(chain_sub_rule_set_offsets, Marshal.SizeOf(offset));
  992. chain_sub_rule_set_offsets += 2;
  993. }
  994. stream.Position = lookup_entry + type1.Coverage;
  995. return new ChainingContextual1(this, LoadCoverage(stream), chainSubRuleSets);
  996. }
  997. private Substitution LoadChainingContextSubstFormat2(FontStream stream)
  998. {
  999. ChainContextSubstFormat2 type2 = new ChainContextSubstFormat2(); // Marshal.PtrToStructure(lookup_entry, typeof(ChainContextSubstFormat2));
  1000. long lookup_entry = stream.Position - 2;
  1001. //type2.SubstFormat = stream.ReadUInt16(); // SwapUInt16(type2.SubstFormat);
  1002. type2.CoverageOffset = stream.ReadUInt16(); // SwapUInt16(type2.Coverage);
  1003. type2.BacktrackClassDefOffset = stream.ReadUInt16(); // SwapUInt16(type2.BacktrackClassDefOffset);
  1004. type2.InputClassDefOffset = stream.ReadUInt16(); // SwapUInt16(type2.InputClassDefOffset);
  1005. type2.LookaheadClassDefOffset = stream.ReadUInt16(); // SwapUInt16(type2.LookaheadClassDefOffset);
  1006. type2.ChainSubClassSetCount = stream.ReadUInt16(); // SwapUInt16(type2.ChainSubClassSetCount);
  1007. ChainingContextual2.ChainSubClassRule[][] chainSubClassRuleSets
  1008. = new ChainingContextual2.ChainSubClassRule[type2.ChainSubClassSetCount][];
  1009. ushort[] offsets = new ushort[type2.ChainSubClassSetCount];
  1010. for (int i = 0; i < type2.ChainSubClassSetCount; i++)
  1011. offsets[i] = stream.ReadUInt16();
  1012. for (int i = 0; i < type2.ChainSubClassSetCount; i++)
  1013. {
  1014. if (offsets[i] == 0)
  1015. {
  1016. // If no patterns are defined with an input sequence beginning with a particular class,
  1017. // then the offset for that class value can be set to NULL.
  1018. continue;
  1019. }
  1020. long chain_sub_class_ruleset_table = lookup_entry + offsets[i];
  1021. stream.Position = chain_sub_class_ruleset_table;
  1022. ushort count = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(chain_sub_class_set_table, typeof(ushort));
  1023. // 20231110: Read chainedClassSeqRuleOffsets
  1024. ushort[] chainedClassSeqRuleOffsets = new ushort[count];
  1025. for (int k = 0; k < count; k++)
  1026. chainedClassSeqRuleOffsets[k] = stream.ReadUInt16();
  1027. ChainingContextual2.ChainSubClassRule[] chainSubClassSet = new ChainingContextual2.ChainSubClassRule[count];
  1028. for (int j = 0; j < count; j++)
  1029. {
  1030. stream.Position = chain_sub_class_ruleset_table + chainedClassSeqRuleOffsets[j];
  1031. //start array
  1032. ushort backtrackGlyphCount = stream.ReadUInt16();
  1033. ushort[] backtrackSequence = new ushort[backtrackGlyphCount];
  1034. for (int k = 0; k < backtrackGlyphCount; k++)
  1035. backtrackSequence[k] = stream.ReadUInt16();
  1036. //end array
  1037. //start array
  1038. ushort inputGlyphCount = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(chain_sub_rule_arrays, typeof(ushort));
  1039. ushort[] inputSequence = new ushort[inputGlyphCount - 1];
  1040. for (int k = 0; k < inputGlyphCount - 1; k++)
  1041. inputSequence[k] = stream.ReadUInt16();
  1042. //end array
  1043. //start array
  1044. ushort lookaheadGlyphCount = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(chain_sub_rule_arrays, typeof(ushort));
  1045. ushort[] lookAheadSequence = new ushort[lookaheadGlyphCount];
  1046. for (int k = 0; k < lookaheadGlyphCount; k++)
  1047. lookAheadSequence[k] = stream.ReadUInt16();
  1048. //end array
  1049. //start array
  1050. ushort substitutionCount = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(chain_sub_rule_arrays, typeof(ushort));
  1051. SubstLookupRecord[] records = new SubstLookupRecord[substitutionCount];
  1052. for (int k = 0; k < substitutionCount; k++)
  1053. {
  1054. SubstLookupRecord record = new SubstLookupRecord(); // Marshal.PtrToStructure(chain_sub_rule_arrays, typeof(SubstLookupRecord));
  1055. record.GlyphSequenceIndex = stream.ReadUInt16(); // SwapUInt16(record.GlyphSequenceIndex);
  1056. record.LookupListIndex = stream.ReadUInt16(); // SwapUInt16(record.LookupListIndex);
  1057. records[k] = record;
  1058. }
  1059. //end array
  1060. chainSubClassSet[j] = new ChainingContextual2.ChainSubClassRule(backtrackSequence, inputSequence, lookAheadSequence, records);
  1061. }
  1062. chainSubClassRuleSets[i] = chainSubClassSet;
  1063. }
  1064. stream.Position = lookup_entry + type2.CoverageOffset;
  1065. Coverage coverage = LoadCoverage(stream);
  1066. stream.Position = lookup_entry + type2.BacktrackClassDefOffset;
  1067. ClassDefinition backtrackClassDefinition = LoadClassDefinition(stream);
  1068. stream.Position = lookup_entry + type2.InputClassDefOffset;
  1069. ClassDefinition inputClassDefinition = LoadClassDefinition(stream);
  1070. stream.Position = lookup_entry + type2.LookaheadClassDefOffset;
  1071. ClassDefinition lookaheadClassDefinition = LoadClassDefinition(stream);
  1072. return new ChainingContextual2(this, chainSubClassRuleSets,
  1073. coverage,
  1074. backtrackClassDefinition,
  1075. inputClassDefinition,
  1076. lookaheadClassDefinition);
  1077. }
  1078. private Substitution LoadChainingContextSubstFormat3(FontStream stream)
  1079. {
  1080. long lookup_entry = stream.Position - 2;
  1081. //IntPtr chain_format_3_array = Increment(lookup_entry, Marshal.SizeOf(typeof(ushort)));
  1082. long chain_format_3_array = lookup_entry + 2;
  1083. //start array
  1084. ushort backtrackGlyphCount = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(chain_format_3_array, typeof(ushort));
  1085. ushort[] offsets = new ushort[backtrackGlyphCount];
  1086. for (int k = 0; k < backtrackGlyphCount; k++)
  1087. offsets[k] = stream.ReadUInt16();
  1088. ushort inputGlyphCount = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(chain_format_3_array, typeof(ushort));
  1089. ushort[] offsets_gc = new ushort[inputGlyphCount];
  1090. for (int k = 0; k < inputGlyphCount; k++)
  1091. offsets_gc[k] = stream.ReadUInt16();
  1092. ushort lookaheadGlyphCount = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(chain_format_3_array, typeof(ushort));
  1093. ushort[] offsets_as = new ushort[lookaheadGlyphCount];
  1094. for (int k = 0; k < lookaheadGlyphCount; k++)
  1095. offsets_as[k] = stream.ReadUInt16();
  1096. ushort lookuoCount = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(chain_format_3_array, typeof(ushort));
  1097. long lookupPosition = stream.Position;
  1098. //start array
  1099. Coverage[] backtrackSequence = new Coverage[backtrackGlyphCount];
  1100. for (int k = 0; k < backtrackGlyphCount; k++)
  1101. {
  1102. stream.Position = lookup_entry + offsets[k];
  1103. backtrackSequence[k] = LoadCoverage(stream);
  1104. }
  1105. //end array
  1106. //start array
  1107. Coverage[] inputSequence = new Coverage[inputGlyphCount];
  1108. for (int k = 0; k < inputGlyphCount; k++)
  1109. {
  1110. stream.Position = lookup_entry + offsets_gc[k];
  1111. inputSequence[k] = LoadCoverage(stream);
  1112. }
  1113. //end array
  1114. //start array
  1115. Coverage[] lookAheadSequence = new Coverage[lookaheadGlyphCount];
  1116. for (int k = 0; k < lookaheadGlyphCount; k++)
  1117. {
  1118. stream.Position = lookup_entry + offsets_as[k];
  1119. lookAheadSequence[k] = LoadCoverage(stream);
  1120. }
  1121. //end array
  1122. //start array
  1123. stream.Position = lookupPosition;
  1124. SubstLookupRecord[] records = new SubstLookupRecord[lookuoCount];
  1125. for (int k = 0; k < lookuoCount; k++)
  1126. {
  1127. SubstLookupRecord record = new SubstLookupRecord(); // Marshal.PtrToStructure(chain_format_3_array, typeof(SubstLookupRecord));
  1128. record.GlyphSequenceIndex = stream.ReadUInt16(); // SwapUInt16(record.GlyphSequenceIndex);
  1129. record.LookupListIndex = stream.ReadUInt16(); // SwapUInt16(record.LookupListIndex);
  1130. records[k] = record;
  1131. }
  1132. //end array
  1133. return new ChainingContextual3(this, records, backtrackSequence, inputSequence, lookAheadSequence);
  1134. }
  1135. #if DEBUG_TTF
  1136. static int debug = 0;
  1137. #endif
  1138. private Substitution LoadChainingContext(FontStream stream)
  1139. {
  1140. // long lookup_entry = stream.Position;
  1141. ushort format = stream.ReadUInt16();
  1142. #if DEBUG_TTF
  1143. debug++;
  1144. Console.WriteLine("LoadChainingContext format" + format.ToString() + " Iteration " + debug.ToString());
  1145. if (debug == 123)
  1146. ;
  1147. #endif
  1148. switch (format)
  1149. {
  1150. case 1:
  1151. return LoadChainingContextSubstFormat1(stream);
  1152. case 2:
  1153. return LoadChainingContextSubstFormat2(stream);
  1154. case 3:
  1155. return LoadChainingContextSubstFormat3(stream);
  1156. default:
  1157. throw new NotSupportedException("Format of GSUB ChaingContext");
  1158. }
  1159. return new VoidSubstitution();
  1160. }
  1161. internal override void Load(FontStream stream)
  1162. {
  1163. stream.Seek(this.Offset, System.IO.SeekOrigin.Begin);
  1164. try
  1165. {
  1166. header.Version = stream.ReadUInt32(); // Version of the GSUB table-initially set to 0x00010000
  1167. header.ScriptList = stream.ReadUInt16(); // Offset to ScriptList table-from beginning of GSUB table
  1168. header.FeatureList = stream.ReadUInt16(); // Offset to FeatureList table-from beginning of GSUB table
  1169. header.LookupList = stream.ReadUInt16(); // Offset to LookupList table-from beginning of GSUB table
  1170. if (header.Version == 0x00010001)
  1171. featureVariationsOffset = stream.ReadUInt32();
  1172. LoadLookupList(stream);
  1173. LoadScriptList(stream);
  1174. //if(do_features) LoadFeatureList();
  1175. }
  1176. catch (System.IO.EndOfStreamException ex)
  1177. {
  1178. Console.WriteLine("End of stream exception");
  1179. }
  1180. }
  1181. //internal override uint Save(FontStream font, uint offset)
  1182. //{
  1183. // this.Offset = offset;
  1184. // return base.Save(font, offset);
  1185. //}
  1186. private void ChangeEndian()
  1187. {
  1188. header.Version = SwapUInt32(header.Version);
  1189. header.ScriptList = SwapUInt16(header.ScriptList);
  1190. header.LookupList = SwapUInt16(header.LookupList);
  1191. header.FeatureList = SwapUInt16(header.FeatureList);
  1192. }
  1193. public GlyphSubstitutionClass(TrueTypeTable src) : base(src) { }
  1194. internal List<ushort> ApplyGlyph(string script, string lang, ushort[] chars)
  1195. {
  1196. if (script == null)
  1197. {
  1198. script = "latn";
  1199. foreach (string name in script_list.Keys)
  1200. {
  1201. script = name;
  1202. break;
  1203. }
  1204. }
  1205. if (script_list.ContainsKey(script))
  1206. {
  1207. Hashtable lang_sys_hash = script_list[script] as Hashtable;
  1208. Hashtable lang_sys = null;
  1209. if (lang_sys_hash.ContainsKey(lang))
  1210. {
  1211. lang_sys = lang_sys_hash[lang] as Hashtable;
  1212. }
  1213. else if (lang_sys_hash.ContainsKey(string.Empty))
  1214. {
  1215. lang_sys = lang_sys_hash[string.Empty] as Hashtable;
  1216. }
  1217. if (lang_sys != null)
  1218. {
  1219. switch (script)
  1220. {
  1221. case "arab":
  1222. return ApplyGlyphArabic(lang_sys, chars);
  1223. }
  1224. }
  1225. }
  1226. return new List<ushort>(chars);
  1227. }
  1228. private void ApplyGlyphFeature(List<ushort> result, ushort[] offsets, ushort[] chars, ref int i)
  1229. {
  1230. foreach (ushort offset in offsets)
  1231. {
  1232. LookupEntry le = lookup_list[offset];
  1233. for (int j = 0; j < le.subs.Length; j++)
  1234. if (le.subs[j].Apply(result, chars, ref i))
  1235. return;
  1236. }
  1237. result.Add(chars[i]);
  1238. }
  1239. private bool IsApplyGlyphFeature(int index, ushort[] offsets, ushort[] chars)
  1240. {
  1241. if (index < 0) return false;
  1242. if (index >= chars.Length) return false;
  1243. foreach (ushort offset in offsets)
  1244. {
  1245. LookupEntry le = lookup_list[offset];
  1246. for (int j = 0; j < le.subs.Length; j++)
  1247. if (le.subs[j].IsApply(chars, index) >= 0)
  1248. return true;
  1249. }
  1250. return false;
  1251. }
  1252. private List<ushort> ApplyGlyphArabic(Hashtable lang_sys, ushort[] chars)
  1253. {
  1254. List<ushort> result = new List<ushort>();
  1255. if (lang_sys.Contains("ccmp"))
  1256. {
  1257. ushort[] ccmp = lang_sys["ccmp"] as ushort[];
  1258. for (int i = 0; i < chars.Length; i++)
  1259. {
  1260. ApplyGlyphFeature(result, ccmp, chars, ref i);
  1261. }
  1262. chars = result.ToArray();
  1263. result.Clear();
  1264. }
  1265. ushort[] isol;
  1266. if (lang_sys.Contains("isol")) isol = lang_sys["isol"] as ushort[];
  1267. else isol = new ushort[0];
  1268. ushort[] init;
  1269. if (lang_sys.Contains("init")) init = lang_sys["init"] as ushort[];
  1270. else init = new ushort[0];
  1271. ushort[] medi;
  1272. if (lang_sys.Contains("medi")) medi = lang_sys["medi"] as ushort[];
  1273. else medi = new ushort[0];
  1274. ushort[] fina;
  1275. if (lang_sys.Contains("fina")) fina = lang_sys["fina"] as ushort[];
  1276. else fina = new ushort[0];
  1277. ArabicCharType[] types = new ArabicCharType[chars.Length];
  1278. //Ýòî êîñòûëü, òàê êàê ÿ íå çíàþ êàêèì îáðàçîì âûòàùèòü íóæíûå èíäåêñû, ñäåëàþ òàêîé âàðèàíò áóäó ãóãëèòü
  1279. for (int i = 0; i < chars.Length; i++)
  1280. {
  1281. bool nextMedi = IsApplyGlyphFeature(i + 1, medi, chars);
  1282. bool nextFina = IsApplyGlyphFeature(i + 1, fina, chars);
  1283. bool prevMedi = IsApplyGlyphFeature(i - 1, medi, chars);
  1284. bool prevInit = IsApplyGlyphFeature(i - 1, init, chars);
  1285. if (nextMedi || nextFina)
  1286. {
  1287. if (prevMedi || prevInit)
  1288. {
  1289. bool curMedi = IsApplyGlyphFeature(i, medi, chars);
  1290. if (curMedi)
  1291. {
  1292. types[i] = ArabicCharType.Medi;
  1293. continue;
  1294. }
  1295. }
  1296. else
  1297. {
  1298. bool curInit = IsApplyGlyphFeature(i, init, chars);
  1299. if (curInit)
  1300. {
  1301. types[i] = ArabicCharType.Init;
  1302. continue;
  1303. }
  1304. }
  1305. types[i] = ArabicCharType.None;
  1306. continue;
  1307. }
  1308. if (prevInit || prevMedi)
  1309. {
  1310. bool curFina = IsApplyGlyphFeature(i, fina, chars);
  1311. if (curFina)
  1312. {
  1313. types[i] = ArabicCharType.Fina;
  1314. continue;
  1315. }
  1316. types[i] = ArabicCharType.None;
  1317. continue;
  1318. }
  1319. if (!nextMedi && !nextFina && !prevInit && !prevMedi)
  1320. {
  1321. bool curIsol = IsApplyGlyphFeature(i, isol, chars);
  1322. if (curIsol)
  1323. {
  1324. types[i] = ArabicCharType.Isol;
  1325. continue;
  1326. }
  1327. types[i] = ArabicCharType.None;
  1328. continue;
  1329. }
  1330. types[i] = ArabicCharType.None;
  1331. }
  1332. for (int i = 0; i < chars.Length; i++)
  1333. {
  1334. switch (types[i])
  1335. {
  1336. case ArabicCharType.None:
  1337. result.Add(chars[i]);
  1338. break;
  1339. case ArabicCharType.Isol:
  1340. ApplyGlyphFeature(result, isol, chars, ref i);
  1341. break;
  1342. case ArabicCharType.Fina:
  1343. ApplyGlyphFeature(result, fina, chars, ref i);
  1344. break;
  1345. case ArabicCharType.Medi:
  1346. ApplyGlyphFeature(result, medi, chars, ref i);
  1347. break;
  1348. case ArabicCharType.Init:
  1349. ApplyGlyphFeature(result, init, chars, ref i);
  1350. break;
  1351. }
  1352. }
  1353. chars = result.ToArray();
  1354. result.Clear();
  1355. if (lang_sys.Contains("rlig"))
  1356. {
  1357. ushort[] rlig = lang_sys["rlig"] as ushort[];
  1358. for (int i = 0; i < chars.Length; i++)
  1359. {
  1360. ApplyGlyphFeature(result, rlig, chars, ref i);
  1361. }
  1362. chars = result.ToArray();
  1363. result.Clear();
  1364. }
  1365. if (lang_sys.Contains("calt"))
  1366. {
  1367. ushort[] calt = lang_sys["calt"] as ushort[];
  1368. for (int i = 0; i < chars.Length; i++)
  1369. {
  1370. ApplyGlyphFeature(result, calt, chars, ref i);
  1371. }
  1372. chars = result.ToArray();
  1373. result.Clear();
  1374. }
  1375. return new List<ushort>(chars);
  1376. }
  1377. enum ArabicCharType
  1378. {
  1379. None, Isol, Init, Medi, Fina
  1380. }
  1381. private ushort[] ApplySubstLookupRecord(ushort[] resultArr, SubstLookupRecord[] records)
  1382. {
  1383. List<ushort> result = new List<ushort>();
  1384. for (int j = 0; j < records.Length; j++)
  1385. {
  1386. result.Clear();
  1387. int resultIndex = 0;
  1388. for (; resultIndex < records[j].GlyphSequenceIndex; resultIndex++)
  1389. result.Add(resultArr[resultIndex]);
  1390. LookupEntry le = lookup_list[records[j].LookupListIndex];
  1391. for (int k = 0; k < le.subs.Length; k++)
  1392. {
  1393. if (le.subs[k].Apply(result, resultArr, ref resultIndex))
  1394. {
  1395. resultIndex += 1;
  1396. break;
  1397. }
  1398. }
  1399. for (; resultIndex < resultArr.Length; resultIndex++)
  1400. result.Add(resultArr[resultIndex]);
  1401. resultArr = result.ToArray();
  1402. }
  1403. return resultArr;
  1404. }
  1405. public interface Substitution
  1406. {
  1407. // need to index = index + step - 1;
  1408. /// <summary>
  1409. /// Return true if was applied
  1410. /// </summary>
  1411. /// <param name="list"></param>
  1412. /// <param name="chars"></param>
  1413. /// <param name="index"></param>
  1414. /// <returns></returns>
  1415. bool Apply(List<ushort> list, ushort[] chars, ref int index);
  1416. /// <summary>
  1417. /// Return coverageIndex for ApplyForce or if fail then return -1
  1418. /// </summary>
  1419. /// <param name="chars"></param>
  1420. /// <param name="index"></param>
  1421. /// <returns></returns>
  1422. int IsApply(ushort[] chars, int index);
  1423. /// <summary>
  1424. /// Apply this Substitution with specified coverageIndex, cant be called only after IsApply
  1425. /// </summary>
  1426. /// <param name="list"></param>
  1427. /// <param name="chars"></param>
  1428. /// <param name="index"></param>
  1429. /// <param name="coverageIndex"></param>
  1430. void ApplyForce(List<ushort> list, ushort[] chars, ref int index, int coverageIndex);
  1431. IEnumerable<KeyValuePair<ushort[], ushort[]>> GetList(LookupTypes[] types);
  1432. }
  1433. public interface Coverage
  1434. {
  1435. int IsSubstituteGetIndex(ushort ch);
  1436. ushort[] GetGlyphs();
  1437. ushort GetFirstGlyph();
  1438. }
  1439. public struct Coverage1 : Coverage
  1440. {
  1441. public ushort GlyphCount;
  1442. public ushort[] Glyphs;
  1443. public Coverage1(ushort glyphCount, ushort[] glyphs)
  1444. {
  1445. this.GlyphCount = glyphCount;
  1446. this.Glyphs = glyphs;
  1447. }
  1448. public ushort GetFirstGlyph()
  1449. {
  1450. if (Glyphs.Length > 0)
  1451. return Glyphs[0];
  1452. return 1;
  1453. }
  1454. public ushort[] GetGlyphs()
  1455. {
  1456. return Glyphs;
  1457. }
  1458. public int IsSubstituteGetIndex(ushort ch)
  1459. {
  1460. for (int i = 0; i < GlyphCount; i++)
  1461. {
  1462. if (Glyphs[i] == ch)
  1463. return i;
  1464. }
  1465. return -1;
  1466. }
  1467. }
  1468. public struct Coverage2 : Coverage
  1469. {
  1470. public ushort GlyphCount;
  1471. public RangeRecord[] RangeRecords;
  1472. public Coverage2(ushort glyphCount, RangeRecord[] rangeRecords)
  1473. {
  1474. this.GlyphCount = glyphCount;
  1475. this.RangeRecords = rangeRecords;
  1476. }
  1477. public ushort GetFirstGlyph()
  1478. {
  1479. if (RangeRecords.Length > 0)
  1480. return RangeRecords[0].Start;
  1481. return 1;
  1482. }
  1483. public ushort[] GetGlyphs()
  1484. {
  1485. Dictionary<int, ushort> results = new Dictionary<int, ushort>();
  1486. for (int i = 0; i < RangeRecords.Length; i++)
  1487. {
  1488. for (int j = 0; j + RangeRecords[i].Start <= RangeRecords[i].End; j++)
  1489. {
  1490. results[j + RangeRecords[i].StartCoverageIndex] =
  1491. (ushort)(RangeRecords[i].Start + j);
  1492. }
  1493. }
  1494. ushort[] result = new ushort[results.Count];
  1495. foreach (ushort key in results.Keys)
  1496. {
  1497. result[key] = results[key];
  1498. }
  1499. return result;
  1500. }
  1501. public int IsSubstituteGetIndex(ushort ch)
  1502. {
  1503. //var arr = RangeRecords.Select(a => a).OrderBy(a => a.StartCoverageIndex).ToArray();
  1504. for (int i = 0; i < GlyphCount; i++)
  1505. {
  1506. if (RangeRecords[i].Start <= ch && RangeRecords[i].End >= ch)
  1507. return RangeRecords[i].End - RangeRecords[i].Start + RangeRecords[i].StartCoverageIndex;
  1508. }
  1509. return -1;
  1510. }
  1511. }
  1512. public struct Single1 : Substitution
  1513. {
  1514. public short DeltaGlyphIDOrGlyphCount;
  1515. public Coverage Coverage;
  1516. public Single1(short deltaGlyphID, Coverage coverage)
  1517. {
  1518. this.DeltaGlyphIDOrGlyphCount = deltaGlyphID;
  1519. this.Coverage = coverage;
  1520. }
  1521. public bool Apply(List<ushort> list, ushort[] chars, ref int index)
  1522. {
  1523. int index2 = IsApply(chars, index);
  1524. if (index2 >= 0)
  1525. {
  1526. ApplyForce(list, chars, ref index, index2);
  1527. return true;
  1528. }
  1529. return false;
  1530. }
  1531. public void ApplyForce(List<ushort> list, ushort[] chars, ref int index, int coverageIndex)
  1532. {
  1533. list.Add((ushort)(chars[index] + DeltaGlyphIDOrGlyphCount));
  1534. }
  1535. public IEnumerable<KeyValuePair<ushort[], ushort[]>> GetList(LookupTypes[] types)
  1536. {
  1537. if (types != null && !ExtFor2005.Contains(types, LookupTypes.Single))
  1538. yield break;
  1539. ushort[] glyphs = Coverage.GetGlyphs();
  1540. for (int i = 0; i < glyphs.Length; i++)
  1541. {
  1542. yield return new KeyValuePair<ushort[], ushort[]>(
  1543. new ushort[] { glyphs[i] },
  1544. new ushort[] { (ushort)(glyphs[i] + DeltaGlyphIDOrGlyphCount) }
  1545. );
  1546. }
  1547. }
  1548. public int IsApply(ushort[] chars, int index)
  1549. {
  1550. return Coverage.IsSubstituteGetIndex(chars[index]);
  1551. }
  1552. }
  1553. public struct Single2 : Substitution
  1554. {
  1555. public ushort[] Substitutes;
  1556. public Coverage Coverage;
  1557. public Single2(ushort[] substitutes, Coverage coverage)
  1558. {
  1559. this.Substitutes = substitutes;
  1560. this.Coverage = coverage;
  1561. }
  1562. public bool Apply(List<ushort> list, ushort[] chars, ref int index)
  1563. {
  1564. int index2 = IsApply(chars, index);
  1565. if (index2 >= 0)
  1566. {
  1567. ApplyForce(list, chars, ref index, index2);
  1568. return true;
  1569. }
  1570. return false;
  1571. }
  1572. public void ApplyForce(List<ushort> list, ushort[] chars, ref int index, int coverageIndex)
  1573. {
  1574. list.Add(Substitutes[coverageIndex]);
  1575. }
  1576. public IEnumerable<KeyValuePair<ushort[], ushort[]>> GetList(LookupTypes[] types)
  1577. {
  1578. if (types != null && !ExtFor2005.Contains(types, LookupTypes.Single))
  1579. yield break;
  1580. ushort[] glyphs = Coverage.GetGlyphs();
  1581. for (int i = 0; i < glyphs.Length; i++)
  1582. {
  1583. yield return new KeyValuePair<ushort[], ushort[]>(
  1584. new ushort[] { glyphs[i] },
  1585. new ushort[] { Substitutes[i] }
  1586. );
  1587. }
  1588. }
  1589. public int IsApply(ushort[] chars, int index)
  1590. {
  1591. return Coverage.IsSubstituteGetIndex(chars[index]);
  1592. }
  1593. }
  1594. public struct Multiple : Substitution
  1595. {
  1596. public ushort[][] Sequences;
  1597. public Coverage Coverage;
  1598. public Multiple(ushort[][] sequences, Coverage coverage)
  1599. {
  1600. this.Sequences = sequences;
  1601. this.Coverage = coverage;
  1602. }
  1603. public bool Apply(List<ushort> list, ushort[] chars, ref int index)
  1604. {
  1605. int index2 = IsApply(chars, index);
  1606. if (index2 >= 0)
  1607. {
  1608. ApplyForce(list, chars, ref index, index2);
  1609. return true;
  1610. }
  1611. return false;
  1612. }
  1613. public void ApplyForce(List<ushort> list, ushort[] chars, ref int index, int coverageIndex)
  1614. {
  1615. list.AddRange(Sequences[coverageIndex]);
  1616. }
  1617. public IEnumerable<KeyValuePair<ushort[], ushort[]>> GetList(LookupTypes[] types)
  1618. {
  1619. if (types != null && !ExtFor2005.Contains(types, LookupTypes.Multiple))
  1620. yield break;
  1621. ushort[] glyphs = Coverage.GetGlyphs();
  1622. for (int i = 0; i < glyphs.Length; i++)
  1623. {
  1624. yield return new KeyValuePair<ushort[], ushort[]>(
  1625. new ushort[] { glyphs[i] },
  1626. Sequences[i]);
  1627. }
  1628. }
  1629. public int IsApply(ushort[] chars, int index)
  1630. {
  1631. return Coverage.IsSubstituteGetIndex(chars[index]);
  1632. }
  1633. }
  1634. public struct Ligature : Substitution
  1635. {
  1636. public Coverage Coverage;
  1637. public LigatureSet[][] LigatureSets;
  1638. LigatureSet LastSetIsApply;
  1639. public Ligature(Coverage coverage, LigatureSet[][] ligatureSets)
  1640. {
  1641. this.Coverage = coverage;
  1642. this.LigatureSets = ligatureSets;
  1643. LastSetIsApply = new LigatureSet();
  1644. }
  1645. public bool Apply(List<ushort> list, ushort[] chars, ref int index)
  1646. {
  1647. int index2 = IsApply(chars, index);
  1648. if (index2 >= 0)
  1649. {
  1650. ApplyForce(list, chars, ref index, index2);
  1651. return true;
  1652. }
  1653. return false;
  1654. }
  1655. public void ApplyForce(List<ushort> list, ushort[] chars, ref int index, int coverageIndex)
  1656. {
  1657. index += LastSetIsApply.Components.Length;
  1658. list.Add(LastSetIsApply.LigGlyph);
  1659. }
  1660. public IEnumerable<KeyValuePair<ushort[], ushort[]>> GetList(LookupTypes[] types)
  1661. {
  1662. if (types != null && !ExtFor2005.Contains(types, LookupTypes.Ligature))
  1663. yield break;
  1664. ushort[] glyphs = Coverage.GetGlyphs();
  1665. for (int i = 0; i < glyphs.Length; i++)
  1666. {
  1667. LigatureSet[] set = LigatureSets[i];
  1668. for (int j = 0; j < set.Length; j++)
  1669. {
  1670. ushort[] key = new ushort[set[j].Components.Length + 1];
  1671. key[0] = glyphs[i];
  1672. for (int k = 0; k < set[j].Components.Length; k++)
  1673. key[k + 1] = set[j].Components[k];
  1674. yield return new KeyValuePair<ushort[], ushort[]>(
  1675. key,
  1676. new ushort[] { set[j].LigGlyph });
  1677. }
  1678. }
  1679. }
  1680. public int IsApply(ushort[] chars, int index)
  1681. {
  1682. int index2 = Coverage.IsSubstituteGetIndex(chars[index]);
  1683. if (index2 >= 0)
  1684. {
  1685. LigatureSet[] sets = LigatureSets[index2];
  1686. foreach (LigatureSet set in sets)
  1687. {
  1688. if (chars.Length - 1 - index - set.Components.Length >= 0)
  1689. {
  1690. bool flag = true;
  1691. for (int i = 0; i < set.Components.Length; i++)
  1692. {
  1693. if (set.Components[i] != chars[index + 1 + i])
  1694. {
  1695. flag = false;
  1696. break;
  1697. }
  1698. }
  1699. if (flag)
  1700. {
  1701. LastSetIsApply = set;
  1702. return index2;
  1703. }
  1704. }
  1705. }
  1706. }
  1707. return -1;
  1708. }
  1709. }
  1710. public struct LigatureSet
  1711. {
  1712. public ushort LigGlyph;
  1713. public ushort[] Components;
  1714. public LigatureSet(ushort ligGlyph, ushort[] components)
  1715. {
  1716. this.LigGlyph = ligGlyph;
  1717. this.Components = components;
  1718. }
  1719. }
  1720. public struct Contextual1 : Substitution
  1721. {
  1722. public struct SubRule
  1723. {
  1724. public ushort[] InputSequence;
  1725. public SubstLookupRecord[] Records;
  1726. public SubRule(ushort[] inputSequence, SubstLookupRecord[] records)
  1727. {
  1728. InputSequence = inputSequence;
  1729. Records = records;
  1730. }
  1731. }
  1732. public SubRule[][] SubRuleSets;
  1733. public Coverage Coverage;
  1734. private GlyphSubstitutionClass gsub_table;
  1735. SubRule LastSubRuleIsApply;
  1736. public Contextual1(GlyphSubstitutionClass gsub_table, SubRule[][] subRuleSets, Coverage coverage)
  1737. {
  1738. this.gsub_table = gsub_table;
  1739. SubRuleSets = subRuleSets;
  1740. Coverage = coverage;
  1741. LastSubRuleIsApply = new SubRule();
  1742. }
  1743. public bool Apply(List<ushort> list, ushort[] chars, ref int index)
  1744. {
  1745. int index2 = IsApply(chars, index);
  1746. if (index2 >= 0)
  1747. {
  1748. ApplyForce(list, chars, ref index, index2);
  1749. return true;
  1750. }
  1751. return false;
  1752. }
  1753. public IEnumerable<KeyValuePair<ushort[], ushort[]>> GetList(LookupTypes[] types)
  1754. {
  1755. if (types != null && !ExtFor2005.Contains(types, LookupTypes.Context))
  1756. yield break;
  1757. ushort[] glyphs = Coverage.GetGlyphs();
  1758. for (int i = 0; i < glyphs.Length; i++)
  1759. {
  1760. SubRule[] set = SubRuleSets[i];
  1761. for (int j = 0; j < set.Length; j++)
  1762. {
  1763. ushort[] key = new ushort[set[j].InputSequence.Length + 1];
  1764. key[0] = glyphs[i];
  1765. for (int k = 0; k < set[j].InputSequence.Length; k++)
  1766. key[k + 1] = set[j].InputSequence[k];
  1767. yield return new KeyValuePair<ushort[], ushort[]>(
  1768. key,
  1769. gsub_table.ApplySubstLookupRecord(key, set[j].Records));
  1770. }
  1771. }
  1772. }
  1773. public int IsApply(ushort[] chars, int index)
  1774. {
  1775. int index2 = Coverage.IsSubstituteGetIndex(chars[index]);
  1776. if (index2 >= 0)
  1777. {
  1778. SubRule[] subRules = SubRuleSets[index2];
  1779. foreach (SubRule rule in subRules)
  1780. {
  1781. if (chars.Length - 1 - index - rule.InputSequence.Length >= 0)
  1782. {
  1783. bool flag = true;
  1784. for (int i = 0; i < rule.InputSequence.Length; i++)
  1785. {
  1786. if (rule.InputSequence[i] != chars[index + 1 + i])
  1787. {
  1788. flag = false;
  1789. break;
  1790. }
  1791. }
  1792. if (flag)
  1793. {
  1794. LastSubRuleIsApply = rule;
  1795. return index2;
  1796. }
  1797. }
  1798. }
  1799. }
  1800. return -1;
  1801. }
  1802. public void ApplyForce(List<ushort> list, ushort[] chars, ref int index, int coverageIndex)
  1803. {
  1804. ushort[] resultArr = new ushort[LastSubRuleIsApply.InputSequence.Length + 1];
  1805. for (int j = 0; j < resultArr.Length; j++)
  1806. {
  1807. resultArr[j] = chars[j + index];
  1808. }
  1809. list.AddRange(gsub_table.ApplySubstLookupRecord(resultArr, LastSubRuleIsApply.Records));
  1810. index += LastSubRuleIsApply.InputSequence.Length;
  1811. }
  1812. }
  1813. public struct Contextual2 : Substitution
  1814. {
  1815. public struct SubClassRule
  1816. {
  1817. public ushort[] InputSequence;
  1818. public SubstLookupRecord[] Records;
  1819. public SubClassRule(ushort[] inputSequence, SubstLookupRecord[] records)
  1820. {
  1821. InputSequence = inputSequence;
  1822. Records = records;
  1823. }
  1824. }
  1825. public SubClassRule[][] SubClassRuleSets;
  1826. private GlyphSubstitutionClass gsub_table;
  1827. public Coverage Coverage;
  1828. public ClassDefinition ClassDefinition;
  1829. SubClassRule LastSubClassRule;
  1830. public Contextual2(GlyphSubstitutionClass gsub_table, SubClassRule[][] subClassRuleSets, Coverage coverage, ClassDefinition classDefinition)
  1831. {
  1832. this.gsub_table = gsub_table;
  1833. SubClassRuleSets = subClassRuleSets;
  1834. Coverage = coverage;
  1835. ClassDefinition = classDefinition;
  1836. LastSubClassRule = new SubClassRule();
  1837. }
  1838. public bool Apply(List<ushort> list, ushort[] chars, ref int index)
  1839. {
  1840. int index2 = IsApply(chars, index);
  1841. if (index2 >= 0)
  1842. {
  1843. ApplyForce(list, chars, ref index, index2);
  1844. return true;
  1845. }
  1846. return false;
  1847. }
  1848. public IEnumerable<KeyValuePair<ushort[], ushort[]>> GetList(LookupTypes[] types)
  1849. {
  1850. if (types != null && !ExtFor2005.Contains(types, LookupTypes.Context))
  1851. yield break;
  1852. ushort[] glyphs = Coverage.GetGlyphs();
  1853. for (int i = 0; i < glyphs.Length; i++)
  1854. {
  1855. SubClassRule[] set = SubClassRuleSets[i];
  1856. if (set != null)
  1857. for (int j = 0; j < set.Length; j++)
  1858. {
  1859. ushort[] key = new ushort[set[j].InputSequence.Length + 1];
  1860. key[0] = glyphs[i];
  1861. for (int k = 0; k < set[j].InputSequence.Length; k++)
  1862. key[k + 1] = ClassDefinition.GetFirstGlyphByClassValue(set[j].InputSequence[k]);
  1863. yield return new KeyValuePair<ushort[], ushort[]>(
  1864. key,
  1865. gsub_table.ApplySubstLookupRecord(key, set[j].Records));
  1866. }
  1867. }
  1868. }
  1869. public int IsApply(ushort[] chars, int index)
  1870. {
  1871. int index2 = Coverage.IsSubstituteGetIndex(chars[index]);
  1872. if (index2 >= 0)
  1873. {
  1874. SubClassRule[] subClassRules = SubClassRuleSets[index2];
  1875. if (subClassRules != null)
  1876. foreach (SubClassRule rule in subClassRules)
  1877. {
  1878. if (chars.Length - 1 - index - rule.InputSequence.Length >= 0)
  1879. {
  1880. bool flag = true;
  1881. for (int i = 0; i < rule.InputSequence.Length; i++)
  1882. {
  1883. if (rule.InputSequence[i] != ClassDefinition.GetClassValue(chars[index + 1 + i]))
  1884. {
  1885. flag = false;
  1886. break;
  1887. }
  1888. }
  1889. if (flag)
  1890. {
  1891. LastSubClassRule = rule;
  1892. return index2;
  1893. }
  1894. }
  1895. }
  1896. }
  1897. return -1;
  1898. }
  1899. public void ApplyForce(List<ushort> list, ushort[] chars, ref int index, int coverageIndex)
  1900. {
  1901. ushort[] resultArr = new ushort[LastSubClassRule.InputSequence.Length + 1];
  1902. for (int j = 0; j < resultArr.Length; j++)
  1903. {
  1904. resultArr[j] = chars[j + index];
  1905. }
  1906. list.AddRange(gsub_table.ApplySubstLookupRecord(resultArr, LastSubClassRule.Records));
  1907. index += LastSubClassRule.InputSequence.Length;
  1908. }
  1909. }
  1910. public struct Contextual3 : Substitution
  1911. {
  1912. public SubstLookupRecord[] Records;
  1913. public Coverage[] Coverages;
  1914. private GlyphSubstitutionClass gsub_table;
  1915. public Contextual3(GlyphSubstitutionClass gsub_table, SubstLookupRecord[] records, Coverage[] coverages)
  1916. {
  1917. this.gsub_table = gsub_table;
  1918. Records = records;
  1919. Coverages = coverages;
  1920. }
  1921. public bool Apply(List<ushort> list, ushort[] chars, ref int index)
  1922. {
  1923. int index2 = IsApply(chars, index);
  1924. if (index2 >= 0)
  1925. {
  1926. ApplyForce(list, chars, ref index, index2);
  1927. return true;
  1928. }
  1929. return false;
  1930. }
  1931. public void ApplyForce(List<ushort> list, ushort[] chars, ref int index, int coverageIndex)
  1932. {
  1933. ushort[] resultArr = new ushort[Coverages.Length];
  1934. for (int j = 0; j < resultArr.Length; j++)
  1935. {
  1936. resultArr[j] = chars[j + index];
  1937. }
  1938. list.AddRange(gsub_table.ApplySubstLookupRecord(resultArr, Records));
  1939. index += Coverages.Length - 1;
  1940. }
  1941. public IEnumerable<KeyValuePair<ushort[], ushort[]>> GetList(LookupTypes[] types)
  1942. {
  1943. if (types != null && !ExtFor2005.Contains(types, LookupTypes.Context))
  1944. yield break;
  1945. if (Coverages.Length > 0)
  1946. {
  1947. ushort[] glyphs = Coverages[0].GetGlyphs();
  1948. for (int i = 0; i < glyphs.Length; i++)
  1949. {
  1950. ushort[] key = new ushort[Coverages.Length];
  1951. key[0] = glyphs[i];
  1952. for (int k = 1; k < Coverages.Length; k++)
  1953. key[k] = Coverages[k].GetFirstGlyph();
  1954. yield return new KeyValuePair<ushort[], ushort[]>(
  1955. key,
  1956. gsub_table.ApplySubstLookupRecord(key, Records));
  1957. }
  1958. }
  1959. }
  1960. public int IsApply(ushort[] chars, int index)
  1961. {
  1962. if (Coverages.Length > 0)
  1963. {
  1964. int index2 = Coverages[0].IsSubstituteGetIndex(chars[index]);
  1965. if (index2 >= 0)
  1966. {
  1967. if (chars.Length - index - Coverages.Length >= 0)
  1968. {
  1969. bool flag = true;
  1970. for (int i = 1; i < Coverages.Length; i++)
  1971. {
  1972. if (Coverages[i].IsSubstituteGetIndex(chars[index + i]) < 0)
  1973. {
  1974. flag = false;
  1975. break;
  1976. }
  1977. }
  1978. if (flag)
  1979. {
  1980. return index;
  1981. }
  1982. }
  1983. }
  1984. }
  1985. return -1;
  1986. }
  1987. }
  1988. public struct ChainingContextual1 : Substitution
  1989. {
  1990. public struct ChainSubRule
  1991. {
  1992. public ushort[] BacktrackSequence;
  1993. public ushort[] InputSequence; // count -= 1;
  1994. public ushort[] LookAheadSequence;
  1995. public SubstLookupRecord[] Records;
  1996. public ChainSubRule(ushort[] backtrackSequence, ushort[] inputSequence, ushort[] lookAheadSequence, SubstLookupRecord[] records)
  1997. {
  1998. BacktrackSequence = backtrackSequence;
  1999. InputSequence = inputSequence;
  2000. LookAheadSequence = lookAheadSequence;
  2001. Records = records;
  2002. }
  2003. }
  2004. public GlyphSubstitutionClass gsub_table;
  2005. public ChainSubRule[][] ChainSubRuleSets;
  2006. public Coverage Coverage;
  2007. ChainSubRule LastChainSubRule;
  2008. public ChainingContextual1(GlyphSubstitutionClass gsub_table, Coverage coverage, ChainSubRule[][] chainSubRuleSets)
  2009. {
  2010. this.gsub_table = gsub_table;
  2011. ChainSubRuleSets = chainSubRuleSets;
  2012. Coverage = coverage;
  2013. LastChainSubRule = new ChainSubRule();
  2014. }
  2015. public bool Apply(List<ushort> list, ushort[] chars, ref int index)
  2016. {
  2017. int index2 = IsApply(chars, index);
  2018. if (index2 >= 0)
  2019. {
  2020. ApplyForce(list, chars, ref index, index2);
  2021. return true;
  2022. }
  2023. return false;
  2024. }
  2025. public IEnumerable<KeyValuePair<ushort[], ushort[]>> GetList(LookupTypes[] types)
  2026. {
  2027. if (types != null && !ExtFor2005.Contains(types, LookupTypes.ChainingContext))
  2028. yield break;
  2029. ushort[] glyphs = Coverage.GetGlyphs();
  2030. for (int i = 0; i < glyphs.Length; i++)
  2031. {
  2032. ChainSubRule[] set = ChainSubRuleSets[i];
  2033. for (int j = 0; j < set.Length; j++)
  2034. {
  2035. ushort[] key = new ushort[set[j].InputSequence.Length + 1];
  2036. key[0] = glyphs[i];
  2037. for (int k = 0; k < set[j].InputSequence.Length; k++)
  2038. key[k + 1] = set[j].InputSequence[k];
  2039. yield return new KeyValuePair<ushort[], ushort[]>(
  2040. key,
  2041. gsub_table.ApplySubstLookupRecord(key, set[j].Records));
  2042. }
  2043. }
  2044. }
  2045. public int IsApply(ushort[] chars, int index)
  2046. {
  2047. int index2 = Coverage.IsSubstituteGetIndex(chars[index]);
  2048. if (index2 >= 0)
  2049. {
  2050. ChainSubRule[] subRules = ChainSubRuleSets[index2];
  2051. foreach (ChainSubRule rule in subRules)
  2052. {
  2053. if (chars.Length - 1 - index - rule.InputSequence.Length >= 0 &&
  2054. chars.Length - 1 - index - rule.LookAheadSequence.Length - rule.InputSequence.Length >= 0 &&
  2055. index >= rule.BacktrackSequence.Length)
  2056. {
  2057. bool flag = true;
  2058. for (int i = 0; i < rule.InputSequence.Length; i++)
  2059. {
  2060. if (rule.InputSequence[i] != chars[index + 1 + i])
  2061. {
  2062. flag = false;
  2063. break;
  2064. }
  2065. }
  2066. if (flag)
  2067. for (int i = 0; i < rule.BacktrackSequence.Length; i++)
  2068. {
  2069. if (rule.BacktrackSequence[i] != chars[index - i - 1])
  2070. {
  2071. flag = false;
  2072. break;
  2073. }
  2074. }
  2075. if (flag)
  2076. for (int i = 0; i < rule.LookAheadSequence.Length; i++)
  2077. {
  2078. if (rule.LookAheadSequence[i] != chars[index + i + 1 + rule.InputSequence.Length])
  2079. {
  2080. flag = false;
  2081. break;
  2082. }
  2083. }
  2084. if (flag)
  2085. {
  2086. LastChainSubRule = rule;
  2087. return index2;
  2088. }
  2089. }
  2090. }
  2091. }
  2092. return -1;
  2093. }
  2094. public void ApplyForce(List<ushort> list, ushort[] chars, ref int index, int coverageIndex)
  2095. {
  2096. ushort[] resultArr = new ushort[LastChainSubRule.InputSequence.Length + 1];
  2097. for (int j = 0; j < resultArr.Length; j++)
  2098. {
  2099. resultArr[j] = chars[j + index];
  2100. }
  2101. list.AddRange(gsub_table.ApplySubstLookupRecord(resultArr, LastChainSubRule.Records));
  2102. index += LastChainSubRule.InputSequence.Length;
  2103. }
  2104. }
  2105. public struct ChainingContextual2 : Substitution
  2106. {
  2107. public struct ChainSubClassRule
  2108. {
  2109. public ushort[] BacktrackSequence;
  2110. public ushort[] InputSequence; // count -= 1;
  2111. public ushort[] LookAheadSequence;
  2112. public SubstLookupRecord[] Records;
  2113. public ChainSubClassRule(ushort[] backtrackSequence, ushort[] inputSequence, ushort[] lookAheadSequence, SubstLookupRecord[] records)
  2114. {
  2115. BacktrackSequence = backtrackSequence;
  2116. InputSequence = inputSequence;
  2117. LookAheadSequence = lookAheadSequence;
  2118. Records = records;
  2119. }
  2120. }
  2121. public ChainSubClassRule[][] SubClassRuleSets;
  2122. private GlyphSubstitutionClass gsub_table;
  2123. public Coverage Coverage;
  2124. public ClassDefinition BacktrackClassDefinition;
  2125. public ClassDefinition InputClassDefinition;
  2126. public ClassDefinition LookaheadClassDefinition;
  2127. ChainSubClassRule LastChainSubClassRule;
  2128. public ChainingContextual2(
  2129. GlyphSubstitutionClass gsub_table,
  2130. ChainSubClassRule[][] subClassRuleSets,
  2131. Coverage coverage,
  2132. ClassDefinition backtrackClassDefinition,
  2133. ClassDefinition inputClassDefinition,
  2134. ClassDefinition lookaheadClassDefinition)
  2135. {
  2136. this.gsub_table = gsub_table;
  2137. SubClassRuleSets = subClassRuleSets;
  2138. Coverage = coverage;
  2139. BacktrackClassDefinition = backtrackClassDefinition;
  2140. InputClassDefinition = inputClassDefinition;
  2141. LookaheadClassDefinition = lookaheadClassDefinition;
  2142. LastChainSubClassRule = new ChainSubClassRule();
  2143. }
  2144. public bool Apply(List<ushort> list, ushort[] chars, ref int index)
  2145. {
  2146. int index2 = IsApply(chars, index);
  2147. if (index2 >= 0)
  2148. {
  2149. ApplyForce(list, chars, ref index, index2);
  2150. return true;
  2151. }
  2152. return false;
  2153. }
  2154. public IEnumerable<KeyValuePair<ushort[], ushort[]>> GetList(LookupTypes[] types)
  2155. {
  2156. if (types != null && !ExtFor2005.Contains(types, LookupTypes.ChainingContext))
  2157. yield break;
  2158. ushort[] glyphs = Coverage.GetGlyphs();
  2159. for (int i = 0; i < glyphs.Length; i++)
  2160. {
  2161. ChainSubClassRule[] set = SubClassRuleSets[i];
  2162. if (set != null)
  2163. for (int j = 0; j < set.Length; j++)
  2164. {
  2165. ushort[] key = new ushort[set[j].InputSequence.Length + 1];
  2166. key[0] = glyphs[i];
  2167. for (int k = 0; k < set[j].InputSequence.Length; k++)
  2168. key[k + 1] = InputClassDefinition.GetFirstGlyphByClassValue(set[j].InputSequence[k]);
  2169. yield return new KeyValuePair<ushort[], ushort[]>(
  2170. key,
  2171. gsub_table.ApplySubstLookupRecord(key, set[j].Records));
  2172. }
  2173. }
  2174. }
  2175. public int IsApply(ushort[] chars, int index)
  2176. {
  2177. int index2 = Coverage.IsSubstituteGetIndex(chars[index]);
  2178. if (index2 >= 0)
  2179. {
  2180. ChainSubClassRule[] subClassRules = SubClassRuleSets[index2];
  2181. if (subClassRules != null)
  2182. foreach (ChainSubClassRule rule in subClassRules)
  2183. {
  2184. if (chars.Length - 1 - index - rule.InputSequence.Length >= 0 &&
  2185. chars.Length - 1 - index - rule.LookAheadSequence.Length - rule.InputSequence.Length >= 0 &&
  2186. index >= rule.BacktrackSequence.Length)
  2187. {
  2188. bool flag = true;
  2189. for (int i = 0; i < rule.InputSequence.Length; i++)
  2190. {
  2191. if (rule.InputSequence[i] != InputClassDefinition.GetClassValue(chars[index + 1 + i]))
  2192. {
  2193. flag = false;
  2194. break;
  2195. }
  2196. }
  2197. if (flag)
  2198. for (int i = 0; i < rule.BacktrackSequence.Length; i++)
  2199. {
  2200. if (rule.BacktrackSequence[i] != BacktrackClassDefinition.GetClassValue(chars[index - i - 1]))
  2201. {
  2202. flag = false;
  2203. break;
  2204. }
  2205. }
  2206. if (flag)
  2207. for (int i = 0; i < rule.LookAheadSequence.Length; i++)
  2208. {
  2209. if (rule.LookAheadSequence[i] !=
  2210. LookaheadClassDefinition.GetClassValue(
  2211. chars[index + i + 1 + rule.InputSequence.Length]))
  2212. {
  2213. flag = false;
  2214. break;
  2215. }
  2216. }
  2217. if (flag)
  2218. {
  2219. LastChainSubClassRule = rule;
  2220. return index2;
  2221. }
  2222. }
  2223. }
  2224. }
  2225. return -1;
  2226. }
  2227. public void ApplyForce(List<ushort> list, ushort[] chars, ref int index, int coverageIndex)
  2228. {
  2229. ushort[] resultArr = new ushort[LastChainSubClassRule.InputSequence.Length + 1];
  2230. for (int j = 0; j < resultArr.Length; j++)
  2231. {
  2232. resultArr[j] = chars[j + index];
  2233. }
  2234. list.AddRange(gsub_table.ApplySubstLookupRecord(resultArr, LastChainSubClassRule.Records));
  2235. index += LastChainSubClassRule.InputSequence.Length;
  2236. }
  2237. }
  2238. public struct ChainingContextual3 : Substitution
  2239. {
  2240. public SubstLookupRecord[] Records;
  2241. public Coverage[] BacktrackCoverages;
  2242. public Coverage[] InputCoverages;
  2243. public Coverage[] LookaheadCoverages;
  2244. private GlyphSubstitutionClass gsub_table;
  2245. public ChainingContextual3(GlyphSubstitutionClass gsub_table, SubstLookupRecord[] records, Coverage[] backtrackCoverages, Coverage[] inputCoverages, Coverage[] lookaheadCoverages)
  2246. {
  2247. this.gsub_table = gsub_table;
  2248. Records = records;
  2249. BacktrackCoverages = backtrackCoverages;
  2250. InputCoverages = inputCoverages;
  2251. LookaheadCoverages = lookaheadCoverages;
  2252. }
  2253. public bool Apply(List<ushort> list, ushort[] chars, ref int index)
  2254. {
  2255. int index2 = IsApply(chars, index);
  2256. if (index2 >= 0)
  2257. {
  2258. ApplyForce(list, chars, ref index, index2);
  2259. return true;
  2260. }
  2261. return false;
  2262. }
  2263. public void ApplyForce(List<ushort> list, ushort[] chars, ref int index, int coverageIndex)
  2264. {
  2265. ushort[] resultArr = new ushort[InputCoverages.Length];
  2266. for (int j = 0; j < resultArr.Length; j++)
  2267. {
  2268. resultArr[j] = chars[j + index];
  2269. }
  2270. list.AddRange(gsub_table.ApplySubstLookupRecord(resultArr, Records));
  2271. index += InputCoverages.Length - 1;
  2272. }
  2273. public IEnumerable<KeyValuePair<ushort[], ushort[]>> GetList(LookupTypes[] types)
  2274. {
  2275. if (types != null && !ExtFor2005.Contains(types, LookupTypes.ChainingContext))
  2276. yield break;
  2277. if (InputCoverages.Length > 0)
  2278. {
  2279. ushort[] glyphs = InputCoverages[0].GetGlyphs();
  2280. for (int i = 0; i < glyphs.Length; i++)
  2281. {
  2282. ushort[] key = new ushort[InputCoverages.Length];
  2283. key[0] = glyphs[i];
  2284. if (InputCoverages.Length > 0)
  2285. for (int k = 1; k < InputCoverages.Length; k++)
  2286. key[k] = InputCoverages[k].GetFirstGlyph();
  2287. yield return new KeyValuePair<ushort[], ushort[]>(
  2288. key,
  2289. gsub_table.ApplySubstLookupRecord(key, Records));
  2290. }
  2291. }
  2292. }
  2293. public int IsApply(ushort[] chars, int index)
  2294. {
  2295. if (InputCoverages.Length > 0)
  2296. {
  2297. int index2 = InputCoverages[0].IsSubstituteGetIndex(chars[index]);
  2298. if (index2 >= 0)
  2299. {
  2300. if (chars.Length - 1 - index - InputCoverages.Length >= 0 &&
  2301. chars.Length - 1 - index - LookaheadCoverages.Length - InputCoverages.Length >= 0 &&
  2302. index >= BacktrackCoverages.Length)
  2303. {
  2304. bool flag = true;
  2305. for (int i = 1; i < InputCoverages.Length; i++)
  2306. {
  2307. if (InputCoverages[i].IsSubstituteGetIndex(chars[index + i]) < 0)
  2308. {
  2309. flag = false;
  2310. break;
  2311. }
  2312. }
  2313. if (flag)
  2314. for (int i = 0; i < BacktrackCoverages.Length; i++)
  2315. {
  2316. if (BacktrackCoverages[i].IsSubstituteGetIndex(chars[index - i - 1]) < 0)
  2317. {
  2318. flag = false;
  2319. break;
  2320. }
  2321. }
  2322. if (flag)
  2323. for (int i = 0; i < LookaheadCoverages.Length; i++)
  2324. {
  2325. if (LookaheadCoverages[i].IsSubstituteGetIndex(
  2326. chars[index + i + 1 + InputCoverages.Length]) < 0)
  2327. {
  2328. flag = false;
  2329. break;
  2330. }
  2331. }
  2332. if (flag)
  2333. {
  2334. return index2;
  2335. }
  2336. }
  2337. }
  2338. }
  2339. return -1;
  2340. }
  2341. }
  2342. public struct Extension : Substitution
  2343. {
  2344. public Substitution Substitution;
  2345. public ushort LookupType;
  2346. public ushort Format;
  2347. public bool Apply(List<ushort> list, ushort[] chars, ref int index)
  2348. {
  2349. return Substitution.Apply(list, chars, ref index);
  2350. }
  2351. public void ApplyForce(List<ushort> list, ushort[] chars, ref int index, int coverageIndex)
  2352. {
  2353. Substitution.ApplyForce(list, chars, ref index, coverageIndex);
  2354. }
  2355. public IEnumerable<KeyValuePair<ushort[], ushort[]>> GetList(LookupTypes[] types)
  2356. {
  2357. if (types != null && !ExtFor2005.Contains(types, LookupTypes.ExtensionSubstitution))
  2358. return new KeyValuePair<ushort[], ushort[]>[0];
  2359. return Substitution.GetList(types);
  2360. }
  2361. public int IsApply(ushort[] chars, int index)
  2362. {
  2363. return Substitution.IsApply(chars, index);
  2364. }
  2365. }
  2366. public struct VoidSubstitution : Substitution
  2367. {
  2368. public bool Apply(List<ushort> list, ushort[] chars, ref int index)
  2369. {
  2370. return false;
  2371. }
  2372. public void ApplyForce(List<ushort> list, ushort[] chars, ref int index, int coverageIndex)
  2373. {
  2374. }
  2375. public IEnumerable<KeyValuePair<ushort[], ushort[]>> GetList(LookupTypes[] types)
  2376. {
  2377. yield break;
  2378. }
  2379. public int IsApply(ushort[] chars, int index)
  2380. {
  2381. return -1;
  2382. }
  2383. }
  2384. internal IEnumerable<KeyValuePair<ushort[], ushort[]>> GetSubstitutions(string script, string language, string feature, LookupTypes[] types)
  2385. {
  2386. if (script_list.ContainsKey(script))
  2387. {
  2388. Hashtable lang_sys_hash = script_list[script] as Hashtable;
  2389. Hashtable lang_sys = null;
  2390. if (lang_sys_hash.ContainsKey(language))
  2391. {
  2392. lang_sys = lang_sys_hash[language] as Hashtable;
  2393. }
  2394. else if (lang_sys_hash.ContainsKey(string.Empty))
  2395. {
  2396. lang_sys = lang_sys_hash[string.Empty] as Hashtable;
  2397. }
  2398. if (lang_sys != null)
  2399. {
  2400. if (lang_sys.ContainsKey(feature))
  2401. {
  2402. foreach (ushort offset in (ushort[])lang_sys[feature])
  2403. {
  2404. LookupEntry le = (LookupEntry)lookup_list[offset];
  2405. for (int i = 0; i < le.subs.Length; i++)
  2406. {
  2407. foreach (KeyValuePair<ushort[], ushort[]> sub in le.subs[i].GetList(types))
  2408. yield return sub;
  2409. }
  2410. }
  2411. }
  2412. }
  2413. }
  2414. }
  2415. public struct VoidCoverage : Coverage
  2416. {
  2417. public ushort GetFirstGlyph()
  2418. {
  2419. return 1;
  2420. }
  2421. public ushort[] GetGlyphs()
  2422. {
  2423. return new ushort[0];
  2424. }
  2425. public int IsSubstituteGetIndex(ushort ch)
  2426. {
  2427. return -1;
  2428. }
  2429. }
  2430. public interface ClassDefinition
  2431. {
  2432. ushort GetClassValue(ushort glyph);
  2433. ushort GetFirstGlyphByClassValue(ushort v);
  2434. }
  2435. public struct ClassDefinition1 : ClassDefinition
  2436. {
  2437. ushort StartGlyphId;
  2438. ushort[] ClassValues;
  2439. public ClassDefinition1(ushort startGlyphId, ushort[] classValues)
  2440. {
  2441. StartGlyphId = startGlyphId;
  2442. ClassValues = classValues;
  2443. }
  2444. public ushort GetClassValue(ushort glyph)
  2445. {
  2446. int index = glyph - StartGlyphId;
  2447. if (index >= 0 && index < ClassValues.Length)
  2448. return ClassValues[index];
  2449. return 0;
  2450. }
  2451. public ushort GetFirstGlyphByClassValue(ushort v)
  2452. {
  2453. for (int i = 0; i < ClassValues.Length; i++)
  2454. if (ClassValues[i] == v)
  2455. return (ushort)(StartGlyphId + i);
  2456. return StartGlyphId;
  2457. }
  2458. }
  2459. public struct ClassDefinition2 : ClassDefinition
  2460. {
  2461. ClassRangeRecord[] Records;
  2462. public ClassDefinition2(ClassRangeRecord[] records)
  2463. {
  2464. Records = records;
  2465. }
  2466. public ushort GetClassValue(ushort glyph)
  2467. {
  2468. foreach (ClassRangeRecord record in Records)
  2469. if (record.StartGlyphID <= glyph && record.EndGlyphID >= glyph)
  2470. return record.ClassValue;
  2471. return 0;
  2472. }
  2473. public ushort GetFirstGlyphByClassValue(ushort v)
  2474. {
  2475. foreach (ClassRangeRecord record in Records)
  2476. if (record.ClassValue == v)
  2477. return record.StartGlyphID;
  2478. if (Records.Length > 0)
  2479. return Records[0].StartGlyphID;
  2480. return 0;
  2481. }
  2482. }
  2483. public struct VoidClassDefinition : ClassDefinition
  2484. {
  2485. public ushort GetClassValue(ushort glyph)
  2486. {
  2487. return 0;
  2488. }
  2489. public ushort GetFirstGlyphByClassValue(ushort v)
  2490. {
  2491. //TODO
  2492. //TO DO
  2493. // WHAT TO DO??? just return zero value, let it be space plz :)
  2494. return 1;
  2495. }
  2496. }
  2497. }
  2498. }
  2499. #pragma warning restore