/// <inheritdoc/>
        public override void AssignFeatures(IGlyphShapingCollection collection, int index, int count)
        {
            this.AddFeature(collection, index, count, CcmpTag);
            this.AddFeature(collection, index, count, LoclTag);
            this.AddFeature(collection, index, count, IsolTag, false);
            this.AddFeature(collection, index, count, FinaTag, false);
            this.AddFeature(collection, index, count, Fin2Tag, false);
            this.AddFeature(collection, index, count, Fin3Tag, false);
            this.AddFeature(collection, index, count, MediTag, false);
            this.AddFeature(collection, index, count, Med2Tag, false);
            this.AddFeature(collection, index, count, InitTag, false);
            this.AddFeature(collection, index, count, MsetTag);

            base.AssignFeatures(collection, index, count);

            int prev  = -1;
            int state = 0;

            byte[] actions = new byte[count];

            // Apply the state machine to map glyphs to features.
            for (int i = 0; i < count; i++)
            {
                GlyphShapingData data         = collection.GetGlyphShapingData(i + index);
                JoiningClass     joiningClass = CodePoint.GetJoiningClass(data.CodePoint);
                JoiningType      joiningType  = joiningClass.JoiningType;
                if (joiningType == JoiningType.Transparent)
                {
                    actions[i] = None;
                    continue;
                }

                int    shapingClassIndex = GetShapingClassIndex(joiningType);
                byte[] actionsWithState  = StateTable[state, shapingClassIndex];
                byte   prevAction        = actionsWithState[0];
                byte   curAction         = actionsWithState[1];
                state = actionsWithState[2];

                if (prevAction != None && prev != -1)
                {
                    actions[prev] = prevAction;
                }

                actions[i] = curAction;
                prev       = i;
            }

            // Apply the chosen features to their respective glyphs.
            for (int i = 0; i < actions.Length; i++)
            {
                switch (actions[i])
                {
                case Fina:
                    collection.EnableShapingFeature(i + index, FinaTag);
                    break;

                case Fin2:
                    collection.EnableShapingFeature(i + index, Fin2Tag);
                    break;

                case Fin3:
                    collection.EnableShapingFeature(i + index, Fin3Tag);
                    break;

                case Isol:
                    collection.EnableShapingFeature(i + index, IsolTag);
                    break;

                case Init:
                    collection.EnableShapingFeature(i + index, InitTag);
                    break;

                case Medi:
                    collection.EnableShapingFeature(i + index, MediTag);
                    break;

                case Med2:
                    collection.EnableShapingFeature(i + index, Med2Tag);
                    break;
                }
            }
        }