Exemplo n.º 1
0
        /// <summary>Checks if given glyph line at the given position matches given rule.</summary>
        /// <returns>
        /// either index which corresponds to the last glyph of the matching context inside the glyph line if context matches,
        /// or -1 if context doesn't match.
        /// </returns>
        protected internal virtual int CheckIfContextMatch(GlyphLine line, ContextualSubstRule rule)
        {
            int j;

            OpenTableLookup.GlyphIndexer gidx = new OpenTableLookup.GlyphIndexer();
            gidx.line = line;
            gidx.idx  = line.idx;
            //Note, that starting index shall be 1
            for (j = 1; j < rule.GetContextLength(); ++j)
            {
                gidx.NextGlyph(openReader, lookupFlag);
                if (gidx.glyph == null || !rule.IsGlyphMatchesInput(gidx.glyph.GetCode(), j))
                {
                    break;
                }
            }
            bool isMatch = j == rule.GetContextLength();

            if (isMatch)
            {
                return(gidx.idx);
            }
            else
            {
                return(-1);
            }
        }
Exemplo n.º 2
0
            public override bool TransformOne(GlyphLine line)
            {
                if (line.idx >= line.end || line.idx < line.start)
                {
                    return(false);
                }
                bool  changed = false;
                Glyph g1      = line.Get(line.idx);
                IDictionary <int, GposLookupType2.PairValueFormat> m = gposMap.Get(g1.GetCode());

                if (m != null)
                {
                    OpenTableLookup.GlyphIndexer gi = new OpenTableLookup.GlyphIndexer();
                    gi.line = line;
                    gi.idx  = line.idx;
                    gi.NextGlyph(openReader, lookupFlag);
                    if (gi.glyph != null)
                    {
                        GposLookupType2.PairValueFormat pv = m.Get(gi.glyph.GetCode());
                        if (pv != null)
                        {
                            Glyph g2 = gi.glyph;
                            line.Set(line.idx, new Glyph(g1, 0, 0, pv.first.XAdvance, pv.first.YAdvance, 0));
                            line.Set(gi.idx, new Glyph(g2, 0, 0, pv.second.XAdvance, pv.second.YAdvance, 0));
                            line.idx = gi.idx;
                            changed  = true;
                        }
                    }
                }
                return(changed);
            }
Exemplo n.º 3
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);
        }
Exemplo n.º 4
0
        public virtual void SubstituteManyToOne(OpenTypeFontTableReader tableReader, int lookupFlag, int rightPartLen
                                                , int substitutionGlyphIndex)
        {
            OpenTableLookup.GlyphIndexer gidx = new OpenTableLookup.GlyphIndexer();
            gidx.line = this;
            gidx.idx  = idx;
            StringBuilder chars        = new StringBuilder();
            Glyph         currentGlyph = glyphs[idx];

            if (currentGlyph.GetChars() != null)
            {
                chars.Append(currentGlyph.GetChars());
            }
            else
            {
                if (currentGlyph.HasValidUnicode())
                {
                    chars.Append(iText.IO.Util.TextUtil.ConvertFromUtf32(currentGlyph.GetUnicode()));
                }
            }
            for (int j = 0; j < rightPartLen; ++j)
            {
                gidx.NextGlyph(tableReader, lookupFlag);
                currentGlyph = glyphs[gidx.idx];
                if (currentGlyph.GetChars() != null)
                {
                    chars.Append(currentGlyph.GetChars());
                }
                else
                {
                    if (currentGlyph.HasValidUnicode())
                    {
                        chars.Append(iText.IO.Util.TextUtil.ConvertFromUtf32(currentGlyph.GetUnicode()));
                    }
                }
                RemoveGlyph(gidx.idx--);
            }
            char[] newChars = new char[chars.Length];
            chars.GetChars(0, chars.Length, newChars, 0);
            Glyph newGlyph = tableReader.GetGlyph(substitutionGlyphIndex);

            newGlyph.SetChars(newChars);
            glyphs[idx] = newGlyph;
            end        -= rightPartLen;
        }
