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