Exemplo n.º 1
0
            void ReadFrom(BinaryReader reader)
            {
                long   markTableBeginAt = reader.BaseStream.Position;
                ushort markCount        = reader.ReadUInt16();

                records = new MarkRecord[markCount];
                for (int i = 0; i < markCount; ++i)
                {
                    //1 mark : 1 anchor
                    records[i] = new MarkRecord(
                        reader.ReadUInt16(),  //mark class
                        reader.ReadUInt16()); //offset to anchor table
                }
                //---------------------------
                //read anchor
                anchorPoints = new AnchorPoint[markCount];
                for (int i = 0; i < markCount; ++i)
                {
                    MarkRecord markRec = records[i];
                    //bug?
                    if (markRec.offset < 0)
                    {
                        //TODO: review here
                        //found err on Tahoma
                        continue;
                    }
                    //read table detail
                    anchorPoints[i] = AnchorPoint.CreateFrom(reader, markTableBeginAt + markRec.offset);
                }
            }
            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);
            }
Exemplo n.º 3
0
        public static void ApplyAnchor(
            GlyphPositioningCollection collection,
            ushort index,
            AnchorTable baseAnchor,
            MarkRecord markRecord,
            int baseGlyphIndex)
        {
            short baseX = baseAnchor.XCoordinate;
            short baseY = baseAnchor.YCoordinate;
            short markX = markRecord.MarkAnchorTable.XCoordinate;
            short markY = markRecord.MarkAnchorTable.YCoordinate;

            GlyphShapingData data = collection.GetGlyphShapingData(index);

            data.Bounds.X       = baseX - markX;
            data.Bounds.Y       = baseY - markY;
            data.MarkAttachment = baseGlyphIndex;
        }
Exemplo n.º 4
0
 void ReadFrom(BinaryReader reader)
 {
     ushort markCount = reader.ReadUInt16();
     records = new MarkRecord[markCount];
     for (int i = 0; i < markCount; ++i)
     {
         records[i] = new MarkRecord(
             reader.ReadUInt16(),
             reader.ReadInt16());
     }
 }
Exemplo n.º 5
0
            public MarkRecord GetMarkRecord(uint i)
            {
                MarkRecord mr = null;

                if (i < MarkCount)
                {
                    mr = new MarkRecord();
                    uint offset = m_offsetMarkArray + (uint)FieldOffsets.MarkRecordArray + i*4;
                    mr.Class            = m_bufTable.GetUshort(offset);
                    mr.MarkAnchorOffset = m_bufTable.GetUshort(offset + 2);
                }

                return mr;
            }
Exemplo n.º 6
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);
            }