/// <summary>
        /// Measures the size of the provided string at the specified font size (starting at a specific offset),
        /// stopping when the available space is full and returning the number of characters fitted.
        /// </summary>
        /// <param name="encoding">The encoding to use to map the characters</param>
        /// <param name="s">The string to measure the size of</param>
        /// <param name="startOffset">The starting (zero based) offset in that string to start measuring from</param>
        /// <param name="emsize">The M size in font units</param>
        /// <param name="availablePts">The max width allowed for this string</param>
        /// <param name="wordspace">The spacing between words in font units. Default 0</param>
        /// <param name="charspace">The spacing between characters in font units. Default 0</param>
        /// <param name="hscale">The horizontal scaling of all characters. Default 100</param>
        /// <param name="vertical">If true then this is vertical writing</param>
        /// <param name="wordboundary">If True the measuring will stop at a boundary to a word rather than character.</param>
        /// <param name="charsfitted">Set to the number of characters that can be renered at this size within the width.</param>
        /// <returns></returns>
        public LineSize MeasureString(CMapEncoding encoding, string s, int startOffset, double emsize, double availablePts, double?wordspacePts, double charspacePts, double hscale, bool vertical, bool wordboundary, out int charsfitted, FontUnitType useUnits = FontUnitType.UseFontPreference)
        {
            HorizontalMetrics table = this.Directories["hmtx"].Table as HorizontalMetrics;
            CMAPTable         cmap  = this.Directories["cmap"].Table as CMAPTable;
            OS2Table          os2   = this.Directories["OS/2"].Table as OS2Table;

            CMAPSubTable mac = cmap.GetOffsetTable(encoding);

            if (mac == null)
            {
                mac = cmap.GetOffsetTable(CMapEncoding.MacRoman);
            }

            HorizontalHeader hhead = this.Directories["hhea"].Table as HorizontalHeader;
            FontHeader       head  = this.Directories["head"].Table as FontHeader;

            double availableFU = availablePts * ((double)head.UnitsPerEm / emsize);
            double charspaceFU = NoCharacterSpace;

            if (charspacePts != NoCharacterSpace)
            {
                charspaceFU = charspacePts * ((double)head.UnitsPerEm / emsize);
            }

            double wordspaceFU = NoWordSpace;

            if (wordspacePts.HasValue)
            {
                wordspaceFU = (wordspacePts.Value * ((double)head.UnitsPerEm / emsize));
            }
            else if (charspacePts != NoCharacterSpace)
            {
                //If we dont have explicit wordspacing then we use the character spacing
                wordspaceFU = charspaceFU;
            }


            double len           = 0.0;
            double lastwordlen   = 0.0;
            int    lastwordcount = 0;

            charsfitted = 0;


            for (int i = startOffset; i < s.Length; i++)
            {
                char c = s[i];
                if (char.IsWhiteSpace(c))
                {
                    lastwordlen   = len;
                    lastwordcount = charsfitted;
                }

                int moffset = (int)mac.GetCharacterGlyphOffset(c);

                if (moffset >= table.HMetrics.Count)
                {
                    moffset = table.HMetrics.Count - 1;
                }

                Scryber.OpenType.SubTables.HMetric metric;
                metric = table.HMetrics[moffset];
                double w = metric.AdvanceWidth;

                if (i == 0)
                {
                    w -= metric.LeftSideBearing;
                }

                if (c == ' ')
                {
                    if (wordspaceFU != NoWordSpace)
                    {
                        w += wordspaceFU;
                    }
                }
                else if (charspaceFU != NoCharacterSpace)
                {
                    w += charspaceFU;
                }



                if (hscale != NoHorizontalScale)
                {
                    w *= hscale;
                }

                len += w;

                //check if we can fit more
                if (len > availableFU)
                {
                    len -= w;
                    break;
                }
                charsfitted++;
            }
            bool isboundary = false;

            if ((charsfitted + startOffset < s.Length) && wordboundary && lastwordlen > 0)
            {
                len         = lastwordlen;
                charsfitted = lastwordcount;
                isboundary  = true;
            }

            len = len * emsize;
            len = len / (double)head.UnitsPerEm;
            double h = GetLineHeight(useUnits, os2, hhead, head, emsize);

            return(new LineSize(len, h, charsfitted, startOffset, isboundary));
        }
        public LineSize MeasureString(CMapEncoding encoding, string s, int startOffset, double emsize, double available, bool wordboundary, out int charsfitted, FontUnitType useUnits = FontUnitType.UseFontPreference)
        {
            HorizontalMetrics table = this.Directories["hmtx"].Table as HorizontalMetrics;
            CMAPTable         cmap  = this.Directories["cmap"].Table as CMAPTable;
            OS2Table          os2   = this.Directories["OS/2"].Table as OS2Table;


            CMAPSubTable mac = cmap.GetOffsetTable(encoding);

            if (mac == null)
            {
                mac = cmap.GetOffsetTable(CMapEncoding.MacRoman);
            }

            HorizontalHeader hhead = this.Directories["hhea"].Table as HorizontalHeader;
            FontHeader       head  = this.Directories["head"].Table as FontHeader;

            available = (available * head.UnitsPerEm) / emsize;

            double len           = 0.0;
            double lastwordlen   = 0.0;
            int    lastwordcount = 0;

            charsfitted = 0;


            for (int i = startOffset; i < s.Length; i++)
            {
                char c = s[i];
                if (char.IsWhiteSpace(c))
                {
                    lastwordlen   = len;
                    lastwordcount = charsfitted;
                }

                int moffset = (int)mac.GetCharacterGlyphOffset(c);
                //System.Diagnostics.Debug.WriteLine("Character '" + chars[i].ToString() + "' (" + ((byte)chars[i]).ToString() + ") has offset '" + moffset.ToString() + "' in mac encoding and '" + woffset + "' in windows encoding");

                if (moffset >= table.HMetrics.Count)
                {
                    moffset = table.HMetrics.Count - 1;
                }
                Scryber.OpenType.SubTables.HMetric metric;
                metric = table.HMetrics[moffset];
                if (i == 0)
                {
                    len = -metric.LeftSideBearing;
                }
                len += metric.AdvanceWidth;

                //check if we can fit more
                if (len > available)
                {
                    len -= metric.AdvanceWidth;
                    break;
                }
                charsfitted++;
            }

            bool isboundary = false;

            if ((charsfitted + startOffset < s.Length) && wordboundary && lastwordlen > 0)
            {
                len         = lastwordlen;
                charsfitted = lastwordcount;
                isboundary  = true;
            }

            len = len / (double)head.UnitsPerEm;
            len = len * emsize;
            double h = GetLineHeight(useUnits, os2, hhead, head, emsize);

            return(new LineSize((float)len, (float)h, charsfitted, startOffset, isboundary));
        }
        public double MeasureChars(string chars, int startOffset, double emsize, double available, bool wordboundary, out int fitted)
        {
            int totalUnits = (int)Math.Floor((available * this.FUnitsPerEm) / emsize);

            int measured = 0;
            int count    = 0;

            int lastWordLen   = 0;
            int lastWordCount = 0;

            for (int i = startOffset; i < chars.Length; i++)
            {
                char c = chars[i];

                if (char.IsWhiteSpace(c))
                {
                    lastWordLen   = measured;
                    lastWordCount = count;
                }
                HMetric metric;

                if (_lookup.TryGetValue(c, out metric) == false)
                {
                    int moffset = _offsets.GetCharacterGlyphOffset(c);

                    if (moffset >= _metrics.Count)
                    {
                        moffset = _metrics.Count - 1;
                    }

                    metric = _metrics[moffset];
                    _lookup.Add(c, metric);
                }

                if (i == 0)
                {
                    measured -= metric.LeftSideBearing;
                }

                measured += metric.AdvanceWidth;

                if (measured > totalUnits)
                {
                    measured -= metric.AdvanceWidth;
                    break;
                }
                else
                {
                    count++;
                }
            }

            if (count + startOffset < chars.Length)
            {
                if (wordboundary && lastWordLen > 0)
                {
                    //Not everything fitted so go bask to the last full word
                    //(if there was one).
                    measured = lastWordLen;
                    count    = lastWordCount;
                }
            }

            double w = (measured * emsize) / (double)_unitsPerEm;

            fitted = count;
            return(w);
        }