Esempio n. 1
0
            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));
            }
Esempio n. 2
0
            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);
            }