123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- using System;
- using System.Collections;
- using System.Runtime.InteropServices;
- #pragma warning disable CS3001, CS3002, CS3003, CS1591
- namespace FastReport.Fonts
- {
- /// <summary>
- /// Kerning table
- /// </summary>
- public class KerningTableClass : TrueTypeTable
- {
- #region "Type definition"
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct KerningTableHeader
- {
- public ushort Version;
- public ushort nTables;
- }
- internal class KerningSubtableClass : TTF_Helpers
- {
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct CommonKerningHeader
- {
- public ushort Version;
- public ushort Length;
- public ushort Coverage;
- }
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct FormatZero
- {
- public ushort nPairs; // This gives the number of kerning pairs in the table.
- public ushort searchRange; // The largest power of two less than or equal to the value of nPairs, multiplied by the size in bytes of an entry in the table.
- public ushort entrySelector; // This is calculated as log2 of the largest power of two less than or equal to the value of nPairs. This value indicates how many iterations of the search loop will have to be made. (For example, in a list of eight items, there would have to be three iterations of the loop).
- public ushort rangeShift; // The value of nPairs minus the largest power of two less than or equal to nPairs, and then multiplied by the size in bytes of an entry in the table.
- }
- public CommonKerningHeader common_header;
- FormatZero format_zero;
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct Kern_Zero_Pair
- {
- public ushort left; /* index of left glyph in pair */
- public ushort right; /* index of right glyph in pair */
- public short value; /* kerning value */
- };
- public Kern_Zero_Pair[] kerning0_pairs;
- Hashtable zero_pairs = new Hashtable();
- public int Length { get { return common_header.Length; } }
- public short this[uint hash_value]
- {
- get
- {
- return (short)(zero_pairs.Contains(hash_value) ? zero_pairs[hash_value] : (short)0);
- }
- }
- public KerningSubtableClass(FontStream stream)
- {
- common_header = new CommonKerningHeader(); // Marshal.PtrToStructure(kerning_table_ptr, typeof(CommonKerningHeader));
- common_header.Version = stream.ReadUInt16();
- common_header.Length = stream.ReadUInt16(); //// SwapUInt16(common_header.Length);
- common_header.Coverage = stream.ReadUInt16(); // SwapUInt16(common_header.Coverage);
- // kerning_table_ptr = Increment(kerning_table_ptr, Marshal.SizeOf(common_header));
- if (common_header.Coverage == 1)
- {
- format_zero = new FormatZero(); // Marshal.PtrToStructure(kerning_table_ptr, typeof(FormatZero));
- format_zero.nPairs = stream.ReadUInt16(); //SwapUInt16(format_zero.nPairs);
- format_zero.searchRange = stream.ReadUInt16(); // SwapUInt16(format_zero.searchRange);
- format_zero.entrySelector = stream.ReadUInt16(); // SwapUInt16(format_zero.entrySelector);
- format_zero.rangeShift = stream.ReadUInt16(); // SwapUInt16(format_zero.rangeShift);
- // kerning_table_ptr = Increment(kerning_table_ptr, Marshal.SizeOf(format_zero));
- kerning0_pairs = new Kern_Zero_Pair[format_zero.nPairs];
- for (int i = 0; i < format_zero.nPairs; i++)
- {
- // kerning0_pairs[i] = (Kern_Zero_Pair)Marshal.PtrToStructure(kerning_table_ptr, typeof(Kern_Zero_Pair));
- kerning0_pairs[i].left = stream.ReadUInt16(); // SwapUInt16(kerning0_pairs[i].left);
- kerning0_pairs[i].right = stream.ReadUInt16(); // SwapUInt16(kerning0_pairs[i].right);
- kerning0_pairs[i].value = stream.ReadInt16(); // SwapInt16(kerning0_pairs[i].value);
- // kerning_table_ptr = Increment(kerning_table_ptr, Marshal.SizeOf(typeof(Kern_Zero_Pair)));
- }
- }
- else if (common_header.Coverage == 0x8000)
- {
- // new Apple-dialect of kerning table
- }
- else if (common_header.Coverage == 0x0000)
- {
- // classic Apple-dialect of kerning table
- }
- else
- {
- throw new Exception("An unknown dialect of kerning table");
- }
- }
- }
- public short this[uint hash_value]
- {
- get
- {
- KerningSubtableClass subtable = kerning_subtables_collection[0] as KerningSubtableClass;
- return subtable[hash_value];
- }
- }
- #endregion
- public KerningTableHeader kerning_table_header;
- private ArrayList kerning_subtables_collection;
- internal KerningSubtableClass format_zero_kern = null;
- internal override void Load(FontStream stream)
- {
- stream.Seek(this.Offset, System.IO.SeekOrigin.Begin);
- kerning_table_header.Version = stream.ReadUInt16();
- kerning_table_header.nTables = stream.ReadUInt16();
- for (int i = 0; i < kerning_table_header.nTables; i++)
- {
- KerningSubtableClass subtable = new KerningSubtableClass(stream);
- if (subtable.common_header.Coverage == 1)
- {
- this.format_zero_kern = subtable;
- }
- kerning_subtables_collection.Add(subtable);
- }
- }
- internal short TryKerning(ushort left, ushort right)
- {
- if (format_zero_kern == null)
- return 0;
- long target_idx = (((long)left) << 16) + right;
- short min, max, middle;
- short new_min = 0;
- short new_max = (short)(this.format_zero_kern.kerning0_pairs.Length - 1);
- short fix_kerning = 0;
- do
- {
- min = new_min;
- max = new_max;
- middle = (short)(max - ((max - min) >> 1));
- if (this.format_zero_kern.kerning0_pairs.Length == 0)
- break;
- long current_idx = (this.format_zero_kern.kerning0_pairs[middle].left << 16) +
- this.format_zero_kern.kerning0_pairs[middle].right;
- if (target_idx == current_idx)
- {
- fix_kerning += this.format_zero_kern.kerning0_pairs[middle].value;
- break;
- }
- else if (target_idx < current_idx)
- {
- if (middle == min)
- break;
- new_max = (short)(middle - 1);
- }
- else
- {
- if (middle == max)
- break;
- new_min = (short)(middle + 1);
- }
- } while (min < max);
- return fix_kerning;
- }
- public KerningTableClass(TrueTypeTable src) : base(src)
- {
- kerning_subtables_collection = new ArrayList();
- }
- }
- }
- #pragma warning restore
|