/// <summary>
        /// Initialize the justifier with an array of infos corresponding to each
        /// glyph. Start and limit indicate the range of the array to examine.
        /// </summary>
        internal TextJustifier(GlyphJustificationInfo[] info, int start, int limit)
        {
            this.Info  = info;
            this.Start = start;
            this.Limit = limit;

            if (DEBUG)
            {
                System.Console.WriteLine("start: " + start + ", limit: " + limit);
                for (int i = start; i < limit; i++)
                {
                    GlyphJustificationInfo gji = info[i];
                    System.Console.WriteLine("w: " + gji.Weight + ", gp: " + gji.GrowPriority + ", gll: " + gji.GrowLeftLimit + ", grl: " + gji.GrowRightLimit);
                }
            }
        }
        /// <summary>
        /// Return an array of deltas twice as long as the original info array,
        /// indicating the amount by which each side of each glyph should grow
        /// or shrink.
        ///
        /// Delta should be positive to expand the line, and negative to compress it.
        /// </summary>
        public virtual float[] Justify(float delta)
        {
            float[] deltas = new float[Info.Length * 2];

            bool grow = delta > 0;

            if (DEBUG)
            {
                System.Console.WriteLine("delta: " + delta);
            }

            // make separate passes through glyphs in order of decreasing priority
            // until justifyDelta is zero or we run out of priorities.
            int fallbackPriority = -1;

            for (int p = 0; delta != 0; p++)
            {
                /*
                 * special case 'fallback' iteration, set flag and recheck
                 * highest priority
                 */
                bool lastPass = p > MAX_PRIORITY;
                if (lastPass)
                {
                    p = fallbackPriority;
                }

                // pass through glyphs, first collecting weights and limits
                float weight       = 0;
                float gslimit      = 0;
                float absorbweight = 0;
                for (int i = Start; i < Limit; i++)
                {
                    GlyphJustificationInfo gi = Info[i];
                    if ((grow ? gi.GrowPriority : gi.ShrinkPriority) == p)
                    {
                        if (fallbackPriority == -1)
                        {
                            fallbackPriority = p;
                        }

                        if (i != Start)                         // ignore left of first character
                        {
                            weight += gi.Weight;
                            if (grow)
                            {
                                gslimit += gi.GrowLeftLimit;
                                if (gi.GrowAbsorb)
                                {
                                    absorbweight += gi.Weight;
                                }
                            }
                            else
                            {
                                gslimit += gi.ShrinkLeftLimit;
                                if (gi.ShrinkAbsorb)
                                {
                                    absorbweight += gi.Weight;
                                }
                            }
                        }

                        if (i + 1 != Limit)                         // ignore right of last character
                        {
                            weight += gi.Weight;
                            if (grow)
                            {
                                gslimit += gi.GrowRightLimit;
                                if (gi.GrowAbsorb)
                                {
                                    absorbweight += gi.Weight;
                                }
                            }
                            else
                            {
                                gslimit += gi.ShrinkRightLimit;
                                if (gi.ShrinkAbsorb)
                                {
                                    absorbweight += gi.Weight;
                                }
                            }
                        }
                    }
                }

                // did we hit the limit?
                if (!grow)
                {
                    gslimit = -gslimit;                     // negative for negative deltas
                }
                bool hitLimit  = (weight == 0) || (!lastPass && ((delta < 0) == (delta < gslimit)));
                bool absorbing = hitLimit && absorbweight > 0;

                // predivide delta by weight
                float weightedDelta = delta / weight;                 // not used if weight == 0

                float weightedAbsorb = 0;
                if (hitLimit && absorbweight > 0)
                {
                    weightedAbsorb = (delta - gslimit) / absorbweight;
                }

                if (DEBUG)
                {
                    System.Console.WriteLine("pass: "******", d: " + delta + ", l: " + gslimit + ", w: " + weight + ", aw: " + absorbweight + ", wd: " + weightedDelta + ", wa: " + weightedAbsorb + ", hit: " + (hitLimit ? "y" : "n"));
                }

                // now allocate this based on ratio of weight to total weight
                int n = Start * 2;
                for (int i = Start; i < Limit; i++)
                {
                    GlyphJustificationInfo gi = Info[i];
                    if ((grow ? gi.GrowPriority : gi.ShrinkPriority) == p)
                    {
                        if (i != Start)                         // ignore left
                        {
                            float d;
                            if (hitLimit)
                            {
                                // factor in sign
                                d = grow ? gi.GrowLeftLimit : -gi.ShrinkLeftLimit;
                                if (absorbing)
                                {
                                    // sign factored in already
                                    d += gi.Weight * weightedAbsorb;
                                }
                            }
                            else
                            {
                                // sign factored in already
                                d = gi.Weight * weightedDelta;
                            }

                            deltas[n] += d;
                        }
                        n++;

                        if (i + 1 != Limit)                         // ignore right
                        {
                            float d;
                            if (hitLimit)
                            {
                                d = grow ? gi.GrowRightLimit : -gi.ShrinkRightLimit;
                                if (absorbing)
                                {
                                    d += gi.Weight * weightedAbsorb;
                                }
                            }
                            else
                            {
                                d = gi.Weight * weightedDelta;
                            }

                            deltas[n] += d;
                        }
                        n++;
                    }
                    else
                    {
                        n += 2;
                    }
                }

                if (!lastPass && hitLimit && !absorbing)
                {
                    delta -= gslimit;
                }
                else
                {
                    delta = 0;                     // stop iteration
                }
            }

            if (DEBUG)
            {
                float total = 0;
                for (int i = 0; i < deltas.Length; i++)
                {
                    total += deltas[i];
                    System.Console.Write(deltas[i] + ", ");
                    if (i % 20 == 9)
                    {
                        System.Console.WriteLine();
                    }
                }
                System.Console.WriteLine("\ntotal: " + total);
                System.Console.WriteLine();
            }

            return(deltas);
        }