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); }
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; }
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()); } }
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; }
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); }