예제 #1
0
        public override bool TransformOne(GlyphLine line)
        {
            if (line.idx >= line.end)
            {
                return(false);
            }
            if (openReader.IsSkip(line.Get(line.idx).GetCode(), lookupFlag))
            {
                line.idx++;
                return(false);
            }
            bool changed = false;

            OpenTableLookup.GlyphIndexer gi = null;
            foreach (GposLookupType4.MarkToBase mb in marksbases)
            {
                OtfMarkRecord omr = mb.marks.Get(line.Get(line.idx).GetCode());
                if (omr == null)
                {
                    continue;
                }
                if (gi == null)
                {
                    gi      = new OpenTableLookup.GlyphIndexer();
                    gi.idx  = line.idx;
                    gi.line = line;
                    while (true)
                    {
                        gi.PreviousGlyph(openReader, lookupFlag);
                        if (gi.glyph == null)
                        {
                            break;
                        }
                        // not mark => base glyph
                        if (!mb.marks.ContainsKey(gi.glyph.GetCode()))
                        {
                            break;
                        }
                    }
                    if (gi.glyph == null)
                    {
                        break;
                    }
                }
                GposAnchor[] gpas = mb.bases.Get(gi.glyph.GetCode());
                if (gpas == null)
                {
                    continue;
                }
                int        markClass  = omr.markClass;
                GposAnchor baseAnchor = gpas[markClass];
                GposAnchor markAnchor = omr.anchor;
                line.Set(line.idx, new Glyph(line.Get(line.idx), -markAnchor.XCoordinate + baseAnchor.XCoordinate, -markAnchor
                                             .YCoordinate + baseAnchor.YCoordinate, 0, 0, gi.idx - line.idx));
                changed = true;
                break;
            }
            line.idx++;
            return(changed);
        }
예제 #2
0
 public static GposAnchor[] ReadAnchorArray(OpenTypeFontTableReader tableReader, int[] locations, int left,
                                            int right)
 {
     GposAnchor[] anchors = new GposAnchor[right - left];
     for (int i = left; i < right; i++)
     {
         anchors[i - left] = ReadGposAnchor(tableReader, locations[i]);
     }
     return(anchors);
 }
예제 #3
0
        public static GposAnchor ReadGposAnchor(OpenTypeFontTableReader tableReader, int location)
        {
            if (location == 0)
            {
                return(null);
            }
            tableReader.rf.Seek(location);
            int        format = tableReader.rf.ReadUnsignedShort();
            GposAnchor t      = null;

            switch (format)
            {
            default: {
                t             = new GposAnchor();
                t.XCoordinate = tableReader.rf.ReadShort() * 1000 / tableReader.GetUnitsPerEm();
                t.YCoordinate = tableReader.rf.ReadShort() * 1000 / tableReader.GetUnitsPerEm();
                break;
            }
            }
            return(t);
        }
예제 #4
0
        public override bool TransformOne(GlyphLine line)
        {
            // TODO it seems that for complex cases (symbol1, symbol2, mark, symbol3) and (symbol1, symbol2, symbol3) compose a ligature,
            // mark should be placed in the corresponding anchor of that ligature (second component's anchor).
            // But for now we do not store all the substitution info and therefore not able to follow that logic.
            // Place the mark symbol in the first available place for now.
            if (line.idx >= line.end)
            {
                return(false);
            }
            if (openReader.IsSkip(line.Get(line.idx).GetCode(), lookupFlag))
            {
                line.idx++;
                return(false);
            }
            bool changed = false;

            OpenTableLookup.GlyphIndexer gi = null;
            foreach (GposLookupType5.MarkToLigature mb in marksligatures)
            {
                OtfMarkRecord omr = mb.marks.Get(line.Get(line.idx).GetCode());
                if (omr == null)
                {
                    continue;
                }
                if (gi == null)
                {
                    gi      = new OpenTableLookup.GlyphIndexer();
                    gi.idx  = line.idx;
                    gi.line = line;
                    while (true)
                    {
                        gi.PreviousGlyph(openReader, lookupFlag);
                        if (gi.glyph == null)
                        {
                            break;
                        }
                        // not mark => ligature glyph
                        if (!mb.marks.ContainsKey(gi.glyph.GetCode()))
                        {
                            break;
                        }
                    }
                    if (gi.glyph == null)
                    {
                        break;
                    }
                }
                IList <GposAnchor[]> gpas = mb.ligatures.Get(gi.glyph.GetCode());
                if (gpas == null)
                {
                    continue;
                }
                int markClass = omr.markClass;
                for (int component = 0; component < gpas.Count; component++)
                {
                    if (gpas[component][markClass] != null)
                    {
                        GposAnchor baseAnchor = gpas[component][markClass];
                        GposAnchor markAnchor = omr.anchor;
                        line.Add(line.idx, new Glyph(line.Get(line.idx), markAnchor.XCoordinate - baseAnchor.XCoordinate, markAnchor
                                                     .YCoordinate - baseAnchor.YCoordinate, 0, 0, gi.idx - line.idx));
                        changed = true;
                        break;
                    }
                }
                break;
            }
            line.idx++;
            return(changed);
        }
