示例#1
0
        public static CMapTable Load(BinaryReader reader)
        {
            ushort version   = reader.ReadUInt16();
            ushort numTables = reader.ReadUInt16();

            var encodings = new EncodingRecord[numTables];

            for (int i = 0; i < numTables; i++)
            {
                encodings[i] = EncodingRecord.Read(reader);
            }

            // foreach encoding we move forward looking for th subtables
            var tables = new List <CMapSubTable>(numTables);

            foreach (IGrouping <uint, EncodingRecord> encoding in encodings.Where(x => x.PlatformID == PlatformIDs.Windows).GroupBy(x => x.Offset))
            {
                reader.Seek(encoding.Key, System.IO.SeekOrigin.Begin);

                ushort subTypeTableFormat = reader.ReadUInt16();

                switch (subTypeTableFormat)
                {
                case 0:
                    tables.AddRange(Format0SubTable.Load(encoding, reader));
                    break;

                case 4:
                    tables.AddRange(Format4SubTable.Load(encoding, reader));
                    break;
                }
            }

            return(new CMapTable(tables.ToArray()));
        }
示例#2
0
        [InlineData(500, 0)] //not in range
        public void GetCharcter(int src, int expected)
        {
            // segCountX2:    8
            // searchRange:   8
            // entrySelector: 4
            // rangeShift:    0
            // endCode:       20  90  480  0xffff
            // reservedPad:   0
            // startCode:     10  30  153  0xffff
            // dDelta:        -9  -18 -27  1
            // idRangeOffset: 0   0   0    0
            ushort[] glyphs = Enumerable.Range(0, expected).Select(x => (ushort)x).ToArray();

            Format4SubTable table = new Format4SubTable(
                0,
                PlatformIDs.Windows,
                0,
                new[]
            {
                new Format4SubTable.Segment(0, 20, 10, -9, 0),
                new Format4SubTable.Segment(1, 90, 30, -18, 0),
                new Format4SubTable.Segment(2, 480, 153, -27, 0),
            },
                glyphs);
            ushort id = table.GetGlyphId((char)src);

            Assert.Equal(expected, id);
        }
示例#3
0
        public void LoadFormat4()
        {
            BinaryWriter writer = new BinaryWriter();

            //int subtableCount = 1;
            writer.WriteCMapSubTable(new SixLabors.Fonts.Tables.General.CMap.Format4SubTable(0, PlatformIDs.Windows, 2,
                                                                                             new[]
            {
                new Format4SubTable.Segment(0, 1, 2, 3, 4)
            }, new ushort[] {
                1, 2, 3, 4, 5, 6, 7, 8
            }));

            BinaryReader reader = writer.GetReader();
            ushort       format = reader.ReadUInt16(); // read format before we pass along as thats whet the cmap table does

            Assert.Equal(4, format);
            Format4SubTable table = Format4SubTable.Load(new[] { new EncodingRecord(PlatformIDs.Windows, 2, 0) }, reader).Single();

            Assert.Equal(0, table.Language);
            Assert.Equal(PlatformIDs.Windows, table.Platform);
            Assert.Equal(2, table.Encoding);
            Assert.Equal(new ushort[] {
                1, 2, 3, 4, 5, 6, 7, 8
            }, table.GlyphIds);

            Assert.Equal(1, table.Segments.Length);
            Format4SubTable.Segment seg = table.Segments[0];
            Assert.Equal(0, seg.Index);
            Assert.Equal(1, seg.End);
            Assert.Equal(2, seg.Start);
            Assert.Equal(3, seg.Delta);
            Assert.Equal(4, seg.Offset);
        }
示例#4
0
        public void Format4SubTableWithSegmentsHasOffByOneWhenOverflowing()
        {
            Segment[] segments = new[]
            {
                new Segment(
                    0,
                    ushort.MaxValue, // end
                    ushort.MinValue, // start of range
                    short.MaxValue,  // delta
                    0)               // zero to force correctly tested codepath
            };
            var tbl = new Format4SubTable(
                0,
                WellKnownIds.PlatformIDs.Windows,
                0,
                segments,
                null);

            const int delta = short.MaxValue + 2; // extra 2 to handle the difference between ushort and short when offsettings

            const int codePoint = delta + 5;

            Assert.True(tbl.TryGetGlyphId(new CodePoint(codePoint), out ushort gid));

            Assert.Equal(5, gid);
        }
示例#5
0
        public static void WriteCMapSubTable(this BinaryWriter writer, Format4SubTable subtable)
        {
            if (subtable == null)
            {
                return;
            }

            // 'cmap' Subtable Format 4:
            // Type   | Name                       | Description
            // -------|----------------------------|------------------------------------------------------------------------
            // uint16 | format                     | Format number is set to 4.
            // uint16 | length                     | This is the length in bytes of the subtable.
            // uint16 | language                   | Please see “Note on the language field in 'cmap' subtables“ in this document.
            // uint16 | segCountX2                 | 2 x segCount.
            // uint16 | searchRange                | 2 x (2**floor(log2(segCount)))
            // uint16 | entrySelector              | log2(searchRange/2)
            // uint16 | rangeShift                 | 2 x segCount - searchRange
            // uint16 | endCount[segCount]         | End characterCode for each segment, last=0xFFFF.
            // uint16 | reservedPad                | Set to 0.
            // uint16 | startCount[segCount]       | Start character code for each segment.
            // int16  | idDelta[segCount]           | Delta for all character codes in segment.
            // uint16 | idRangeOffset[segCount]    | Offsets into glyphIdArray or 0
            // uint16 | glyphIdArray[ ]            | Glyph index array (arbitrary length)
            writer.WriteUInt16(4);
            writer.WriteUInt16((ushort)subtable.DataLength());
            writer.WriteUInt16(subtable.Language);
            int segCount = subtable.Segments.Length;

            writer.WriteUInt16((ushort)(subtable.Segments.Length * 2));
            double searchRange = Math.Pow(2, Math.Floor(Math.Log(segCount, 2)));

            writer.WriteUInt16((ushort)searchRange);
            double entrySelector = Math.Log(searchRange / 2, 2);

            writer.WriteUInt16((ushort)entrySelector);
            double rangeShift = (2 * segCount) - searchRange;

            writer.WriteUInt16((ushort)rangeShift);
            foreach (Format4SubTable.Segment seg in subtable.Segments)
            {
                writer.WriteUInt16(seg.End);
            }

            writer.WriteUInt16(0);
            foreach (Format4SubTable.Segment seg in subtable.Segments)
            {
                writer.WriteUInt16(seg.Start);
            }

            foreach (Format4SubTable.Segment seg in subtable.Segments)
            {
                writer.WriteInt16(seg.Delta);
            }

            foreach (Format4SubTable.Segment seg in subtable.Segments)
            {
                writer.WriteUInt16(seg.Offset);
            }

            foreach (ushort c in subtable.GlyphIds)
            {
                writer.WriteUInt16(c);
            }
        }