CmapTableClass.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. using System;
  2. using System.Runtime.InteropServices;
  3. namespace FastReport.Fonts
  4. {
  5. /////////////////////////////////////////////////////////////////////////////////////////////////
  6. // Cmap table
  7. /////////////////////////////////////////////////////////////////////////////////////////////////
  8. class CmapTableClass : TrueTypeTable
  9. {
  10. #region "Type definition"
  11. public enum EncodingFormats
  12. {
  13. ByteEncoding = 0,
  14. HighByteMapping = 2,
  15. SegmentMapping = 4,
  16. TrimmedTable = 6,
  17. TrimmedArray = 10,
  18. SegmentedCoverage = 12,
  19. ManyToOneRangeMapping = 13,
  20. UnicodeVariationSequences = 14
  21. }
  22. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  23. public struct Table_CMAP
  24. {
  25. [FieldOffset(0)]
  26. public ushort TableVersion;
  27. [FieldOffset(2)]
  28. public ushort NumSubTables;
  29. }
  30. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  31. public struct Table_SUBMAP
  32. {
  33. [FieldOffset(0)]
  34. public ushort Platform;
  35. [FieldOffset(2)]
  36. public ushort EncodingID;
  37. [FieldOffset(4)]
  38. public uint TableOffset;
  39. }
  40. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  41. public struct SegmentMapping
  42. {
  43. [FieldOffset(0)]
  44. public ushort Format;
  45. [FieldOffset(2)]
  46. public ushort Length;
  47. [FieldOffset(4)]
  48. public ushort Version;
  49. [FieldOffset(6)]
  50. public ushort segCountX2; // 2 x segCount.
  51. [FieldOffset(8)]
  52. public ushort searchRange; // 2 x (2**floor(log2(segCount)))
  53. [FieldOffset(10)]
  54. public ushort entrySelector; // log2(searchRange/2)
  55. [FieldOffset(12)]
  56. public ushort rangeShift; // 2 x segCount - searchRange
  57. }
  58. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  59. public struct SequentialMapGroup
  60. {
  61. [FieldOffset(0)]
  62. public uint startCharCode;
  63. [FieldOffset(4)]
  64. public uint searchRange;
  65. [FieldOffset(8)]
  66. public uint entrySelector;
  67. }
  68. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  69. public struct Format6 // Trimmed table
  70. {
  71. [FieldOffset(0)]
  72. public ushort format;
  73. [FieldOffset(4)]
  74. public ushort length;
  75. [FieldOffset(6)]
  76. public ushort language;
  77. [FieldOffset(8)]
  78. public ushort startCharCode;
  79. [FieldOffset(10)]
  80. public ushort numChars;
  81. }
  82. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  83. public struct Format8
  84. {
  85. }
  86. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  87. public struct Format10 // Trimmed array
  88. {
  89. [FieldOffset(0)]
  90. public ushort format;
  91. [FieldOffset(2)]
  92. public ushort reserved;
  93. [FieldOffset(4)]
  94. public uint length;
  95. [FieldOffset(8)]
  96. public uint language;
  97. [FieldOffset(12)]
  98. public uint startCharCode;
  99. [FieldOffset(16)]
  100. public uint numChars;
  101. }
  102. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  103. public struct Format12
  104. {
  105. [FieldOffset(0)]
  106. public ushort format; // Subtable format; set to 12.
  107. [FieldOffset(2)]
  108. public ushort reserved; // Reserved; set to 0
  109. [FieldOffset(4)]
  110. public uint length; // Byte length of this subtable (including the header)
  111. [FieldOffset(8)]
  112. public uint language;
  113. [FieldOffset(12)]
  114. public uint numGroups; // Number of groupings which follow
  115. }
  116. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  117. public struct VariationSequences
  118. {
  119. [FieldOffset(0)]
  120. public ushort Format;
  121. [FieldOffset(2)]
  122. public uint Length;
  123. [FieldOffset(6)]
  124. public uint NumRecords;
  125. }
  126. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  127. public struct VariationSequenceRecord
  128. {
  129. [FieldOffset(0)]
  130. public byte _b0; //
  131. [FieldOffset(1)]
  132. public byte _b1; //
  133. [FieldOffset(2)]
  134. public byte _b2; //
  135. [FieldOffset(3)]
  136. public uint defaultUVSOffset; //
  137. [FieldOffset(7)]
  138. public uint nonDefaultUVSOffset; //
  139. // Not shure that followin property is allowed in packed structures
  140. public uint VariantSelector { get { return (uint)(_b0 | (_b1 << 8) | (_b2 << 16)); } }
  141. }
  142. #endregion
  143. // Format 4: Segment mapping to delta values
  144. int segment_count;
  145. ushort[] endCount;
  146. ushort[] startCount;
  147. short[] idDelta;
  148. ushort[] idRangeOffset;
  149. ushort[] glyphIndexArray;
  150. // Format 6 and 10
  151. uint trimmedStat;
  152. ushort[] trimmed;
  153. // Format 12: Segmented coverage
  154. SequentialMapGroup[] mapGroup;
  155. private ushort[] LoadCmapSegment(FontStream stream, int segment_count)
  156. {
  157. ushort[] result = new ushort[segment_count];
  158. for (int i = 0; i < segment_count; i++)
  159. result[i] = stream.ReadUInt16();
  160. return result;
  161. }
  162. private short[] LoadSignedCmapSegment(FontStream stream, int segment_count)
  163. {
  164. short[] result = new short[segment_count];
  165. for (int i = 0; i < segment_count; i++)
  166. {
  167. result[i] = stream.ReadInt16();
  168. }
  169. return result;
  170. }
  171. internal void LoadCmapTable(FontStream stream)
  172. {
  173. // IntPtr subtable_ptr;
  174. // IntPtr cmap_ptr = Increment(font, (int)this.Offset);
  175. stream.Seek(this.Offset, System.IO.SeekOrigin.Begin);
  176. Table_CMAP cmap = new Table_CMAP(); // Marshal.PtrToStructure(cmap_ptr, typeof(Table_CMAP));
  177. cmap.TableVersion = stream.ReadUInt16();
  178. cmap.NumSubTables = stream.ReadUInt16();
  179. // int subtables_count = cmap.NumSubTables;
  180. // IntPtr submap_ptr = Increment(cmap_ptr, Marshal.SizeOf(cmap));
  181. // IntPtr payload_ptr;
  182. Table_SUBMAP submap;
  183. long record_position = stream.Position;
  184. for (int j = 0; j < cmap.NumSubTables; j++)
  185. {
  186. // submap = (Table_SUBMAP)Marshal.PtrToStructure(submap_ptr, typeof(Table_SUBMAP));
  187. // submap_ptr = Increment(submap_ptr, Marshal.SizeOf(submap));
  188. stream.Seek(record_position, System.IO.SeekOrigin.Begin);
  189. submap.Platform = stream.ReadUInt16(); // SwapUInt16(submap.Platform);
  190. submap.EncodingID = stream.ReadUInt16(); // SwapUInt16(submap.EncodingID);
  191. submap.TableOffset = stream.ReadUInt32(); //SwapUInt32(submap.TableOffset);
  192. record_position = stream.Position;
  193. // --- Skip non microsft unicode charmaps
  194. // --- No no no! We will try to parse as much as possible
  195. // if ((submap.Platform != 3 || submap.EncodingID != 1)) continue;
  196. //IntPtr encode_ptr = Increment(cmap_ptr, (int)submap.TableOffset);
  197. stream.Seek(this.Offset + submap.TableOffset, System.IO.SeekOrigin.Begin);
  198. ushort format = stream.ReadUInt16(); // SwapUInt16(encode.Format);
  199. switch ((EncodingFormats)format)
  200. {
  201. case EncodingFormats.ByteEncoding:
  202. //throw new Exception("TO DO: ByteEncoding cmap format not implemented");
  203. continue;
  204. case EncodingFormats.HighByteMapping:
  205. //throw new Exception("TO DO: HighByteMapping cmap format not implemented");
  206. continue;
  207. case EncodingFormats.SegmentMapping:
  208. // payload_ptr = Increment(encode_ptr, Marshal.SizeOf(encode));
  209. SegmentMapping segment = new SegmentMapping(); // Marshal.PtrToStructure(payload_ptr, typeof(SegmentMapping));
  210. segment.Format = format;
  211. segment.Length = stream.ReadUInt16(); // SwapUInt16(encode.Length);
  212. segment.Version = stream.ReadUInt16(); // SwapUInt16(encode.Version);
  213. segment.segCountX2 = stream.ReadUInt16(); // SwapUInt16(segment.segCountX2); // 2 x segCount.
  214. segment.searchRange = stream.ReadUInt16(); // SwapUInt16(segment.searchRange); // 2 x (2**floor(log2(segCount)))
  215. segment.entrySelector = stream.ReadUInt16(); // SwapUInt16(segment.entrySelector); // log2(searchRange/2)
  216. segment.rangeShift = stream.ReadUInt16(); // SwapUInt16(segment.rangeShift); // 2 x segCount - searchRange
  217. segment_count = segment.segCountX2 / 2;
  218. // Euristic algoritmm for selection best representation. Not sure about it.
  219. if (startCount == null || startCount.Length < segment_count)
  220. {
  221. // payload_ptr = Increment(payload_ptr, Marshal.SizeOf(segment));
  222. endCount = LoadCmapSegment(stream, segment_count);
  223. // payload_ptr = Increment(payload_ptr, segment.segCountX2 + sizeof(ushort));
  224. ushort zeropad = stream.ReadUInt16();
  225. startCount = LoadCmapSegment(stream, segment_count);
  226. //payload_ptr = Increment(payload_ptr, segment.segCountX2);
  227. idDelta = LoadSignedCmapSegment(stream, segment_count);
  228. //payload_ptr = Increment(payload_ptr, segment.segCountX2);
  229. idRangeOffset = LoadCmapSegment(stream, segment_count);
  230. uint index_array_size = (8 + 4 * (uint)segment_count) * 2;
  231. index_array_size = (segment.Length - index_array_size) / 2;
  232. //payload_ptr = Increment(payload_ptr, segment.segCountX2);
  233. //////// int checksize = encode.Length - 3 * segment_count * 2;
  234. glyphIndexArray = LoadCmapSegment(stream, (int)index_array_size);
  235. #if false
  236. string[] debug = new string[segment_count];
  237. for (int z = 0; z < segment_count; z++)
  238. {
  239. debug[z] = ""+(char)startCount[z]+" - "+(char)endCount[z] +" = " + idDelta[z].ToString() + " & " + idRangeOffset[z].ToString();
  240. }
  241. #endif
  242. }
  243. continue;
  244. case EncodingFormats.TrimmedTable:
  245. Format6 format6 = new Format6(); // Marshal.PtrToStructure(encode_ptr, typeof(Format6));
  246. format6.format = format;
  247. format6.length = stream.ReadUInt16(); // SwapUInt16(format6.length);
  248. format6.language = stream.ReadUInt16(); //SwapUInt16(format6.language);
  249. format6.startCharCode = stream.ReadUInt16(); // SwapUInt16(format6.startCharCode);
  250. format6.numChars = stream.ReadUInt16(); // SwapUInt16(format6.numChars);
  251. trimmed = new ushort[format6.numChars];
  252. for (int i = 0; i < format6.numChars; ++i)
  253. {
  254. trimmed[i] = stream.ReadUInt16();
  255. }
  256. trimmedStat = format6.startCharCode;
  257. continue;
  258. case EncodingFormats.TrimmedArray:
  259. Format10 format10 = new Format10(); // Marshal.PtrToStructure(encode_ptr, typeof(Format10));
  260. format10.format = format;
  261. format10.reserved = stream.ReadUInt16();
  262. format10.length = stream.ReadUInt32(); // SwapUInt32(format10.length);
  263. format10.language = stream.ReadUInt32(); // SwapUInt32(format10.language);
  264. format10.startCharCode = stream.ReadUInt32(); // SwapUInt32(format10.startCharCode);
  265. format10.numChars = SwapUInt32(format10.numChars);
  266. trimmed = new ushort[format10.numChars];
  267. // payload_ptr = Increment(encode_ptr, Marshal.SizeOf(format10));
  268. for (int i = 0; i < format10.numChars; ++i)
  269. {
  270. trimmed[i] = stream.ReadUInt16();
  271. }
  272. trimmedStat = format10.startCharCode;
  273. continue;
  274. case EncodingFormats.SegmentedCoverage:
  275. Format12 format12 = new Format12(); // Marshal.PtrToStructure(encode_ptr, typeof(Format12));
  276. format12.format = format;
  277. format12.reserved = stream.ReadUInt16();
  278. format12.length = stream.ReadUInt32(); // SwapUInt32(format12.length);
  279. format12.language = stream.ReadUInt32(); // SwapUInt32(format12.language);
  280. format12.numGroups = stream.ReadUInt32();
  281. mapGroup = new SequentialMapGroup[format12.numGroups];
  282. // payload_ptr = Increment(encode_ptr, Marshal.SizeOf(format12));
  283. for (int i = 0; i < format12.numGroups; ++i)
  284. {
  285. // mapGroup[i] = (SequentialMapGroup)Marshal.PtrToStructure(payload_ptr, typeof(SequentialMapGroup));
  286. mapGroup[i].startCharCode = stream.ReadUInt32(); // SwapUInt32(mapGroup[i].startCharCode);
  287. mapGroup[i].searchRange = stream.ReadUInt32(); // SwapUInt32(mapGroup[i].searchRange);
  288. mapGroup[i].entrySelector = stream.ReadUInt32(); // SwapUInt32(mapGroup[i].entrySelector);
  289. // payload_ptr = Increment(payload_ptr, Marshal.SizeOf(mapGroup[0]));
  290. }
  291. continue;
  292. case EncodingFormats.ManyToOneRangeMapping:
  293. //throw new Exception("TO DO: ManyToOneRangeMapping cmap format not implemented");
  294. continue;
  295. case EncodingFormats.UnicodeVariationSequences:
  296. VariationSequences seq_header = new VariationSequences(); // Marshal.PtrToStructure(encode_ptr, typeof(VariationSequences));
  297. seq_header.Format = format;
  298. seq_header.Length = stream.ReadUInt32(); // SwapUInt32(seq_header.Length);
  299. seq_header.NumRecords = stream.ReadUInt32(); // SwapUInt32(seq_header.NumRecords);
  300. // Not parsed, but this table is optional
  301. continue;
  302. default:
  303. throw new Exception("cmap format not known");
  304. }
  305. }
  306. }
  307. internal ushort GetGlyphIndex(ushort ch)
  308. {
  309. ushort GlyphIDX = 0;
  310. if (segment_count != 0)
  311. {
  312. for (int i = 0; i < segment_count; i++)
  313. {
  314. if (endCount[i] >= ch)
  315. {
  316. if (startCount[i] <= ch)
  317. {
  318. if (idRangeOffset[i] == 0)
  319. {
  320. GlyphIDX = (ushort)((ch + idDelta[i]) % 65536);
  321. }
  322. else
  323. {
  324. int j = (ushort)(idRangeOffset[i] / 2 + (ch - startCount[i]) - (segment_count - i));
  325. GlyphIDX = this.glyphIndexArray[j];
  326. }
  327. }
  328. return GlyphIDX;
  329. }
  330. }
  331. }
  332. if (mapGroup != null && mapGroup.Length != 0)
  333. {
  334. for (int i = 0; i < mapGroup.Length; ++i)
  335. {
  336. if (ch >= mapGroup[i].startCharCode && ch <= mapGroup[i].searchRange)
  337. {
  338. GlyphIDX = (ushort)((uint)ch - mapGroup[i].startCharCode + mapGroup[i].entrySelector);
  339. return GlyphIDX;
  340. }
  341. }
  342. }
  343. if (trimmed != null && trimmed.Length != 0)
  344. {
  345. uint idx;
  346. if (ch > trimmedStat)
  347. {
  348. idx = (uint)(ch - trimmedStat);
  349. if (idx < trimmed.Length)
  350. GlyphIDX = trimmed[idx];
  351. }
  352. }
  353. return GlyphIDX;
  354. }
  355. internal ushort GetGlyph32Index(uint ch)
  356. {
  357. ushort GlyphIDX = 0;
  358. if (mapGroup != null && mapGroup.Length != 0)
  359. {
  360. for (int i = 0; i < mapGroup.Length; ++i)
  361. {
  362. if (ch >= mapGroup[i].startCharCode && ch <= mapGroup[i].searchRange)
  363. {
  364. GlyphIDX = (ushort)((uint)ch - mapGroup[i].startCharCode + mapGroup[i].entrySelector);
  365. return GlyphIDX;
  366. }
  367. }
  368. }
  369. return GlyphIDX;
  370. }
  371. public CmapTableClass(TrueTypeTable src) : base(src) { }
  372. }
  373. }