public override bool TryUpdatePosition(
                FontMetrics fontMetrics,
                GPosTable table,
                GlyphPositioningCollection collection,
                Tag feature,
                ushort index,
                int count)
            {
                // Mark-to-Base Attachment Positioning Subtable.
                // Implements: https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#lookup-type-4-mark-to-base-attachment-positioning-subtable
                ushort glyphId = collection[index][0];

                if (glyphId == 0)
                {
                    return(false);
                }

                int markIndex = this.markCoverage.CoverageIndexOf(glyphId);

                if (markIndex == -1)
                {
                    return(false);
                }

                // Search backward for a base glyph.
                int baseGlyphIndex = index;

                while (--baseGlyphIndex >= 0)
                {
                    GlyphShapingData data = collection.GetGlyphShapingData(baseGlyphIndex);
                    if (!AdvancedTypographicUtils.IsMarkGlyph(fontMetrics, data.GlyphIds[0], data) && !(data.LigatureComponent > 0))
                    {
                        break;
                    }
                }

                if (baseGlyphIndex < 0)
                {
                    return(false);
                }

                ushort baseGlyphId = collection[baseGlyphIndex][0];
                int    baseIndex   = this.baseCoverage.CoverageIndexOf(baseGlyphId);

                if (baseIndex < 0)
                {
                    return(false);
                }

                MarkRecord  markRecord = this.markArrayTable.MarkRecords[markIndex];
                AnchorTable baseAnchor = this.baseArrayTable.BaseRecords[baseIndex].BaseAnchorTables[markRecord.MarkClass];

                AdvancedTypographicUtils.ApplyAnchor(collection, index, baseAnchor, markRecord, baseGlyphIndex);

                return(true);
            }
Ejemplo n.º 2
0
            public override bool TryUpdatePosition(
                FontMetrics fontMetrics,
                GPosTable table,
                GlyphPositioningCollection collection,
                Tag feature,
                ushort index,
                int count)
            {
                // Mark-to-Ligature Attachment Positioning.
                // Implements: https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#lookup-type-5-mark-to-ligature-attachment-positioning-subtable
                ushort glyphId = collection[index][0];

                if (glyphId == 0)
                {
                    return(false);
                }

                int markIndex = this.markCoverage.CoverageIndexOf(glyphId);

                if (markIndex < 0)
                {
                    return(false);
                }

                // Search backward for a base glyph.
                int baseGlyphIndex = index;

                while (--baseGlyphIndex >= 0)
                {
                    GlyphShapingData data = collection.GetGlyphShapingData(baseGlyphIndex);
                    if (!AdvancedTypographicUtils.IsMarkGlyph(fontMetrics, data.GlyphIds[0], data))
                    {
                        break;
                    }
                }

                if (baseGlyphIndex < 0)
                {
                    return(false);
                }

                ushort baseGlyphId   = collection[baseGlyphIndex][0];
                int    ligatureIndex = this.ligatureCoverage.CoverageIndexOf(baseGlyphId);

                if (ligatureIndex < 0)
                {
                    return(false);
                }

                // We must now check whether the ligature ID of the current mark glyph
                // is identical to the ligature ID of the found ligature.
                // If yes, we can directly use the component index. If not, we attach the mark
                // glyph to the last component of the ligature.
                LigatureAttachTable ligatureAttach = this.ligatureArrayTable.LigatureAttachTables[ligatureIndex];
                GlyphShapingData    markGlyph      = collection.GetGlyphShapingData(index);
                GlyphShapingData    ligGlyph       = collection.GetGlyphShapingData(baseGlyphIndex);
                int compIndex = ligGlyph.LigatureId > 0 && ligGlyph.LigatureId == markGlyph.LigatureId && markGlyph.LigatureComponent > 0
                    ? Math.Min(markGlyph.LigatureComponent, ligGlyph.CodePointCount) - 1
                    : ligGlyph.CodePointCount - 1;

                MarkRecord  markRecord = this.markArrayTable.MarkRecords[markIndex];
                AnchorTable baseAnchor = ligatureAttach.ComponentRecords[compIndex].LigatureAnchorTables[markRecord.MarkClass];

                AdvancedTypographicUtils.ApplyAnchor(collection, index, baseAnchor, markRecord, baseGlyphIndex);

                return(true);
            }
            public override bool TryUpdatePosition(
                FontMetrics fontMetrics,
                GPosTable table,
                GlyphPositioningCollection collection,
                Tag feature,
                ushort index,
                int count)
            {
                // Mark to mark positioning.
                // Implements: https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#lookup-type-6-mark-to-mark-attachment-positioning-subtable
                ushort glyphId = collection[index][0];

                if (glyphId == 0)
                {
                    return(false);
                }

                int mark1Index = this.mark1Coverage.CoverageIndexOf(glyphId);

                if (mark1Index == -1)
                {
                    return(false);
                }

                // Get the previous mark to attach to.
                if (index < 1)
                {
                    return(false);
                }

                int              prevIdx     = index - 1;
                ushort           prevGlyphId = collection[prevIdx][0];
                GlyphShapingData prevGlyph   = collection.GetGlyphShapingData(prevIdx);

                if (!AdvancedTypographicUtils.IsMarkGlyph(fontMetrics, prevGlyphId, prevGlyph))
                {
                    return(false);
                }

                // The following logic was borrowed from Harfbuzz,
                // see: https://github.com/harfbuzz/harfbuzz/blob/3e635cf5e26e33d6210d3092256a49291752deec/src/hb-ot-layout-gpos-table.hh#L2525
                bool             good     = false;
                GlyphShapingData curGlyph = collection.GetGlyphShapingData(index);

                if (curGlyph.LigatureId == prevGlyph.LigatureId)
                {
                    if (curGlyph.LigatureId > 0)
                    {
                        // Marks belonging to the same base.
                        good = true;
                    }
                    else if (curGlyph.LigatureComponent == prevGlyph.LigatureComponent)
                    {
                        // Marks belonging to the same ligature component.
                        good = true;
                    }
                }
                else
                {
                    // If ligature ids don't match, it may be the case that one of the marks
                    // itself is a ligature, in which case match.
                    if ((curGlyph.LigatureId > 0 && curGlyph.LigatureComponent <= 0) ||
                        (prevGlyph.LigatureId > 0 && prevGlyph.LigatureComponent <= 0))
                    {
                        good = true;
                    }
                }

                if (!good)
                {
                    return(false);
                }

                int mark2Index = this.mark2Coverage.CoverageIndexOf(prevGlyphId);

                if (mark2Index == -1)
                {
                    return(false);
                }

                MarkRecord  markRecord = this.mark1ArrayTable.MarkRecords[mark1Index];
                AnchorTable baseAnchor = this.mark2ArrayTable.Mark2Records[mark2Index].MarkAnchorTable[markRecord.MarkClass];

                AdvancedTypographicUtils.ApplyAnchor(collection, index, baseAnchor, markRecord, prevIdx);

                return(true);
            }