public override bool TryUpdatePosition( FontMetrics fontMetrics, GPosTable table, GlyphPositioningCollection collection, Tag feature, ushort index, int count) { if (count <= 1) { return(false); } ushort glyphId = collection[index][0]; if (glyphId == 0) { return(false); } int coverage = this.coverageTable.CoverageIndexOf(glyphId); if (coverage > -1) { PairSetTable pairSet = this.pairSets[coverage]; ushort glyphId2 = collection[index + 1][0]; if (glyphId2 == 0) { return(false); } if (pairSet.TryGetPairValueRecord(glyphId2, out PairValueRecord pairValueRecord)) { ValueRecord record1 = pairValueRecord.ValueRecord1; AdvancedTypographicUtils.ApplyPosition(collection, index, record1); ValueRecord record2 = pairValueRecord.ValueRecord2; AdvancedTypographicUtils.ApplyPosition(collection, (ushort)(index + 1), record2); return(true); } } return(false); }
public static LookupType2Format1SubTable Load(BigEndianBinaryReader reader, long offset, LookupFlags lookupFlags) { // Pair Adjustment Positioning Subtable format 1. // +-------------+------------------------------+------------------------------------------------+ // | Type | Name | Description | // +=============+==============================+================================================+ // | uint16 | posFormat | Format identifier: format = 1 | // +-------------+------------------------------+------------------------------------------------+ // | Offset16 | coverageOffset | Offset to Coverage table, from beginning of | // | | | PairPos subtable. | // +-------------+------------------------------+------------------------------------------------+ // | uint16 | valueFormat1 | Defines the types of data in valueRecord1 — | // | | | for the first glyph in the pair (may be zero). | // +-------------+------------------------------+------------------------------------------------+ // | uint16 | valueFormat2 | Defines the types of data in valueRecord2 — | // | | | for the second glyph in the pair (may be zero).| // +-------------+------------------------------+------------------------------------------------+ // | uint16 | pairSetCount | Number of PairSet tables | // +-------------+------------------------------+------------------------------------------------+ // | Offset16 | pairSetOffsets[pairSetCount] | Array of offsets to PairSet tables. | // | | | Offsets are from beginning of PairPos subtable,| // | | | ordered by Coverage Index. | // +-------------+------------------------------+------------------------------------------------+ ushort coverageOffset = reader.ReadOffset16(); ValueFormat valueFormat1 = reader.ReadUInt16 <ValueFormat>(); ValueFormat valueFormat2 = reader.ReadUInt16 <ValueFormat>(); ushort pairSetCount = reader.ReadUInt16(); using Buffer <ushort> pairSetOffsetsBuffer = new(pairSetCount); Span <ushort> pairSetOffsets = pairSetOffsetsBuffer.GetSpan(); reader.ReadUInt16Array(pairSetOffsets); var pairSets = new PairSetTable[pairSetCount]; for (int i = 0; i < pairSetCount; i++) { reader.Seek(offset + pairSetOffsets[i], SeekOrigin.Begin); pairSets[i] = PairSetTable.Load(reader, offset + pairSetOffsets[i], valueFormat1, valueFormat2); } var coverageTable = CoverageTable.Load(reader, offset + coverageOffset); return(new LookupType2Format1SubTable(coverageTable, pairSets, lookupFlags)); }
/// <summary> /// Lookup Type 2: Pair Adjustment Positioning Subtable /// </summary> /// <param name="reader"></param> void ReadLookupType2(BinaryReader reader) { //----------------------------------------------- // USHORT PosFormat Format identifier-format = 1 //Offset Coverage Offset to Coverage table-from beginning of PairPos subtable-only the first glyph in each pair //USHORT ValueFormat1 Defines the types of data in ValueRecord1-for the first glyph in the pair -may be zero (0) //USHORT ValueFormat2 Defines the types of data in ValueRecord2-for the second glyph in the pair -may be zero (0) //USHORT PairSetCount Number of PairSet tables //Offset PairSetOffset //[PairSetCount] Array of offsets to PairSet tables-from beginning of PairPos subtable-ordered by Coverage Index // PairSet table //Value Type Description //USHORT PairValueCount Number of PairValueRecords //struct PairValueRecord //[PairValueCount] Array of PairValueRecords-ordered by GlyphID of the second glyph //A PairValueRecord specifies the second glyph in a pair (SecondGlyph) and defines a ValueRecord for each glyph (Value1 and Value2). If ValueFormat1 is set to zero (0) in the PairPos subtable, ValueRecord1 will be empty; similarly, if ValueFormat2 is 0, Value2 will be empty. //Example 4 at the end of this chapter shows a PairPosFormat1 subtable that defines two cases of pair kerning. //PairValueRecord //Value Type Description //GlyphID SecondGlyph GlyphID of second glyph in the pair-first glyph is listed in the Coverage table //ValueRecord Value1 Positioning data for the first glyph in the pair //ValueRecord Value2 Positioning data for the second glyph in the pair //----------------------------------------------- // PairPosFormat2 subtable: Class pair adjustment //Value Type Description //USHORT PosFormat Format identifier-format = 2 //Offset Coverage Offset to Coverage table-from beginning of PairPos subtable-for the first glyph of the pair //USHORT ValueFormat1 ValueRecord definition-for the first glyph of the pair-may be zero (0) //USHORT ValueFormat2 ValueRecord definition-for the second glyph of the pair-may be zero (0) //Offset ClassDef1 Offset to ClassDef table-from beginning of PairPos subtable-for the first glyph of the pair //Offset ClassDef2 Offset to ClassDef table-from beginning of PairPos subtable-for the second glyph of the pair //USHORT Class1Count Number of classes in ClassDef1 table-includes Class0 //USHORT Class2Count Number of classes in ClassDef2 table-includes Class0 //struct Class1Record //[Class1Count] Array of Class1 records-ordered by Class1 //Each Class1Record contains an array of Class2Records (Class2Record), which also are ordered by class value. //One Class2Record must be declared for each class in the ClassDef2 table, including Class 0. //Class1Record //Value Type Description //struct Class2Record[Class2Count] Array of Class2 records-ordered by Class2 //A Class2Record consists of two ValueRecords, //one for the first glyph in a class pair (Value1) and one for the second glyph (Value2). //If the PairPos subtable has a value of zero (0) for ValueFormat1 or ValueFormat2, //the corresponding record (ValueRecord1 or ValueRecord2) will be empty. //Example 5 at the end of this chapter demonstrates pair kerning with glyph classes in a PairPosFormat2 subtable. //Class2Record //Value Type Description //ValueRecord Value1 Positioning for first glyph-empty if ValueFormat1 = 0 //ValueRecord Value2 Positioning for second glyph-empty if ValueFormat2 = 0 long thisLookupTablePos = reader.BaseStream.Position; int j = subTableOffsets.Length; for (int i = 0; i < j; ++i) { //move to read pos long subTableStartAt = lookupTablePos + subTableOffsets[i]; reader.BaseStream.Seek(subTableStartAt, SeekOrigin.Begin); //----------------------- ushort format = reader.ReadUInt16(); switch (format) { default: throw new NotSupportedException(); case 1: { short coverage = reader.ReadInt16(); ushort value1Format = reader.ReadUInt16(); ushort value2Format = reader.ReadUInt16(); ushort pairSetCount = reader.ReadUInt16(); short[] pairSetOffsetArray = Utils.ReadInt16Array(reader, pairSetCount); PairSetTable[] pairSetTables = new PairSetTable[pairSetCount]; for (int n = 0; n < pairSetCount; ++n) { //read each pair set table reader.BaseStream.Seek(thisLookupTablePos + pairSetOffsetArray[i], SeekOrigin.Begin); var pairSetTable = new PairSetTable(); pairSetTable.ReadFrom(reader, value1Format, value2Format); pairSetTables[n] = pairSetTable; } var subTable = new LkSubTableType2(pairSetTables); //coverage subTable.CoverageTable = CoverageTable.CreateFrom(reader, subTableStartAt + coverage); subTables.Add(subTable); } break; case 2: { short coverage = reader.ReadInt16(); ushort value1Format = reader.ReadUInt16(); ushort value2Format = reader.ReadUInt16(); short classDef1Offset = reader.ReadInt16(); short classDef2Offset = reader.ReadInt16(); ushort class1Count = reader.ReadUInt16(); ushort class2Count = reader.ReadUInt16(); throw new NotImplementedException(); } break; } } }
public LkSubTableType2(PairSetTable[] pairSetTables) { this.pairSetTables = pairSetTables; }