protected virtual void parseString(string expression, Font font, Point offset, Color color,
                                           IILTextRenderer renderer, ref Size size,
                                           ref List <ILRenderQueueItem> queue)
        {
            int        pos = 0;
            string     key, itemText;
            RectangleF bmpSize = new RectangleF();
            int        curHeigth = 0, curWidth = 0;
            Bitmap     itemBMP = null;
            int        lineHeight = 0, lineWidth = 0;
            Size       itemSize = Size.Empty;

            while (pos < expression.Length)
            {
                itemText = expression.Substring(pos++, 1);
                key      = ILHashCreator.Hash(font, itemText);

                if (renderer.TryGetSize(key, ref itemSize))
                {
                    queue.Add(new ILRenderQueueItem(key, offset, color));
                    if (itemSize.Height > lineHeight)
                    {
                        lineHeight = itemSize.Height;
                    }
                    lineWidth += (int)itemSize.Width;
                }
                else
                {
                    lock (this) {
                        itemBMP = transformItem(itemText, font, out bmpSize);
                        renderer.Cache(key, itemBMP, bmpSize);
                        queue.Add(new ILRenderQueueItem(key, offset, color));
                        // update size
                        if (bmpSize.Height > lineHeight)
                        {
                            lineHeight = (int)bmpSize.Height;
                        }
                        lineWidth += (int)bmpSize.Width;
                    }
                }
            }
            size.Width += ((curWidth > lineWidth)?curWidth:lineWidth);
            size.Height = curHeigth + lineHeight;
        }
        protected override void parseString(string expression, Font font, Point offset, Color color,
                                            IILTextRenderer renderer, ref Size size,
                                            ref List <ILRenderQueueItem> queue)
        {
            int        pos = 0;
            string     key, itemText;
            RectangleF bmpSize = new RectangleF();
            int        curHeigth = 0, curWidth = 0;
            Bitmap     itemBMP = null;
            int        lineHeight = 0, lineWidth = 0;
            Size       itemSize = Size.Empty;

            while (pos < expression.Length)
            {
                itemText = expression.Substring(pos++, 1);
                #region special position control sequences
                if (itemText == "\r")
                {
                    queue.Add(new ILRenderQueueItem(itemText, 0, 0, color));
                    if (curWidth < lineWidth)
                    {
                        curWidth = lineWidth;
                    }
                    lineWidth = 0;
                    continue;
                }
                else if (itemText == "\n")
                {
                    queue.Add(new ILRenderQueueItem(itemText, 0, 0, color));
                    curHeigth += lineHeight;
                    lineHeight = 0;
                    if (curWidth < lineWidth)
                    {
                        curWidth = lineWidth;
                    }
                    lineWidth = 0;
                    continue;
                    #endregion
                }
                else if (itemText == "\\")
                {
                    #region font control
                    if (pos < expression.Length - 2)
                    {
                        #region test for font control sequences: \it,\bf,\rm
                        if (expression[pos] == 'i' && expression[pos + 1] == 't')
                        {
                            font = new Font(font, font.Style | FontStyle.Italic);
                            pos += 2; continue;
                        }
                        else if (expression[pos] == 'b' && expression[pos + 1] == 'f')
                        {
                            font = new Font(font, font.Style | FontStyle.Bold);
                            pos += 2; continue;
                        }
                        else if (expression[pos] == 'r' && expression[pos + 1] == 'm')
                        {
                            font = new Font(font, FontStyle.Regular);
                            pos += 2; continue;
                        }
                        #endregion
                        #region fontname,-size,-color
                        if (parseKeyword(expression, ref pos, Keywords.Reset))
                        {
                            color  = Color.Empty;
                            font   = m_normalFont;
                            offset = new Point(0, 0);
                            continue;
                        }
                        string parameter = "";
                        if (parseKeywordArgumented(expression, ref pos, Keywords.Fontname, ref parameter))
                        {
                            font = new Font(parameter, font.Size, font.Style, font.Unit);
                            continue;
                        }
                        if (parseKeywordArgumented(expression, ref pos, Keywords.Fontsize, ref parameter))
                        {
                            int newSize;
                            if (!int.TryParse(parameter, out newSize))
                            {
                                continue;
                            }
                            if (parameter.StartsWith("+") && newSize > 0)
                            {
                                newSize += (int)font.Size;
                                if (newSize > 40)
                                {
                                    newSize = 40;
                                }
                            }
                            else if (parameter.StartsWith("-") && -newSize < font.Size)
                            {
                                newSize = (int)font.Size + newSize;
                            }
                            if (newSize > 0 && newSize < 40)
                            {
                                offset.Y += (int)Math.Round(font.Size - newSize);
                                font      = new Font(font.Name, newSize, font.Style, font.Unit);
                            }
                            continue;
                        }
                        if (parseKeywordArgumented(expression, ref pos, Keywords.Color, ref parameter))
                        {
                            parseColor(parameter, ref color);
                            continue;
                        }
                        #endregion
                    }
                    #endregion
                    //if (pos < expression.Length - "size".Length)
                    #region handle predefined symbols
                    TextSymbols symbol = matchSymbol(expression, ref pos);
                    if (symbol != TextSymbols.nothing)
                    {
                        itemText = TranslateSymbol(symbol);
                        if (String.IsNullOrEmpty(itemText))
                        {
                            continue;
                        }
                    }
                    #endregion
                    #region lower- upper indices
                }
                else if (pos < expression.Length && itemText == "_")
                {
                    int end;
                    if (pos < expression.Length - 1 && expression[pos] == '{')
                    {
                        pos++;
                        // find end brace & remove
                        end = expression.IndexOf('}', pos) - 1;
                        if (end > 0 && end < expression.Length)
                        {
                            parseString(
                                expression.Substring(pos, end - pos + 1),
                                new Font(font.Name, font.Size * 0.7f, font.Style, font.Unit),
                                new Point(offset.X, offset.Y + (int)(0.3f * font.Height)),
                                color, renderer, ref size, ref queue);
                            pos = end + 2;
                            continue;
                        }
                    }
                    // cache next char only
                    parseString(
                        expression.Substring(pos++, 1),
                        new Font(font.Name, font.Size * 0.7f, font.Style, font.Unit),
                        new Point(offset.X, offset.Y + (int)(0.3f * font.Height)),
                        color, renderer, ref size, ref queue);
                    continue;
                }
                else if (pos < expression.Length && itemText == "^")
                {
                    int end;
                    //offset.Y += 0.8f * font.Height;
                    if (pos < expression.Length - 1 && expression[pos] == '{')
                    {
                        pos++;
                        // find end brace & remove
                        end = expression.IndexOf('}', pos) - 1;
                        if (end > 0 && end < expression.Length)
                        {
                            parseString(
                                expression.Substring(pos, end - pos + 1),
                                new Font(font.Name, font.Size * 0.7f, font.Style, font.Unit),
                                new Point(offset.X, offset.Y - (int)(0.2f * font.Height)),
                                color, renderer, ref size, ref queue);
                            pos = end + 2;
                            continue;
                        }
                    }
                    // cache next char only
                    parseString(
                        expression.Substring(pos++, 1),
                        new Font(font.Name, font.Size * 0.7f, font.Style, font.Unit),
                        new Point(offset.X, offset.Y - (int)(0.2f * font.Height))
                        , color, renderer, ref size, ref queue);
                    continue;
                    #endregion
                }
                key = ILHashCreator.Hash(font, itemText);

                if (renderer.TryGetSize(key, ref itemSize))
                {
                    queue.Add(new ILRenderQueueItem(key, offset, color));
                    if (itemSize.Height > lineHeight)
                    {
                        lineHeight = itemSize.Height;
                    }
                    lineWidth += (int)itemSize.Width;
                }
                else
                {
                    lock (this) {
                        itemBMP = transformItem(itemText, font, out bmpSize);
                        renderer.Cache(key, itemBMP, bmpSize);
                        queue.Add(new ILRenderQueueItem(key, offset, color));
                        // update size
                        if (bmpSize.Height > lineHeight)
                        {
                            lineHeight = (int)bmpSize.Height;
                        }
                        lineWidth += (int)bmpSize.Width;
                    }
                }
            }
            size.Width += ((curWidth > lineWidth)?curWidth:lineWidth);
            size.Height = curHeigth + lineHeight;
        }