예제 #5
0
        public override bool TransformOne(GlyphLine line)
        {
            if (line.idx >= line.end)
            {
                return(false);
            }
            if (openReader.IsSkip(line.Get(line.idx).GetCode(), lookupFlag))
            {
                line.idx++;
                return(false);
            }
            bool changed = false;

            OpenTableLookup.GlyphIndexer gi = null;
            foreach (GposLookupType6.MarkToBaseMark mb in marksbases)
            {
                OtfMarkRecord omr = mb.marks.Get(line.Get(line.idx).GetCode());
                if (omr == null)
                {
                    continue;
                }
                if (gi == null)
                {
                    gi      = new OpenTableLookup.GlyphIndexer();
                    gi.idx  = line.idx;
                    gi.line = line;
                    while (true)
                    {
                        int prev = gi.idx;
                        // avoid attaching this mark glyph to another very distant mark glyph
                        bool foundBaseGlyph = false;
                        gi.PreviousGlyph(openReader, lookupFlag);
                        if (gi.idx != -1)
                        {
                            for (int i = gi.idx; i < prev; i++)
                            {
                                if (openReader.GetGlyphClass(line.Get(i).GetCode()) == OtfClass.GLYPH_BASE)
                                {
                                    foundBaseGlyph = true;
                                    break;
                                }
                            }
                        }
                        if (foundBaseGlyph)
                        {
                            gi.glyph = null;
                            break;
                        }
                        if (gi.glyph == null)
                        {
                            break;
                        }
                        if (mb.baseMarks.ContainsKey(gi.glyph.GetCode()))
                        {
                            break;
                        }
                    }
                    if (gi.glyph == null)
                    {
                        break;
                    }
                }
                GposAnchor[] gpas = mb.baseMarks.Get(gi.glyph.GetCode());
                if (gpas == null)
                {
                    continue;
                }
                int        markClass  = omr.markClass;
                GposAnchor baseAnchor = gpas[markClass];
                GposAnchor markAnchor = omr.anchor;
                line.Set(line.idx, new Glyph(line.Get(line.idx), -markAnchor.XCoordinate + baseAnchor.XCoordinate, -markAnchor
                                             .YCoordinate + baseAnchor.YCoordinate, 0, 0, gi.idx - line.idx));
                changed = true;
                break;
            }
            line.idx++;
            return(changed);
        }
예제 #6
0
        public override bool TransformOne(GlyphLine line)
        {
            if (line.idx >= line.end)
            {
                return(false);
            }
            if (openReader.IsSkip(line.Get(line.idx).GetCode(), lookupFlag))
            {
                line.idx++;
                return(false);
            }
            bool changed = false;

            OpenTableLookup.GlyphIndexer ligatureGlyphIndexer = null;
            foreach (GposLookupType5.MarkToLigature mb in marksligatures)
            {
                OtfMarkRecord omr = mb.marks.Get(line.Get(line.idx).GetCode());
                if (omr == null)
                {
                    continue;
                }
                if (ligatureGlyphIndexer == null)
                {
                    ligatureGlyphIndexer      = new OpenTableLookup.GlyphIndexer();
                    ligatureGlyphIndexer.idx  = line.idx;
                    ligatureGlyphIndexer.line = line;
                    while (true)
                    {
                        ligatureGlyphIndexer.PreviousGlyph(openReader, lookupFlag);
                        if (ligatureGlyphIndexer.glyph == null)
                        {
                            break;
                        }
                        // not mark => ligature glyph
                        if (!mb.marks.ContainsKey(ligatureGlyphIndexer.glyph.GetCode()))
                        {
                            break;
                        }
                    }
                    if (ligatureGlyphIndexer.glyph == null)
                    {
                        break;
                    }
                }
                IList <GposAnchor[]> componentAnchors = mb.ligatures.Get(ligatureGlyphIndexer.glyph.GetCode());
                if (componentAnchors == null)
                {
                    continue;
                }
                int markClass = omr.markClass;
                // TODO DEVSIX-3732 For complex cases like (glyph1, glyph2, mark, glyph3) and
                //  (glyph1, mark, glyph2, glyph3) when the base glyphs compose a ligature and the mark
                //  is attached to the ligature afterwards, mark should be placed in the corresponding anchor
                //  of that ligature (by finding the right component's anchor).
                //  Excerpt from Microsoft Docs: "For a given mark assigned to a particular class, the appropriate
                //  base attachment point is determined by which ligature component the mark is associated with.
                //  This is dependent on the original character string and subsequent character- or glyph-sequence
                //  processing, not the font data alone. While a text-layout client is performing any character-based
                //  preprocessing or any glyph-substitution operations using the GSUB table, the text-layout client
                //  must keep track of the associations of marks to particular ligature-glyph components."
                //  For now we do not store all the substitution info and therefore not able to follow that logic.
                //  We place the mark symbol in the last available place for now (seems to be better default than
                //  first available place).
                for (int component = componentAnchors.Count - 1; component >= 0; component--)
                {
                    if (componentAnchors[component][markClass] != null)
                    {
                        GposAnchor baseAnchor = componentAnchors[component][markClass];
                        GposAnchor markAnchor = omr.anchor;
                        line.Set(line.idx, new Glyph(line.Get(line.idx), baseAnchor.XCoordinate - markAnchor.XCoordinate, baseAnchor
                                                     .YCoordinate - markAnchor.YCoordinate, 0, 0, ligatureGlyphIndexer.idx - line.idx));
                        changed = true;
                        break;
                    }
                }
                break;
            }
            line.idx++;
            return(changed);
        }