public D2D.GeometryRealization CreateSymbol(ShowSymbol sym, DW.TextFormat format)
        {
            D2D.GeometryRealization cached_geo = null;
            bool result = symbol_cache.TryGetValue(sym, out cached_geo);

            if (!result)
            {
                const int        margin = 2;
                D2D.Geometry     geo    = null;
                DW.TextLayout    layout = null;
                D2D.PathGeometry path   = null;
                DW.TextMetrics   metrics;
                D2D.StrokeStyle  stroke = null;
                switch (sym)
                {
                case ShowSymbol.FullSpace:
                    layout  = new DW.TextLayout(this._DWFactory, " ", format, float.MaxValue, float.MaxValue);
                    metrics = layout.Metrics;
                    Rectangle rect = new Rectangle(margin, margin, Math.Max(1, metrics.WidthIncludingTrailingWhitespace - margin * 2), Math.Max(1, metrics.Height - margin * 2));
                    geo    = new D2D.RectangleGeometry(this.Factory, rect);
                    stroke = this.GetStroke(HilightType.Dash);
                    break;

                case ShowSymbol.HalfSpace:
                    layout  = new DW.TextLayout(this._DWFactory, " ", format, float.MaxValue, float.MaxValue);
                    metrics = layout.Metrics;
                    rect    = new Rectangle(margin, margin, Math.Max(1, metrics.WidthIncludingTrailingWhitespace - margin * 2), Math.Max(1, metrics.Height - margin * 2));
                    geo     = new D2D.RectangleGeometry(this.Factory, rect);
                    stroke  = this.GetStroke(HilightType.Sold);
                    break;

                case ShowSymbol.Tab:
                    layout  = new DW.TextLayout(this._DWFactory, "0", format, float.MaxValue, float.MaxValue);
                    metrics = layout.Metrics;
                    path    = new D2D.PathGeometry(this.Factory);
                    var sink = path.Open();
                    sink.BeginFigure(new SharpDX.Mathematics.Interop.RawVector2(1, 1), D2D.FigureBegin.Filled);     //少し隙間を開けないと描写されない
                    sink.AddLine(new SharpDX.Mathematics.Interop.RawVector2((float)1, (float)metrics.Height));
                    sink.EndFigure(D2D.FigureEnd.Closed);
                    sink.Close();
                    geo    = path;
                    stroke = this.GetStroke(HilightType.Sold);
                    break;
                }
                cached_geo = new D2D.GeometryRealization(this.Device, geo, 1.0f, 1.0f, stroke);
                this.symbol_cache.Add(sym, cached_geo);
            }
            return(cached_geo);
        }
        public void DrawOneLine(Document doc, LineToIndexTable lti, int row, double x, double y, PreDrawOneLineHandler PreDrawOneLine)
        {
            int lineLength = lti.GetLengthFromLineNumber(row);

            if (lineLength == 0 || this.render == null || this.render.IsDisposed)
            {
                return;
            }

            MyTextLayout layout = (MyTextLayout)lti.GetLayout(row);

            if (PreDrawOneLine != null)
            {
                PreDrawOneLine(layout, lti, row, x, y);
            }

            if (layout.Markers != null)
            {
                foreach (Marker sel in layout.Markers)
                {
                    if (sel.length == 0 || sel.start == -1)
                    {
                        continue;
                    }
                    Color4 color = new Color4()
                    {
                        Alpha = sel.color.A, Red = sel.color.R, Blue = sel.color.B, Green = sel.color.G
                    };
                    if (sel.hilight == HilightType.Url)
                    {
                        color = this.Url;
                    }
                    this.DrawMarkerEffect(layout, sel.hilight, sel.start, sel.length, x, y, sel.isBoldLine, color);
                }
            }
            if (layout.Selects != null)
            {
                foreach (Selection sel in layout.Selects)
                {
                    if (sel.length == 0 || sel.start == -1)
                    {
                        continue;
                    }

                    this.DrawMarkerEffect(layout, HilightType.Select, sel.start, sel.length, x, y, false);
                }
            }

            if (this.ShowFullSpace || this.ShowHalfSpace || this.ShowTab)
            {
                string str = lti[row];
                D2D.GeometryRealization geo = null;
                for (int i = 0; i < lineLength; i++)
                {
                    Point pos = new Point(0, 0);
                    if (this.ShowTab && str[i] == '\t')
                    {
                        pos = layout.GetPostionFromIndex(i);
                        geo = this._factory.CreateSymbol(ShowSymbol.Tab, this.format);
                    }
                    else if (this.ShowFullSpace && str[i] == ' ')
                    {
                        pos = layout.GetPostionFromIndex(i);
                        geo = this._factory.CreateSymbol(ShowSymbol.FullSpace, this.format);
                    }
                    else if (this.ShowHalfSpace && str[i] == ' ')
                    {
                        pos = layout.GetPostionFromIndex(i);
                        geo = this._factory.CreateSymbol(ShowSymbol.HalfSpace, this.format);
                    }
                    if (geo != null)
                    {
                        var old_trans = this.render.Transform;
                        this.render.Transform = SharpDX.Matrix3x2.Translation(new Vector2((float)(pos.X + x), (float)(pos.Y + y)));
                        this.render.DrawGeometryRealization(geo, this._factory.GetSolidColorBrush(this.ControlChar));
                        this.render.Transform = old_trans;
                        geo = null;
                    }
                }
            }

            layout.Draw(this.render, (float)x, (float)y, this._factory.GetSolidColorBrush(this.Foreground));
        }