Exemplo n.º 5
0
        public override bool TransformOne(GlyphLine line)
        {
            //TODO >
            if (line.idx >= line.end)
            {
                return(false);
            }
            bool  changed = false;
            Glyph g       = line.Get(line.idx);
            bool  match   = false;

            if (ligatures.ContainsKey(g.GetCode()) && !openReader.IsSkip(g.GetCode(), lookupFlag))
            {
                OpenTableLookup.GlyphIndexer gidx = new OpenTableLookup.GlyphIndexer();
                gidx.line = line;
                IList <int[]> ligs = ligatures.Get(g.GetCode());
                foreach (int[] lig in ligs)
                {
                    match    = true;
                    gidx.idx = line.idx;
                    for (int j = 1; j < lig.Length; ++j)
                    {
                        gidx.NextGlyph(openReader, lookupFlag);
                        if (gidx.glyph == null || gidx.glyph.GetCode() != lig[j])
                        {
                            match = false;
                            break;
                        }
                    }
                    if (match)
                    {
                        line.SubstituteManyToOne(openReader, lookupFlag, lig.Length - 1, lig[0]);
                        break;
                    }
                }
            }
            if (match)
            {
                changed = true;
            }
            line.idx++;
            return(changed);
        }
Exemplo n.º 6
0
            public override bool TransformOne(GlyphLine line)
            {
                if (line.idx >= line.end || line.idx < line.start)
                {
                    return(false);
                }
                Glyph g1 = line.Get(line.idx);

                if (!coverageSet.Contains(g1.GetCode()))
                {
                    return(false);
                }
                int c1 = classDef1.GetOtfClass(g1.GetCode());

                GposLookupType2.PairValueFormat[] pvs = posSubs.Get(c1);
                if (pvs == null)
                {
                    return(false);
                }
                OpenTableLookup.GlyphIndexer gi = new OpenTableLookup.GlyphIndexer();
                gi.line = line;
                gi.idx  = line.idx;
                gi.NextGlyph(openReader, lookupFlag);
                if (gi.glyph == null)
                {
                    return(false);
                }
                Glyph g2 = gi.glyph;
                int   c2 = classDef2.GetOtfClass(g2.GetCode());

                if (c2 >= pvs.Length)
                {
                    return(false);
                }
                GposLookupType2.PairValueFormat pv = pvs[c2];
                line.Set(line.idx, new Glyph(g1, 0, 0, pv.first.XAdvance, pv.first.YAdvance, 0));
                line.Set(gi.idx, new Glyph(g2, 0, 0, pv.second.XAdvance, pv.second.YAdvance, 0));
                line.idx = gi.idx;
                return(true);
            }
Exemplo n.º 7
0
        public override bool TransformOne(GlyphLine line)
        {
            bool changed          = false;
            int  oldLineStart     = line.start;
            int  oldLineEnd       = line.end;
            int  initialLineIndex = line.idx;

            foreach (ContextualSubTable subTable in subTables)
            {
                ContextualSubstRule contextRule = subTable.GetMatchingContextRule(line);
                if (contextRule == null)
                {
                    continue;
                }
                int lineEndBeforeSubstitutions = line.end;
                SubstLookupRecord[]          substLookupRecords = contextRule.GetSubstLookupRecords();
                OpenTableLookup.GlyphIndexer gidx = new OpenTableLookup.GlyphIndexer();
                gidx.line = line;
                foreach (SubstLookupRecord substRecord in substLookupRecords)
                {
                    // There could be some skipped glyphs inside the context sequence, therefore currently GlyphIndexer and
                    // nextGlyph method are used to get to the glyph at "substRecord.sequenceIndex" index
                    gidx.idx = initialLineIndex;
                    for (int i = 0; i < substRecord.sequenceIndex; ++i)
                    {
                        gidx.NextGlyph(openReader, lookupFlag);
                    }
                    line.idx = gidx.idx;
                    OpenTableLookup lookupTable = openReader.GetLookupTable(substRecord.lookupListIndex);
                    changed = lookupTable.TransformOne(line) || changed;
                }
                line.idx   = line.end;
                line.start = oldLineStart;
                int lenDelta = lineEndBeforeSubstitutions - line.end;
                line.end = oldLineEnd - lenDelta;
                return(changed);
            }
            ++line.idx;
            return(changed);
        }
Exemplo n.º 8
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);
        }
Exemplo n.º 9
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);
        }
Exemplo n.º 10
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);
        }