OSDN Git Service

選択領域の表示時の処理を最適化した
[fooeditengine/FooEditEngine.git] / Core / Direct2D / D2DRenderCommon.cs
1 /*
2  * Copyright (C) 2013 FooProject
3  * * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
5
6  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 
7  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
8
9 You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
10  */
11 using System;
12 using System.Collections.Generic;
13 using System.Linq;
14 using System.Text;
15 using FooEditEngine;
16 using SharpDX;
17 using D2D = SharpDX.Direct2D1;
18 using DW = SharpDX.DirectWrite;
19 using DXGI = SharpDX.DXGI;
20 using System.Runtime.InteropServices;
21
22 namespace FooEditEngine
23 {
24     delegate void PreDrawOneLineHandler(MyTextLayout layout,LineToIndexTable lti,int row,double x,double y);
25
26     delegate void GetDpiHandler(out float dpix,out float dpiy);
27
28     /// <summary>
29     /// 文字列のアンチエイリアシングモードを指定する
30     /// </summary>
31     public enum TextAntialiasMode
32     {
33         /// <summary>
34         /// 最適なものが選択されます
35         /// </summary>
36         Default = D2D.TextAntialiasMode.Default,
37         /// <summary>
38         /// ClearTypeでアンチエイリアシングを行います
39         /// </summary>
40         ClearType = D2D.TextAntialiasMode.Cleartype,
41         /// <summary>
42         /// グレイスケールモードでアンチエイリアシングを行います
43         /// </summary>
44         GrayScale = D2D.TextAntialiasMode.Grayscale,
45         /// <summary>
46         /// アンチエイリアシングを行いません
47         /// </summary>
48         Aliased = D2D.TextAntialiasMode.Aliased,
49     }
50
51     sealed class ColorBrushCollection
52     {
53         ResourceManager<Color4, D2D.SolidColorBrush> cache = new ResourceManager<Color4, D2D.SolidColorBrush>();
54         D2D.RenderTarget _render;
55
56         public event EventHandler RenderChanged;
57
58         public D2D.RenderTarget Render
59         {
60             get
61             {
62                 return this._render;
63             }
64             set
65             {
66                 this._render = value;
67                 if (this.RenderChanged != null)
68                     this.RenderChanged(this, null);
69             }
70         }
71
72         public D2D.SolidColorBrush Get(Color4 key)
73         {
74             if (this.Render == null || this.Render.IsDisposed)
75                 throw new InvalidOperationException();
76             D2D.SolidColorBrush brush;
77             bool result = cache.TryGetValue(key, out brush);
78             if (!result)
79             {
80                 brush = new D2D.SolidColorBrush(this.Render, key);
81                 cache.Add(key, brush);
82             }
83             
84             return brush;
85         }
86
87         public void Clear()
88         {
89             cache.Clear();
90         }
91     }
92
93     sealed class StrokeCollection
94     {
95         ResourceManager<HilightType, D2D.StrokeStyle> cache = new ResourceManager<HilightType, D2D.StrokeStyle>();
96
97         public D2D.Factory Factory;
98
99         public D2D.StrokeStyle Get(HilightType type)
100         {
101             if(this.Factory == null || this.Factory.IsDisposed)
102                 throw new InvalidOperationException();
103             D2D.StrokeStyle stroke;
104             if (this.cache.TryGetValue(type, out stroke))
105                 return stroke;
106
107             D2D.StrokeStyleProperties prop = new D2D.StrokeStyleProperties();
108             prop.DashCap = D2D.CapStyle.Flat;
109             prop.DashOffset = 0;
110             prop.DashStyle = D2D.DashStyle.Solid;
111             prop.EndCap = D2D.CapStyle.Flat;
112             prop.LineJoin = D2D.LineJoin.Miter;
113             prop.MiterLimit = 0;
114             prop.StartCap = D2D.CapStyle.Flat;
115             switch (type)
116             {
117                 case HilightType.Sold:
118                 case HilightType.Url:
119                 case HilightType.Squiggle:
120                     prop.DashStyle = D2D.DashStyle.Solid;
121                     break;
122                 case HilightType.Dash:
123                     prop.DashStyle = D2D.DashStyle.Dash;
124                     break;
125                 case HilightType.DashDot:
126                     prop.DashStyle = D2D.DashStyle.DashDot;
127                     break;
128                 case HilightType.DashDotDot:
129                     prop.DashStyle = D2D.DashStyle.DashDotDot;
130                     break;
131                 case HilightType.Dot:
132                     prop.DashStyle = D2D.DashStyle.Dot;
133                     break;
134             }
135             stroke = new D2D.StrokeStyle(this.Factory, prop);
136             this.cache.Add(type, stroke);
137             return stroke;
138         }
139         public void Clear()
140         {
141             cache.Clear();
142         }
143     }
144
145     class D2DRenderCommon : IDisposable
146     {
147         ColorBrushCollection Brushes = new ColorBrushCollection();
148         StrokeCollection Strokes = new StrokeCollection();
149         InlineManager HiddenChars;
150         TextAntialiasMode _TextAntialiasMode;
151         Color4 _ControlChar,_Forground,_URL,_Hilight;
152         DW.Factory DWFactory;
153 #if METRO || WINDOWS_UWP
154         D2D.Factory1 D2DFactory;
155 #else
156         D2D.Factory D2DFactory;
157 #endif
158         DW.TextFormat format;
159         protected D2D.Bitmap cachedBitMap;
160         CustomTextRenderer textRender;
161         int tabLength = 8;
162         bool _ShowLineBreak;
163         Color4 _Comment, _Literal, _Keyword1, _Keyword2;
164         protected bool hasCache;
165
166         protected Size renderSize
167         {
168             get;
169             private set;
170         }
171
172         protected D2D.RenderTarget render
173         {
174             get;
175             private set;
176         }
177
178         public D2DRenderCommon()
179         {
180             this.DWFactory = new DW.Factory(DW.FactoryType.Shared);
181 #if METRO || WINDOWS_UWP
182             this.D2DFactory = new D2D.Factory1(D2D.FactoryType.MultiThreaded);
183 #else
184             this.D2DFactory = new D2D.Factory(D2D.FactoryType.MultiThreaded);
185 #endif
186             this.Strokes.Factory = this.D2DFactory;
187             this.ChangedRenderResource += (s, e) => { };
188             this.ChangedRightToLeft += (s, e) => { };
189             this.renderSize = new Size();
190         }
191
192         public event ChangedRenderResourceEventHandler ChangedRenderResource;
193
194         public event EventHandler ChangedRightToLeft;
195
196         public const int MiniumeWidth = 40;    //これ以上ないと誤操作が起こる
197
198         public void InitTextFormat(string fontName, float fontSize, DW.FontWeight fontWeigth = DW.FontWeight.Normal,DW.FontStyle fontStyle = DW.FontStyle.Normal)
199         {
200             if(this.format != null)
201                 this.format.Dispose();
202
203             float dpix, dpiy;
204             this.GetDpi(out dpix, out dpiy);
205
206             this.format = new DW.TextFormat(this.DWFactory, fontName, fontWeigth, fontStyle, fontSize);
207             this.format.WordWrapping = DW.WordWrapping.NoWrap;
208
209             if (this.HiddenChars == null)
210                 this.HiddenChars = new InlineManager(this.DWFactory, this.format, this.ControlChar, this.Brushes);
211             else
212                 this.HiddenChars.Format = this.format;
213
214             this.TabWidthChar = this.TabWidthChar;
215
216             this.hasCache = false;
217
218             MyTextLayout layout = new MyTextLayout(this.DWFactory, "0", this.format, float.MaxValue, float.MaxValue, dpix, false);
219             layout.RightToLeft = false;
220             this.emSize = new Size(layout.Width, layout.Height);
221             layout.Dispose();
222
223             layout = new MyTextLayout(this.DWFactory, "+", this.format, float.MaxValue, float.MaxValue, dpix, false);
224             layout.RightToLeft = false;
225 #if METRO
226             this.FoldingWidth = Math.Max(D2DRenderCommon.MiniumeWidth, layout.Width);
227 #else
228             this.FoldingWidth = layout.Width;
229 #endif
230             layout.Dispose();
231
232             this.ChangedRenderResource(this,new ChangedRenderRsourceEventArgs(ResourceType.Font));
233         }
234
235         public bool RightToLeft
236         {
237             get
238             {
239                 return this.format.ReadingDirection == DW.ReadingDirection.RightToLeft;
240             }
241             set
242             {
243                 this.format.ReadingDirection = value ? DW.ReadingDirection.RightToLeft : DW.ReadingDirection.LeftToRight;
244                 this.ChangedRightToLeft(this, null);                
245             }
246         }
247
248         public TextAntialiasMode TextAntialiasMode
249         {
250             get
251             {
252                 return this._TextAntialiasMode;
253             }
254             set
255             {
256                 if (this.render == null)
257                     throw new InvalidOperationException();
258                 this._TextAntialiasMode = value;
259                 this.render.TextAntialiasMode = (D2D.TextAntialiasMode)value;
260                 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Antialias));
261             }
262         }
263
264         public bool ShowFullSpace
265         {
266             get
267             {
268                 if (this.HiddenChars == null)
269                     return false;
270                 else
271                     return this.HiddenChars.ContainsSymbol(' ');
272             }
273             set
274             {
275                 if (this.HiddenChars == null)
276                     throw new InvalidOperationException();
277                 if (value)
278                     this.HiddenChars.AddSymbol(' ', '□');
279                 else
280                     this.HiddenChars.RemoveSymbol(' ');
281             }
282         }
283
284         public bool ShowHalfSpace
285         {
286             get
287             {
288                 if (this.HiddenChars == null)
289                     return false;
290                 else
291                     return this.HiddenChars.ContainsSymbol(' ');
292             }
293             set
294             {
295                 if (this.HiddenChars == null)
296                     throw new InvalidOperationException();
297                 if (value)
298                     this.HiddenChars.AddSymbol(' ', 'ロ');
299                 else
300                     this.HiddenChars.RemoveSymbol(' ');
301             }
302         }
303
304         public bool ShowTab
305         {
306             get
307             {
308                 if (this.HiddenChars == null)
309                     return false;
310                 else
311                     return this.HiddenChars.ContainsSymbol('\t');
312             }
313             set
314             {
315                 if (this.HiddenChars == null)
316                     throw new InvalidOperationException();
317                 if (value)
318                     this.HiddenChars.AddSymbol('\t', '>');
319                 else
320                     this.HiddenChars.RemoveSymbol('\t');
321             }
322         }
323
324         public bool ShowLineBreak
325         {
326             get
327             {
328                 return this._ShowLineBreak;
329             }
330             set
331             {
332                 this._ShowLineBreak = value;
333             }
334         }
335
336         public Color4 Foreground
337         {
338             get
339             {
340                 return this._Forground;
341             }
342             set
343             {
344                 if (this.render == null)
345                     return;
346                 this._Forground = value;
347                 if (this.textRender != null)
348                     this.textRender.DefaultFore = value;
349                 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Brush));
350             }
351         }
352
353         public Color4 HilightForeground
354         {
355             get;
356             set;
357         }
358
359         public Color4 Background
360         {
361             get;
362             set;
363         }
364
365         public Color4 InsertCaret
366         {
367             get;
368             set;
369         }
370
371         public Color4 OverwriteCaret
372         {
373             get;
374             set;
375         }
376
377         public Color4 LineMarker
378         {
379             get;
380             set;
381         }
382
383         public Color4 UpdateArea
384         {
385             get;
386             set;
387         }
388
389         public Color4 LineNumber
390         {
391             get;
392             set;
393         }
394
395         public Color4 ControlChar
396         {
397             get
398             {
399                 return this._ControlChar;
400             }
401             set
402             {
403                 this._ControlChar = value;
404                 if (this.HiddenChars != null)
405                     this.HiddenChars.Fore = value;
406                 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Brush));
407             }
408         }
409
410         public Color4 Url
411         {
412             get
413             {
414                 return this._URL;
415             }
416             set
417             {
418                 this._URL = value;
419                 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Brush));
420             }
421         }
422
423         public Color4 Hilight
424         {
425             get
426             {
427                 return this._Hilight;
428             }
429             set
430             {
431                 this._Hilight = value;
432             }
433         }
434
435         public Color4 Comment
436         {
437             get
438             {
439                 return this._Comment;
440             }
441             set
442             {
443                 this._Comment = value;
444                 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Brush));
445             }
446         }
447
448         public Color4 Literal
449         {
450             get
451             {
452                 return this._Literal;
453             }
454             set
455             {
456                 this._Literal = value;
457                 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Brush));
458             }
459         }
460
461         public Color4 Keyword1
462         {
463             get
464             {
465                 return this._Keyword1;
466             }
467             set
468             {
469                 this._Keyword1 = value;
470                 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Brush));
471             }
472         }
473
474         public Color4 Keyword2
475         {
476             get
477             {
478                 return this._Keyword2;
479             }
480             set
481             {
482                 this._Keyword2 = value;
483                 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Brush));
484             }
485         }
486
487         public Rectangle TextArea
488         {
489             get;
490             set;
491         }
492
493         public double LineNemberWidth
494         {
495             get
496             {
497                 return this.emSize.Width * EditView.LineNumberLength;
498             }
499         }
500
501         public double FoldingWidth
502         {
503             get;
504             private set;
505         }
506
507         public int TabWidthChar
508         {
509             get { return this.tabLength; }
510             set
511             {
512                 if (value == 0)
513                     return;
514                 this.tabLength = value;
515                 DW.TextLayout layout = new DW.TextLayout(this.DWFactory, "0", this.format, float.MaxValue, float.MaxValue);
516                 float width = (float)(layout.Metrics.Width * value);
517                 this.HiddenChars.TabWidth = width;
518                 this.format.IncrementalTabStop = width;
519                 layout.Dispose();
520             }
521         }
522
523         public Size emSize
524         {
525             get;
526             private set;
527         }
528
529         public void DrawGripper(Point p, double radius)
530         {
531             D2D.Ellipse ellipse = new D2D.Ellipse();
532             ellipse.Point = p;
533             ellipse.RadiusX = (float)radius;
534             ellipse.RadiusY = (float)radius;
535             this.render.FillEllipse(ellipse, this.Brushes.Get(this.Background));
536             this.render.DrawEllipse(ellipse, this.Brushes.Get(this.Foreground));
537         }
538
539         public void ReConstructDeviceResource()
540         {
541             this.ReConstructDeviceResource(this.renderSize.Width, this.renderSize.Height);
542         }
543
544         public void ReConstructDeviceResource(double width, double height)
545         {
546             this.DestructDeviceResource();
547             this.ConstructDeviceResource(width, height);
548         }
549
550         public virtual void DrawCachedBitmap(Rectangle rect)
551         {
552         }
553
554         public virtual void CacheContent()
555         {
556         }
557
558         public virtual bool IsVaildCache()
559         {
560             return this.hasCache;
561         }
562
563         protected void BegineDraw()
564         {
565             if (this.render == null || this.render.IsDisposed)
566                 return;
567             this.render.BeginDraw();
568             this.render.AntialiasMode = D2D.AntialiasMode.Aliased;
569         }
570
571         protected void EndDraw()
572         {
573             if (this.render == null || this.render.IsDisposed)
574                 return;
575             this.render.AntialiasMode = D2D.AntialiasMode.PerPrimitive;
576             this.render.EndDraw();
577         }
578
579         public void DrawString(string str, double x, double y, StringAlignment align, Size layoutRect, StringColorType colorType = StringColorType.Forground)
580         {
581             if (this.render == null || this.render.IsDisposed)
582                 return;
583             float dpix, dpiy;
584             D2D.SolidColorBrush brush;
585             switch (colorType)
586             {
587                 case StringColorType.Forground:
588                     brush = this.Brushes.Get(this.Foreground);
589                     break;
590                 case StringColorType.LineNumber:
591                     brush = this.Brushes.Get(this.LineNumber);
592                     break;
593                 default:
594                     throw new ArgumentOutOfRangeException();
595             }
596             this.GetDpi(out dpix, out dpiy);
597             MyTextLayout layout = new MyTextLayout(this.DWFactory, str, this.format, (float)layoutRect.Width, (float)layoutRect.Height,dpix,false);
598             layout.StringAlignment = align;
599             layout.Draw(this.render, (float)x, (float)y, brush);
600             layout.Dispose();
601         }
602
603         public void DrawFoldingMark(bool expand, double x, double y)
604         {
605             string mark = expand ? "-" : "+";
606             this.DrawString(mark, x, y,StringAlignment.Left, new Size(this.FoldingWidth, this.emSize.Height));
607         }
608
609         public void FillRectangle(Rectangle rect,FillRectType type)
610         {
611             if (this.render == null || this.render.IsDisposed)
612                 return;
613             D2D.SolidColorBrush brush = null;
614             switch(type)
615             {
616                 case FillRectType.OverwriteCaret:
617                     brush = this.Brushes.Get(this.OverwriteCaret);
618                     this.render.FillRectangle(rect, brush);
619                     break;
620                 case FillRectType.InsertCaret:
621                     brush = this.Brushes.Get(this.InsertCaret);
622                     this.render.FillRectangle(rect, brush);
623                     break;
624                 case FillRectType.InsertPoint:
625                     brush = this.Brushes.Get(this.Hilight);
626                     this.render.FillRectangle(rect, brush);
627                     break;
628                 case FillRectType.LineMarker:
629                     brush = this.Brushes.Get(this.LineMarker);
630                     this.render.DrawRectangle(rect, brush, EditView.LineMarkerThickness);
631                     break;
632                 case FillRectType.UpdateArea:
633                     brush = this.Brushes.Get(this.UpdateArea);
634                     this.render.FillRectangle(rect, brush);
635                     break;
636             }
637         }
638
639         public void FillBackground(Rectangle rect)
640         {
641             if (this.render == null || this.render.IsDisposed)
642                 return;
643             this.render.Clear(this.Background);
644         }
645
646         public void DrawOneLine(Document doc,LineToIndexTable lti, int row, double x, double y, PreDrawOneLineHandler PreDrawOneLine)
647         {
648             int lineLength = lti.GetLengthFromLineNumber(row);
649
650             if (lineLength == 0 || this.render == null || this.render.IsDisposed)
651                 return;
652
653             MyTextLayout layout = (MyTextLayout)lti.GetLayout(row);
654
655             if(PreDrawOneLine != null)
656                 PreDrawOneLine(layout,lti,row,x,y);
657
658             if(this.HilightForeground.Alpha == 0.0f)
659             {
660                 int lineIndex = lti.GetIndexFromLineNumber(row);
661                 var SelectRanges = from s in doc.Selections.Get(lineIndex, lineLength)
662                                    let n = Util.ConvertAbsIndexToRelIndex(s, lineIndex, lineLength)
663                                    select n;
664
665                 if (SelectRanges != null)
666                 {
667                     foreach (Selection sel in SelectRanges)
668                     {
669                         if (sel.length == 0 || sel.start == -1)
670                             continue;
671
672                         this.DrawMarkerEffect(layout, HilightType.Select, sel.start, sel.length, x, y, false);
673                     }
674                 }
675             }
676
677             layout.Draw(textRender, (float)x, (float)y);
678
679         }
680
681         public void BeginClipRect(Rectangle rect)
682         {
683             this.render.PushAxisAlignedClip(rect, D2D.AntialiasMode.Aliased);
684         }
685
686         public void EndClipRect()
687         {
688             this.render.PopAxisAlignedClip();
689         }
690
691         public void SetTextColor(MyTextLayout layout,int start, int length, Color4? color)
692         {
693             if (color == null)
694                 return;
695             layout.SetDrawingEffect(this.Brushes.Get((Color4)color), new DW.TextRange(start, length));
696         }
697
698         public void DrawLine(Point from, Point to)
699         {
700             D2D.Brush brush = this.Brushes.Get(this.Foreground);
701             D2D.StrokeStyle stroke = this.Strokes.Get(HilightType.Sold);
702             this.render.DrawLine(from, to, brush, 1.0f, stroke);
703         }
704
705         public const int BoldThickness = 2;
706         public const int NormalThickness = 1;
707
708         public void DrawMarkerEffect(MyTextLayout layout, HilightType type, int start, int length, double x, double y, bool isBold, Color4? effectColor = null)
709         {
710             if (type == HilightType.None)
711                 return;
712
713             float thickness = isBold ? BoldThickness : NormalThickness;
714
715             Color4 color;
716             if (effectColor != null)
717                 color = (Color4)effectColor;
718             else if (type == HilightType.Select)
719                 color = this.Hilight;
720             else
721                 color = this.Foreground;
722
723             IMarkerEffecter effecter = null;
724             D2D.SolidColorBrush brush = this.Brushes.Get(color);
725
726             if (type == HilightType.Squiggle)
727                 effecter = new D2DSquilleLineMarker(this.render, brush, this.Strokes.Get(HilightType.Squiggle), thickness);
728             else if (type == HilightType.Select)
729                 effecter = new HilightMarker(this.render, brush);
730             else if (type == HilightType.None)
731                 effecter = null;
732             else
733                 effecter = new LineMarker(this.render, brush, this.Strokes.Get(type), thickness);
734
735             if (effecter != null)
736             {
737                 bool isUnderline = type != HilightType.Select;
738
739                 DW.HitTestMetrics[] metrics = layout.HitTestTextRange(start, length, (float)x, (float)y);
740                 foreach (DW.HitTestMetrics metric in metrics)
741                 {
742                     float offset = isUnderline ? metric.Height : 0;
743                     effecter.Draw(metric.Left, metric.Top + offset, metric.Width, metric.Height);
744                 }
745             }
746         }
747
748         public ITextLayout CreateLaytout(string str, SyntaxInfo[] syntaxCollection, IEnumerable<Marker> MarkerRanges, IEnumerable<Selection> SelectRanges)
749         {
750             float dpix,dpiy;
751             this.GetDpi(out dpix,out dpiy);
752
753             bool hasNewLine = str.Length > 0 && str[str.Length - 1] == Document.NewLine;
754             MyTextLayout newLayout = new MyTextLayout(this.DWFactory,
755                 str,
756                 this.format,
757                 this.TextArea.Width,
758                 this.TextArea.Height,
759                 dpiy,
760                 hasNewLine && this._ShowLineBreak);
761             ParseLayout(newLayout, str);
762             if (syntaxCollection != null)
763             {
764                 foreach (SyntaxInfo s in syntaxCollection)
765                 {
766                     D2D.SolidColorBrush brush = this.Brushes.Get(this.Foreground);
767                     switch (s.type)
768                     {
769                         case TokenType.Comment:
770                             brush = this.Brushes.Get(this.Comment);
771                             break;
772                         case TokenType.Keyword1:
773                             brush = this.Brushes.Get(this.Keyword1);
774                             break;
775                         case TokenType.Keyword2:
776                             brush = this.Brushes.Get(this.Keyword2);
777                             break;
778                         case TokenType.Literal:
779                             brush = this.Brushes.Get(this.Literal);
780                             break;
781                     }
782                     newLayout.SetDrawingEffect(brush, new DW.TextRange(s.index, s.length));
783                 }
784             }
785
786             if (MarkerRanges != null)
787             {
788                 foreach (Marker m in MarkerRanges)
789                 {
790                     if (m.start == -1 || m.length == 0)
791                         continue;
792                     Color4 color = new Color4(m.color.R / 255.0f, m.color.G / 255.0f, m.color.B / 255.0f, m.color.A / 255.0f);
793                     if (m.hilight == HilightType.Url)
794                         color = this.Url;
795                     if (m.hilight == HilightType.Select)
796                         newLayout.SetDrawingEffect(new SelectedEffect(this.HilightForeground, color, m.isBoldLine), new DW.TextRange(m.start, m.length));
797                     else
798                         newLayout.SetDrawingEffect(new DrawingEffect(m.hilight, color,m.isBoldLine), new DW.TextRange(m.start, m.length));
799                     if (m.hilight != HilightType.None && m.hilight != HilightType.Select)
800                         newLayout.SetUnderline(true, new DW.TextRange(m.start, m.length));
801                 }
802             }
803
804             if (SelectRanges != null && this.HilightForeground.Alpha > 0.0)
805             {
806                 foreach (Selection sel in SelectRanges)
807                 {
808                     if (sel.length == 0 || sel.start == -1)
809                         continue;
810
811                     newLayout.SetDrawingEffect(new SelectedEffect(this.HilightForeground, this.Hilight, false), new DW.TextRange(sel.start, sel.length));
812                 }
813             }
814
815             return newLayout;
816        }
817
818         public List<LineToIndexTableData> BreakLine(Document doc, LineToIndexTable layoutLineCollection, int startIndex, int endIndex, double wrapwidth)
819         {
820             List<LineToIndexTableData> output = new List<LineToIndexTableData>();
821
822             this.format.WordWrapping = DW.WordWrapping.Wrap;
823
824             foreach (string str in doc.GetLines(startIndex, endIndex))
825             {
826                 DW.TextLayout layout = new DW.TextLayout(this.DWFactory, str, this.format, (float)wrapwidth, float.MaxValue);
827
828                 int i = startIndex;
829                 foreach (DW.LineMetrics metrics in layout.GetLineMetrics())
830                 {
831                     if (metrics.Length == 0 && metrics.NewlineLength == 0)
832                         continue;
833
834                     bool lineend = false;
835                     if (metrics.NewlineLength > 0)
836                         lineend = true;
837
838                     output.Add(layoutLineCollection.CreateLineToIndexTableData(i, (int)metrics.Length, lineend, null));
839                     i += Util.RoundUp(metrics.Length);
840                 }
841
842                 layout.Dispose();
843
844                 startIndex += str.Length;
845             }
846
847             this.format.WordWrapping = DW.WordWrapping.NoWrap;
848
849             if (output.Count > 0)
850                 output.Last().LineEnd = true;
851
852             return output;
853         }
854
855         public virtual void Dispose()
856         {
857             this.DestructDeviceResource();
858             this.HiddenChars.Clear();
859             if (this.format != null)
860                 this.format.Dispose();
861             if(this.DWFactory != null)
862                 this.DWFactory.Dispose();
863             if(this.D2DFactory != null)
864                 this.D2DFactory.Dispose();
865         }
866
867         public void ConstructDeviceResource(double width, double height)
868         {
869             float dpiX, dpiY;
870             this.GetDpi(out dpiX, out dpiY);
871             D2D.RenderTargetProperties prop = new D2D.RenderTargetProperties(
872                 D2D.RenderTargetType.Default,
873                 new D2D.PixelFormat(DXGI.Format.B8G8R8A8_UNorm, D2D.AlphaMode.Ignore),
874                 dpiX,
875                 dpiY,
876                 D2D.RenderTargetUsage.None,
877                 D2D.FeatureLevel.Level_DEFAULT);
878
879             this.render = this.ConstructRender(this.D2DFactory,prop,width,height);
880
881             this.Brushes.Render = this.render;
882
883             D2D.BitmapProperties bmpProp = new D2D.BitmapProperties();
884             bmpProp.DpiX = dpiX;
885             bmpProp.DpiY = dpiY;
886             bmpProp.PixelFormat = new D2D.PixelFormat(DXGI.Format.B8G8R8A8_UNorm, D2D.AlphaMode.Ignore);
887             this.cachedBitMap = new D2D.Bitmap(this.render, new SharpDX.Size2((int)width, (int)height), bmpProp);
888             this.hasCache = false;
889
890             this.ConstrctedResource();
891
892             this.textRender = new CustomTextRenderer(this.render, this.Brushes,this.Strokes, this.Foreground);
893
894             this.renderSize = new Size(width,height);
895
896             this.TextAntialiasMode = this._TextAntialiasMode;
897         }
898
899 #if METRO || WINDOWS_UWP
900         protected virtual D2D.RenderTarget ConstructRender(D2D.Factory1 factory, D2D.RenderTargetProperties prop, double width, double height)
901 #else
902         protected virtual D2D.RenderTarget ConstructRender(D2D.Factory factory, D2D.RenderTargetProperties prop, double width, double height)
903 #endif
904         {
905             throw new NotImplementedException();
906         }
907
908         protected virtual void ConstrctedResource()
909         {
910             throw new NotImplementedException();
911         }
912
913         public virtual void GetDpi(out float dpix,out float dpiy)
914         {
915             throw new NotImplementedException();
916         }
917
918         protected virtual void DestructRender()
919         {
920             throw new NotImplementedException();
921
922         }
923
924         protected virtual void ReCreateTarget()
925         {
926             throw new NotImplementedException();
927         }
928
929         public void DestructDeviceResource()
930         {
931             this.hasCache = false;
932             if (this.cachedBitMap != null)
933                 this.cachedBitMap.Dispose();
934             this.Brushes.Clear();
935             this.Strokes.Clear();
936             if (this.textRender != null)
937                 this.textRender.Dispose();
938             this.DestructRender();
939         }
940
941         void ParseLayout(MyTextLayout layout, string str)
942         {
943             for (int i = 0; i < str.Length; i++)
944             {
945                 DW.InlineObject inlineObject = this.HiddenChars.Get(layout,i, str);
946                 if (inlineObject != null)
947                 {
948                     layout.SetInlineObject(inlineObject, new DW.TextRange(i, 1));
949                     layout.SetDrawingEffect(this.Brushes.Get(this.ControlChar), new DW.TextRange(i, 1));
950                 }
951             }
952             layout.SetLineBreakBrush(this.Brushes.Get(this.ControlChar));
953         }
954     }
955 }