123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 |
- using System;
- using System.Runtime.InteropServices;
- namespace FastReport.Fonts
- {
- /////////////////////////////////////////////////////////////////////////////////////////////////
- // Cmap table
- /////////////////////////////////////////////////////////////////////////////////////////////////
- class CmapTableClass : TrueTypeTable
- {
- #region "Type definition"
- public enum EncodingFormats
- {
- ByteEncoding = 0,
- HighByteMapping = 2,
- SegmentMapping = 4,
- TrimmedTable = 6,
- TrimmedArray = 10,
- SegmentedCoverage = 12,
- ManyToOneRangeMapping = 13,
- UnicodeVariationSequences = 14
- }
- [StructLayout(LayoutKind.Explicit, Pack = 1)]
- public struct Table_CMAP
- {
- [FieldOffset(0)]
- public ushort TableVersion;
- [FieldOffset(2)]
- public ushort NumSubTables;
- }
- [StructLayout(LayoutKind.Explicit, Pack = 1)]
- public struct Table_SUBMAP
- {
- [FieldOffset(0)]
- public ushort Platform;
- [FieldOffset(2)]
- public ushort EncodingID;
- [FieldOffset(4)]
- public uint TableOffset;
- }
- [StructLayout(LayoutKind.Explicit, Pack = 1)]
- public struct SegmentMapping
- {
- [FieldOffset(0)]
- public ushort Format;
- [FieldOffset(2)]
- public ushort Length;
- [FieldOffset(4)]
- public ushort Version;
- [FieldOffset(6)]
- public ushort segCountX2; // 2 x segCount.
- [FieldOffset(8)]
- public ushort searchRange; // 2 x (2**floor(log2(segCount)))
- [FieldOffset(10)]
- public ushort entrySelector; // log2(searchRange/2)
- [FieldOffset(12)]
- public ushort rangeShift; // 2 x segCount - searchRange
- }
- [StructLayout(LayoutKind.Explicit, Pack = 1)]
- public struct SequentialMapGroup
- {
- [FieldOffset(0)]
- public uint startCharCode;
- [FieldOffset(4)]
- public uint searchRange;
- [FieldOffset(8)]
- public uint entrySelector;
- }
- [StructLayout(LayoutKind.Explicit, Pack = 1)]
- public struct Format6 // Trimmed table
- {
- [FieldOffset(0)]
- public ushort format;
- [FieldOffset(4)]
- public ushort length;
- [FieldOffset(6)]
- public ushort language;
- [FieldOffset(8)]
- public ushort startCharCode;
- [FieldOffset(10)]
- public ushort numChars;
- }
- [StructLayout(LayoutKind.Explicit, Pack = 1)]
- public struct Format8
- {
- }
- [StructLayout(LayoutKind.Explicit, Pack = 1)]
- public struct Format10 // Trimmed array
- {
- [FieldOffset(0)]
- public ushort format;
- [FieldOffset(2)]
- public ushort reserved;
- [FieldOffset(4)]
- public uint length;
- [FieldOffset(8)]
- public uint language;
- [FieldOffset(12)]
- public uint startCharCode;
- [FieldOffset(16)]
- public uint numChars;
- }
- [StructLayout(LayoutKind.Explicit, Pack = 1)]
- public struct Format12
- {
- [FieldOffset(0)]
- public ushort format; // Subtable format; set to 12.
- [FieldOffset(2)]
- public ushort reserved; // Reserved; set to 0
- [FieldOffset(4)]
- public uint length; // Byte length of this subtable (including the header)
- [FieldOffset(8)]
- public uint language;
- [FieldOffset(12)]
- public uint numGroups; // Number of groupings which follow
- }
- [StructLayout(LayoutKind.Explicit, Pack = 1)]
- public struct VariationSequences
- {
- [FieldOffset(0)]
- public ushort Format;
- [FieldOffset(2)]
- public uint Length;
- [FieldOffset(6)]
- public uint NumRecords;
- }
- [StructLayout(LayoutKind.Explicit, Pack = 1)]
- public struct VariationSequenceRecord
- {
- [FieldOffset(0)]
- public byte _b0; //
- [FieldOffset(1)]
- public byte _b1; //
- [FieldOffset(2)]
- public byte _b2; //
- [FieldOffset(3)]
- public uint defaultUVSOffset; //
- [FieldOffset(7)]
- public uint nonDefaultUVSOffset; //
- // Not shure that followin property is allowed in packed structures
- public uint VariantSelector { get { return (uint)(_b0 | (_b1 << 8) | (_b2 << 16)); } }
- }
- #endregion
- // Format 4: Segment mapping to delta values
- int segment_count;
- ushort[] endCount;
- ushort[] startCount;
- short[] idDelta;
- ushort[] idRangeOffset;
- ushort[] glyphIndexArray;
- // Format 6 and 10
- uint trimmedStat;
- ushort[] trimmed;
- // Format 12: Segmented coverage
- SequentialMapGroup[] mapGroup;
- private ushort[] LoadCmapSegment(FontStream stream, int segment_count)
- {
- ushort[] result = new ushort[segment_count];
- for (int i = 0; i < segment_count; i++)
- result[i] = stream.ReadUInt16();
- return result;
- }
- private short[] LoadSignedCmapSegment(FontStream stream, int segment_count)
- {
- short[] result = new short[segment_count];
- for (int i = 0; i < segment_count; i++)
- {
- result[i] = stream.ReadInt16();
- }
- return result;
- }
- internal void LoadCmapTable(FontStream stream)
- {
- // IntPtr subtable_ptr;
- // IntPtr cmap_ptr = Increment(font, (int)this.Offset);
- stream.Seek(this.Offset, System.IO.SeekOrigin.Begin);
- Table_CMAP cmap = new Table_CMAP(); // Marshal.PtrToStructure(cmap_ptr, typeof(Table_CMAP));
- cmap.TableVersion = stream.ReadUInt16();
- cmap.NumSubTables = stream.ReadUInt16();
- // int subtables_count = cmap.NumSubTables;
- // IntPtr submap_ptr = Increment(cmap_ptr, Marshal.SizeOf(cmap));
- // IntPtr payload_ptr;
- Table_SUBMAP submap;
- long record_position = stream.Position;
- for (int j = 0; j < cmap.NumSubTables; j++)
- {
- // submap = (Table_SUBMAP)Marshal.PtrToStructure(submap_ptr, typeof(Table_SUBMAP));
- // submap_ptr = Increment(submap_ptr, Marshal.SizeOf(submap));
- stream.Seek(record_position, System.IO.SeekOrigin.Begin);
- submap.Platform = stream.ReadUInt16(); // SwapUInt16(submap.Platform);
- submap.EncodingID = stream.ReadUInt16(); // SwapUInt16(submap.EncodingID);
- submap.TableOffset = stream.ReadUInt32(); //SwapUInt32(submap.TableOffset);
- record_position = stream.Position;
- // --- Skip non microsft unicode charmaps
- // --- No no no! We will try to parse as much as possible
- // if ((submap.Platform != 3 || submap.EncodingID != 1)) continue;
- //IntPtr encode_ptr = Increment(cmap_ptr, (int)submap.TableOffset);
- stream.Seek(this.Offset + submap.TableOffset, System.IO.SeekOrigin.Begin);
- ushort format = stream.ReadUInt16(); // SwapUInt16(encode.Format);
- switch ((EncodingFormats)format)
- {
- case EncodingFormats.ByteEncoding:
- //throw new Exception("TO DO: ByteEncoding cmap format not implemented");
- continue;
- case EncodingFormats.HighByteMapping:
- //throw new Exception("TO DO: HighByteMapping cmap format not implemented");
- continue;
- case EncodingFormats.SegmentMapping:
- // payload_ptr = Increment(encode_ptr, Marshal.SizeOf(encode));
- SegmentMapping segment = new SegmentMapping(); // Marshal.PtrToStructure(payload_ptr, typeof(SegmentMapping));
- segment.Format = format;
- segment.Length = stream.ReadUInt16(); // SwapUInt16(encode.Length);
- segment.Version = stream.ReadUInt16(); // SwapUInt16(encode.Version);
- segment.segCountX2 = stream.ReadUInt16(); // SwapUInt16(segment.segCountX2); // 2 x segCount.
- segment.searchRange = stream.ReadUInt16(); // SwapUInt16(segment.searchRange); // 2 x (2**floor(log2(segCount)))
- segment.entrySelector = stream.ReadUInt16(); // SwapUInt16(segment.entrySelector); // log2(searchRange/2)
- segment.rangeShift = stream.ReadUInt16(); // SwapUInt16(segment.rangeShift); // 2 x segCount - searchRange
- segment_count = segment.segCountX2 / 2;
- // Euristic algoritmm for selection best representation. Not sure about it.
- if (startCount == null || startCount.Length < segment_count)
- {
- // payload_ptr = Increment(payload_ptr, Marshal.SizeOf(segment));
- endCount = LoadCmapSegment(stream, segment_count);
- // payload_ptr = Increment(payload_ptr, segment.segCountX2 + sizeof(ushort));
- ushort zeropad = stream.ReadUInt16();
- startCount = LoadCmapSegment(stream, segment_count);
- //payload_ptr = Increment(payload_ptr, segment.segCountX2);
- idDelta = LoadSignedCmapSegment(stream, segment_count);
- //payload_ptr = Increment(payload_ptr, segment.segCountX2);
- idRangeOffset = LoadCmapSegment(stream, segment_count);
- uint index_array_size = (8 + 4 * (uint)segment_count) * 2;
- index_array_size = (segment.Length - index_array_size) / 2;
- //payload_ptr = Increment(payload_ptr, segment.segCountX2);
- //////// int checksize = encode.Length - 3 * segment_count * 2;
- glyphIndexArray = LoadCmapSegment(stream, (int)index_array_size);
- #if false
- string[] debug = new string[segment_count];
- for (int z = 0; z < segment_count; z++)
- {
- debug[z] = ""+(char)startCount[z]+" - "+(char)endCount[z] +" = " + idDelta[z].ToString() + " & " + idRangeOffset[z].ToString();
- }
- #endif
- }
- continue;
- case EncodingFormats.TrimmedTable:
- Format6 format6 = new Format6(); // Marshal.PtrToStructure(encode_ptr, typeof(Format6));
- format6.format = format;
- format6.length = stream.ReadUInt16(); // SwapUInt16(format6.length);
- format6.language = stream.ReadUInt16(); //SwapUInt16(format6.language);
- format6.startCharCode = stream.ReadUInt16(); // SwapUInt16(format6.startCharCode);
- format6.numChars = stream.ReadUInt16(); // SwapUInt16(format6.numChars);
- trimmed = new ushort[format6.numChars];
- for (int i = 0; i < format6.numChars; ++i)
- {
- trimmed[i] = stream.ReadUInt16();
- }
- trimmedStat = format6.startCharCode;
- continue;
- case EncodingFormats.TrimmedArray:
- Format10 format10 = new Format10(); // Marshal.PtrToStructure(encode_ptr, typeof(Format10));
- format10.format = format;
- format10.reserved = stream.ReadUInt16();
- format10.length = stream.ReadUInt32(); // SwapUInt32(format10.length);
- format10.language = stream.ReadUInt32(); // SwapUInt32(format10.language);
- format10.startCharCode = stream.ReadUInt32(); // SwapUInt32(format10.startCharCode);
- format10.numChars = SwapUInt32(format10.numChars);
- trimmed = new ushort[format10.numChars];
- // payload_ptr = Increment(encode_ptr, Marshal.SizeOf(format10));
- for (int i = 0; i < format10.numChars; ++i)
- {
- trimmed[i] = stream.ReadUInt16();
- }
- trimmedStat = format10.startCharCode;
- continue;
- case EncodingFormats.SegmentedCoverage:
- Format12 format12 = new Format12(); // Marshal.PtrToStructure(encode_ptr, typeof(Format12));
- format12.format = format;
- format12.reserved = stream.ReadUInt16();
- format12.length = stream.ReadUInt32(); // SwapUInt32(format12.length);
- format12.language = stream.ReadUInt32(); // SwapUInt32(format12.language);
- format12.numGroups = stream.ReadUInt32();
- mapGroup = new SequentialMapGroup[format12.numGroups];
- // payload_ptr = Increment(encode_ptr, Marshal.SizeOf(format12));
- for (int i = 0; i < format12.numGroups; ++i)
- {
- // mapGroup[i] = (SequentialMapGroup)Marshal.PtrToStructure(payload_ptr, typeof(SequentialMapGroup));
- mapGroup[i].startCharCode = stream.ReadUInt32(); // SwapUInt32(mapGroup[i].startCharCode);
- mapGroup[i].searchRange = stream.ReadUInt32(); // SwapUInt32(mapGroup[i].searchRange);
- mapGroup[i].entrySelector = stream.ReadUInt32(); // SwapUInt32(mapGroup[i].entrySelector);
- // payload_ptr = Increment(payload_ptr, Marshal.SizeOf(mapGroup[0]));
- }
- continue;
- case EncodingFormats.ManyToOneRangeMapping:
- //throw new Exception("TO DO: ManyToOneRangeMapping cmap format not implemented");
- continue;
- case EncodingFormats.UnicodeVariationSequences:
- VariationSequences seq_header = new VariationSequences(); // Marshal.PtrToStructure(encode_ptr, typeof(VariationSequences));
- seq_header.Format = format;
- seq_header.Length = stream.ReadUInt32(); // SwapUInt32(seq_header.Length);
- seq_header.NumRecords = stream.ReadUInt32(); // SwapUInt32(seq_header.NumRecords);
- // Not parsed, but this table is optional
- continue;
- default:
- throw new Exception("cmap format not known");
- }
- }
- }
- internal ushort GetGlyphIndex(ushort ch)
- {
- ushort GlyphIDX = 0;
- if (segment_count != 0)
- {
- for (int i = 0; i < segment_count; i++)
- {
- if (endCount[i] >= ch)
- {
- if (startCount[i] <= ch)
- {
- if (idRangeOffset[i] == 0)
- {
- GlyphIDX = (ushort)((ch + idDelta[i]) % 65536);
- }
- else
- {
- int j = (ushort)(idRangeOffset[i] / 2 + (ch - startCount[i]) - (segment_count - i));
- GlyphIDX = this.glyphIndexArray[j];
- }
- }
- return GlyphIDX;
- }
- }
- }
- if (mapGroup != null && mapGroup.Length != 0)
- {
- for (int i = 0; i < mapGroup.Length; ++i)
- {
- if (ch >= mapGroup[i].startCharCode && ch <= mapGroup[i].searchRange)
- {
- GlyphIDX = (ushort)((uint)ch - mapGroup[i].startCharCode + mapGroup[i].entrySelector);
- return GlyphIDX;
- }
- }
- }
- if (trimmed != null && trimmed.Length != 0)
- {
- uint idx;
- if (ch > trimmedStat)
- {
- idx = (uint)(ch - trimmedStat);
- if (idx < trimmed.Length)
- GlyphIDX = trimmed[idx];
- }
- }
- return GlyphIDX;
- }
- internal ushort GetGlyph32Index(uint ch)
- {
- ushort GlyphIDX = 0;
- if (mapGroup != null && mapGroup.Length != 0)
- {
- for (int i = 0; i < mapGroup.Length; ++i)
- {
- if (ch >= mapGroup[i].startCharCode && ch <= mapGroup[i].searchRange)
- {
- GlyphIDX = (ushort)((uint)ch - mapGroup[i].startCharCode + mapGroup[i].entrySelector);
- return GlyphIDX;
- }
- }
- }
- return GlyphIDX;
- }
- public CmapTableClass(TrueTypeTable src) : base(src) { }
- }
- }
|