public static LookupType3Format1SubTable Load(BigEndianBinaryReader reader, long offset, LookupFlags lookupFlags) { // Cursive Attachment Positioning Format1. // +--------------------+---------------------------------+------------------------------------------------------+ // | Type | Name | Description | // +====================+=================================+======================================================+ // | uint16 | posFormat | Format identifier: format = 1 | // +--------------------+---------------------------------+------------------------------------------------------+ // | Offset16 | coverageOffset | Offset to Coverage table, | // | | | from beginning of CursivePos subtable. | // +--------------------+---------------------------------+------------------------------------------------------+ // | uint16 | entryExitCount | Number of EntryExit records. | // +--------------------+---------------------------------+------------------------------------------------------+ // | EntryExitRecord | entryExitRecord[entryExitCount] | Array of EntryExit records, in Coverage index order. | // +--------------------+---------------------------------+------------------------------------------------------+ ushort coverageOffset = reader.ReadOffset16(); ushort entryExitCount = reader.ReadUInt16(); var entryExitRecords = new EntryExitRecord[entryExitCount]; for (int i = 0; i < entryExitCount; i++) { entryExitRecords[i] = new EntryExitRecord(reader, offset); } var entryExitAnchors = new EntryExitAnchors[entryExitCount]; for (int i = 0; i < entryExitCount; i++) { entryExitAnchors[i] = new EntryExitAnchors(reader, offset, entryExitRecords[i]); } var coverageTable = CoverageTable.Load(reader, offset + coverageOffset); return(new LookupType3Format1SubTable(coverageTable, entryExitAnchors, lookupFlags)); }
public override bool TryUpdatePosition( FontMetrics fontMetrics, GPosTable table, GlyphPositioningCollection collection, Tag feature, ushort index, int count) { if (count <= 1) { return(false); } // Implements Cursive Attachment Positioning Subtable: // https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#lookup-type-3-cursive-attachment-positioning-subtable ushort glyphId = collection[index][0]; if (glyphId == 0) { return(false); } ushort nextIndex = (ushort)(index + 1); ushort nextGlyphId = collection[nextIndex][0]; if (nextGlyphId == 0) { return(false); } int coverageNext = this.coverageTable.CoverageIndexOf(nextGlyphId); if (coverageNext < 0) { return(false); } EntryExitAnchors nextRecord = this.entryExitAnchors[coverageNext]; AnchorTable? entry = nextRecord.EntryAnchor; if (entry is null) { return(false); } int coverage = this.coverageTable.CoverageIndexOf(glyphId); if (coverage < 0) { return(false); } EntryExitAnchors curRecord = this.entryExitAnchors[coverage]; AnchorTable? exit = curRecord.ExitAnchor; if (exit is null) { return(false); } GlyphShapingData current = collection.GetGlyphShapingData(index); GlyphShapingData next = collection.GetGlyphShapingData(nextIndex); // TODO: Vertical. if (current.Direction == TextDirection.LeftToRight) { current.Bounds.Width = exit.XCoordinate + current.Bounds.X; int delta = entry.XCoordinate + next.Bounds.X; next.Bounds.Width -= delta; next.Bounds.X -= delta; } else { int delta = exit.XCoordinate + current.Bounds.X; current.Bounds.Width -= delta; current.Bounds.X -= delta; next.Bounds.Width = entry.XCoordinate + next.Bounds.X; } int child = index; int parent = nextIndex; int xOffset = entry.XCoordinate - exit.XCoordinate; int yOffset = entry.YCoordinate - exit.YCoordinate; if (this.LookupFlags.HasFlag(LookupFlags.RightToLeft)) { int temp = child; child = parent; parent = temp; xOffset = -xOffset; yOffset = -yOffset; } // If child was already connected to someone else, walk through its old // chain and reverse the link direction, such that the whole tree of its // previous connection now attaches to new parent.Watch out for case // where new parent is on the path from old chain... bool horizontal = !collection.IsVerticalLayoutMode; ReverseCursiveMinorOffset(collection, index, child, horizontal, parent); GlyphShapingData c = collection.GetGlyphShapingData(child); c.CursiveAttachment = parent - child; if (horizontal) { c.Bounds.Y = yOffset; } else { c.Bounds.X = xOffset; } // If parent was attached to child, separate them. GlyphShapingData p = collection.GetGlyphShapingData(parent); if (p.CursiveAttachment == -c.CursiveAttachment) { p.CursiveAttachment = 0; } return(true); }