OSDN Git Service

初コミット
[fooeditengine/FooEditEngine.git] / WPF / FooEditEngine / Direct2D / D2DRender.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 System.Windows;
16 using System.Windows.Controls;
17 using System.Windows.Media;
18 using System.Windows.Interop;
19 using FooEditEngine;
20 using DotNetTextStore;
21 using DotNetTextStore.UnmanagedAPI.TSF;
22 using DotNetTextStore.UnmanagedAPI.WinDef;
23 using SharpDX;
24 using D2D = SharpDX.Direct2D1;
25 using DW = SharpDX.DirectWrite;
26 using D3D10 = SharpDX.Direct3D10;
27 using D3D9 = SharpDX.Direct3D9;
28 using DXGI = SharpDX.DXGI;
29
30 namespace FooEditEngine.WPF
31 {
32     class D2DRender : ITextRender, IDisposable
33     {
34         D2DRenderCommon common;
35         System.Windows.Media.Color ForegroundColor, BackgroundColor, HilightColor, Keyword1Color, Keyword2Color, LiteralColor, UrlColor, ControlCharColor, CommentColor, InsertCaretColor,OverwriteCaretColor,LineMarkerColor;
36         DotNetTextStore.TextStore store;
37         D3D10.Texture2D texture;
38         DXGI.Surface surface;
39         D3D10.Device device;
40         D3D9.Device device9;
41         D3D9.Surface surface9;
42         D2D.RenderTarget render;
43         double fontSize;
44         FontFamily fontFamily;
45         FontWeight fontWeigth;
46         FontStyle fontStyle;
47         D3DImage imageSource;
48
49         public D2DRender(FooTextBox textbox, double width, double height,Image image)
50         {
51             this.fontFamily = textbox.FontFamily;
52             this.fontSize = textbox.FontSize;
53             this.fontWeigth = textbox.FontWeight;
54             this.fontStyle = textbox.FontStyle;
55             this.ForegroundColor = textbox.Foreground;
56             this.BackgroundColor = textbox.Background;
57             this.ControlCharColor = textbox.ControlChar;
58             this.HilightColor = textbox.Hilight;
59             this.CommentColor = textbox.Comment;
60             this.UrlColor = textbox.URL;
61             this.Keyword1Color = textbox.Keyword1;
62             this.Keyword2Color = textbox.Keyword2;
63             this.LiteralColor = textbox.Literal;
64             this.InsertCaretColor = textbox.InsertCaret;
65             this.OverwriteCaretColor = textbox.OverwriteCaret;
66             this.LineMarkerColor = textbox.LineMarker;
67             this.store = textbox.TextStore;
68
69             this.CreateDevice();
70
71             this.common = new D2DRenderCommon();
72             this.common.ConstructRender = ConstructRenderHandler;
73             this.common.ConstrctedResource = ConstructedResourceHandler;
74             this.common.DestructRender = this.DestructRenderHandler;
75             this.common.ReCreateTarget = this.ReCreateTarget;
76             this.common.GetDpi = this.GetDpi;
77             this.common.ConstructDeviceResource(width, height);
78             this.common.InitTextFormat(this.fontFamily.Source, (float)this.fontSize, this.GetDWFontWeigth(this.fontWeigth), this.GetDWFontStyle(this.fontStyle));
79
80             this.imageSource = new D3DImage();
81             this.imageSource.Lock();
82             this.imageSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, this.surface9.NativePointer);  //設定しないとロード時に例外が発生する
83             this.imageSource.Unlock();
84
85             image.Source = this.imageSource;
86         }
87
88         private void GetDpi(out int dpix, out int dpiy)
89         {
90             IntPtr hDc = NativeMethods.GetDC(IntPtr.Zero);
91             dpix = NativeMethods.GetDeviceCaps(hDc, NativeMethods.LOGPIXELSX);
92             dpiy = NativeMethods.GetDeviceCaps(hDc, NativeMethods.LOGPIXELSY);
93             NativeMethods.ReleaseDC(IntPtr.Zero, hDc);
94         }
95
96         public TextAntialiasMode TextAntialiasMode
97         {
98             get
99             {
100                 return this.common.TextAntialiasMode;
101             }
102             set
103             {
104                 this.common.TextAntialiasMode = value;
105             }
106         }
107
108         public bool ShowFullSpace
109         {
110             get
111             {
112                 return this.common.ShowFullSpace;
113             }
114             set
115             {
116                 this.common.ShowFullSpace = value;
117             }
118         }
119
120         public bool ShowHalfSpace
121         {
122             get
123             {
124                 return this.common.ShowHalfSpace;
125             }
126             set
127             {
128                 this.common.ShowHalfSpace = value;
129             }
130         }
131
132         public bool ShowTab
133         {
134             get
135             {
136                 return this.common.ShowTab;
137             }
138             set
139             {
140                 this.common.ShowTab = value;
141             }
142         }
143
144         public FontFamily FontFamily
145         {
146             get { return this.fontFamily; }
147             set
148             {
149                 this.fontFamily = value;
150                 this.common.InitTextFormat(this.fontFamily.Source, (float)this.fontSize, this.GetDWFontWeigth(this.fontWeigth), this.GetDWFontStyle(this.fontStyle));
151                 this.TabWidthChar = this.TabWidthChar;
152             }
153         }
154
155         public double FontSize
156         {
157             get { return this.fontSize; }
158             set
159             {
160                 this.fontSize = value;
161                 this.common.InitTextFormat(this.fontFamily.Source, (float)value, this.GetDWFontWeigth(this.fontWeigth), this.GetDWFontStyle(this.fontStyle));
162                 this.TabWidthChar = this.TabWidthChar;
163             }
164         }
165
166         public FontWeight FontWeigth
167         {
168             get
169             {
170                 return this.fontWeigth;
171             }
172             set
173             {
174                 this.fontWeigth = value;
175                 this.common.InitTextFormat(this.fontFamily.Source, (float)this.fontSize, this.GetDWFontWeigth(value),this.GetDWFontStyle(this.fontStyle));
176             }
177         }
178
179         public FontStyle FontStyle
180         {
181             get
182             {
183                 return this.fontStyle;
184             }
185             set
186             {
187                 this.fontStyle = value;
188                 this.common.InitTextFormat(this.fontFamily.Source, (float)this.fontSize, this.GetDWFontWeigth(this.fontWeigth), this.GetDWFontStyle(this.fontStyle));
189             }
190         }
191
192         public bool RightToLeft
193         {
194             get
195             {
196                 return this.common.RightToLeft;
197             }
198             set
199             {
200                 this.common.RightToLeft = value;
201             }
202         }
203
204         Color4 ToColor4(System.Windows.Media.Color color)
205         {
206             return new Color4(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, color.A / 255.0f);
207         }
208
209         public System.Windows.Media.Color Foreground
210         {
211             get
212             {
213                 return this.ForegroundColor;
214             }
215             set
216             {
217                 this.ForegroundColor = value;
218                 this.common.Foreground = this.ToColor4(value);
219             }
220         }
221
222         public System.Windows.Media.Color Background
223         {
224             get
225             {
226                 return this.BackgroundColor;
227             }
228             set
229             {
230                 this.BackgroundColor = value;
231                 this.common.Background = this.ToColor4(value);
232             }
233         }
234
235         public System.Windows.Media.Color InsertCaret
236         {
237             get
238             {
239                 return this.InsertCaretColor;
240             }
241             set
242             {
243                 this.InsertCaretColor = value;
244                 this.common.InsertCaret = this.ToColor4(value);
245             }
246         }
247
248         public System.Windows.Media.Color OverwriteCaret
249         {
250             get
251             {
252                 return this.OverwriteCaretColor;
253             }
254             set
255             {
256                 this.OverwriteCaretColor = value;
257                 this.common.OverwriteCaret = this.ToColor4(value);
258             }
259         }
260
261         public System.Windows.Media.Color LineMarker
262         {
263             get
264             {
265                 return this.LineMarkerColor;
266             }
267             set
268             {
269                 this.LineMarkerColor = value;
270                 this.common.LineMarker = this.ToColor4(value);
271             }
272         }
273
274         public System.Windows.Media.Color ControlChar
275         {
276             get
277             {
278                 return this.ControlCharColor;
279             }
280             set
281             {
282                 this.ControlCharColor = value;
283                 this.common.ControlChar = this.ToColor4(value);
284             }
285         }
286
287         public System.Windows.Media.Color Url
288         {
289             get
290             {
291                 return this.UrlColor;
292             }
293             set
294             {
295                 this.UrlColor = value;
296                 this.common.Url = this.ToColor4(value);
297             }
298         }
299
300         public System.Windows.Media.Color Hilight
301         {
302             get
303             {
304                 return this.HilightColor;
305             }
306             set
307             {
308                 this.HilightColor = value;
309                 this.common.Hilight = this.ToColor4(this.HilightColor);
310             }
311         }
312
313         public System.Windows.Media.Color Comment
314         {
315             get
316             {
317                 return this.CommentColor;
318             }
319             set
320             {
321                 this.CommentColor = value;
322                 this.common.Comment = this.ToColor4(value);
323             }
324         }
325
326         public System.Windows.Media.Color Literal
327         {
328             get
329             {
330                 return this.LiteralColor;
331             }
332             set
333             {
334                 this.LiteralColor = value;
335                 this.common.Literal = this.ToColor4(value);
336             }
337         }
338
339         public System.Windows.Media.Color Keyword1
340         {
341             get
342             {
343                 return this.Keyword1Color;
344             }
345             set
346             {
347                 this.Keyword1Color = value;
348                 this.common.Keyword1 = this.ToColor4(value);
349             }
350         }
351
352         public System.Windows.Media.Color Keyword2
353         {
354             get
355             {
356                 return this.Keyword2Color;
357             }
358             set
359             {
360                 this.Keyword2Color = value;
361                 this.common.Keyword2 = this.ToColor4(value);
362             }
363         }
364
365         public Rectangle TextArea
366         {
367             get { return this.common.ClipRect; }
368             set { this.common.ClipRect = value; }
369         }
370
371         public double LineNemberWidth
372         {
373             get
374             {
375                 return this.common.LineNemberWidth;
376             }
377         }
378
379         public double FoldingWidth
380         {
381             get
382             {
383                 return this.common.FoldingWidth;
384             }
385         }
386
387         public int TabWidthChar
388         {
389             get { return this.common.TabWidthChar; }
390             set
391             {
392                 if (value == 0)
393                     return;
394                 this.common.TabWidthChar = value;
395             }
396         }
397
398         public Size emSize
399         {
400             get
401             {
402                 return this.common.emSize;
403             }
404         }
405
406         public event ChangedRenderResourceEventHandler ChangedRenderResource
407         {
408             add
409             {
410                 this.common.ChangedRenderResource += value;
411             }
412             remove
413             {
414                 this.common.ChangedRenderResource -= value;
415             }
416         }
417
418         public event EventHandler ChangedRightToLeft
419         {
420             add
421             {
422                 this.common.ChangedRightToLeft += value;
423             }
424             remove
425             {
426                 this.common.ChangedRightToLeft -= value;
427             }
428         }
429
430         public bool Resize(double width, double height)
431         {
432             if (width != this.imageSource.Width || height != this.imageSource.Height)
433             {
434                 this.common.ReConstructDeviceResource(width, height);
435                 this.imageSource.Lock();
436                 this.imageSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, this.surface9.NativePointer);
437                 this.imageSource.Unlock();
438                 return true;
439             }
440             return false;
441         }
442
443         public void DrawCachedBitmap(Rectangle rect)
444         {
445             this.common.DrawCachedBitmap(rect);
446         }
447
448         public void CacheContent()
449         {
450             this.common.CacheContent();
451         }
452
453         public bool IsVaildCache()
454         {
455             return this.common.IsVaildCache();
456         }
457
458         public void BegineDraw()
459         {
460             this.common.BegineDraw();
461         }
462
463         public void EndDraw()
464         {
465             this.common.EndDraw();
466             this.device.Flush();
467
468             if (this.imageSource.IsFrontBufferAvailable)
469             {
470                 this.imageSource.Lock();
471                 this.imageSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, this.surface9.NativePointer);
472                 this.imageSource.AddDirtyRect(new Int32Rect(0, 0, (int)this.imageSource.Width, (int)this.imageSource.Height));
473                 this.imageSource.Unlock();
474             }
475         }
476
477         public void DrawString(string str, double x, double y, StringAlignment align, Size layoutRect)
478         {
479             this.common.DrawString(str, x, y,align,layoutRect);
480         }
481
482         public void FillRectangle(Rectangle rect,FillRectType type)
483         {
484             this.common.FillRectangle(rect, type);
485         }
486
487         public void DrawFoldingMark(bool expand, double x, double y)
488         {
489             this.common.DrawFoldingMark(expand, x, y);
490         }
491
492         public void FillBackground(Rectangle rect)
493         {
494             this.common.FillBackground(rect);
495         }
496
497         public void DrawLine(Point from, Point to)
498         {
499             this.common.DrawLine(from, to);
500         }
501
502         public void DrawOneLine(LineToIndexTable lti, int row, double x, double y, IEnumerable<Selection> SelectRanges)
503         {
504             PreDrawOneLineHandler PreDrawOneLine = (layout) => {
505                 using (Unlocker locker = this.store.LockDocument(false))
506                 {
507                     int lineIndex = lti.GetIndexFromLineNumber(row);
508                     int lineLength = lti.GetLengthFromLineNumber(row);
509                     foreach (TextDisplayAttribute attr in this.store.EnumAttributes(lineIndex,lineIndex + lineLength))
510                     {
511                         if (attr.startIndex == attr.endIndex)
512                             continue;
513                         int length = attr.endIndex - attr.startIndex;
514                         int start = attr.startIndex - lineIndex;
515
516                         HilightType type = HilightType.None;
517                         Color4? color = null;
518                         switch (attr.attribute.lsStyle)
519                         {
520                             case TF_DA_LINESTYLE.TF_LS_DOT:
521                                 type = HilightType.Dot;
522                                 color = this.GetColor4(attr.attribute.crLine);
523                                 break;
524                             case TF_DA_LINESTYLE.TF_LS_SOLID:
525                                 type = HilightType.Sold;
526                                 color = this.GetColor4(attr.attribute.crLine);
527                                 break;
528                             case TF_DA_LINESTYLE.TF_LS_DASH:
529                                 type = HilightType.Dash;
530                                 color = this.GetColor4(attr.attribute.crLine);
531                                 break;
532                             case TF_DA_LINESTYLE.TF_LS_SQUIGGLE:
533                                 type = HilightType.Squiggle;
534                                 color = this.GetColor4(attr.attribute.crLine);
535                                 break;
536                         }
537
538                         if (attr.attribute.crBk.type != TF_DA_COLORTYPE.TF_CT_NONE)
539                         {
540                             type = HilightType.Select;
541                             color = this.GetColor4(attr.attribute.crBk);
542                         }
543
544                         this.common.DrawMarkerEffect(layout, type, start, length,x,y,attr.attribute.fBoldLine,color);
545
546                         color = this.GetColor4(attr.attribute.crText);
547                         if (color != null)
548                         {
549                             this.common.SetTextColor(layout, start, length, color);
550                             layout.Invaild = true;
551                         }
552                     }
553                 }
554             };
555             this.common.DrawOneLine(lti,
556                 row,
557                 x,
558                 y,
559                 SelectRanges,
560                 PreDrawOneLine);
561         }
562
563         private Color4? GetColor4(TF_DA_COLOR cr)
564         {
565             COLORREF colorref;
566             switch(cr.type)
567             {
568                 case TF_DA_COLORTYPE.TF_CT_SYSCOLOR:
569                     colorref = new COLORREF(NativeMethods.GetSysColor((int)cr.indexOrColorRef));
570                     break;
571                 case TF_DA_COLORTYPE.TF_CT_COLORREF:
572                     colorref = new COLORREF(cr.indexOrColorRef);
573                     break;
574                 default:
575                     return null;
576             }
577             return new Color4(colorref.R / 255.0f, colorref.G / 255.0f, colorref.B / 255.0f, 1);
578         }
579
580         public ITextLayout CreateLaytout(string str, SyntaxInfo[] syntaxCollection, IEnumerable<Marker> MarkerRanges)
581         {
582             return this.common.CreateLaytout(str,syntaxCollection,MarkerRanges);
583         }
584
585         public List<LineToIndexTableData> BreakLine(Document doc, int startIndex, int endIndex, double wrapwidth)
586         {
587             return this.common.BreakLine(doc, startIndex, endIndex, wrapwidth);
588         }
589
590         public void Dispose()
591         {
592             //CA2213が表示されるが、DestructRenderHandlerで破棄しているので問題はない
593             this.common.Dispose();
594             this.DestructDevice();
595         }
596
597         void ReCreateTarget()
598         {
599             System.Diagnostics.Debug.WriteLine("ReCreatedDevice");
600             this.DestructDevice();
601             this.CreateDevice();
602             this.common.ReConstructDeviceResource();
603         }
604
605         DW.FontStyle GetDWFontStyle(FontStyle style)
606         {
607             return (DW.FontStyle)Enum.Parse(typeof(DW.FontStyle), style.ToString());
608         }
609
610         DW.FontWeight GetDWFontWeigth(FontWeight weigth)
611         {
612             return (DW.FontWeight)Enum.Parse(typeof(DW.FontWeight), weigth.ToString());
613         }
614
615         void CreateDevice()
616         {
617             D3D10.FeatureLevel[] levels = new D3D10.FeatureLevel[]{D3D10.FeatureLevel.Level_10_1,
618                 D3D10.FeatureLevel.Level_10_0,
619                 D3D10.FeatureLevel.Level_9_3,
620                 D3D10.FeatureLevel.Level_9_2,
621                 D3D10.FeatureLevel.Level_9_1};
622             foreach (D3D10.FeatureLevel level in levels)
623             {
624                 try
625                 {
626                     this.device = new D3D10.Device1(D3D10.DriverType.Hardware, D3D10.DeviceCreationFlags.BgraSupport,level);
627                     break;
628                 }
629                 catch
630                 {
631                     continue;
632                 }
633             }
634             if (this.device == null)
635                 throw new PlatformNotSupportedException("DirectX10デバイスの作成に失敗しました");
636
637             IntPtr DesktopWnd = NativeMethods.GetDesktopWindow();
638             D3D9.Direct3DEx d3dex = new D3D9.Direct3DEx();
639
640             D3D9.PresentParameters param = new D3D9.PresentParameters();
641             param.Windowed = true;
642             param.SwapEffect = D3D9.SwapEffect.Discard;
643             param.DeviceWindowHandle = DesktopWnd;
644             param.PresentationInterval = D3D9.PresentInterval.Default;
645
646             try
647             {
648                 this.device9 = new D3D9.DeviceEx(
649                     d3dex,
650                     0,
651                     D3D9.DeviceType.Hardware,
652                     DesktopWnd,
653                     D3D9.CreateFlags.HardwareVertexProcessing | D3D9.CreateFlags.Multithreaded | D3D9.CreateFlags.FpuPreserve,
654                     param);
655             }
656             catch
657             {
658                 try
659                 {
660                     this.device9 = new D3D9.DeviceEx(
661                         d3dex,
662                         0,
663                         D3D9.DeviceType.Hardware,
664                         DesktopWnd,
665                         D3D9.CreateFlags.SoftwareVertexProcessing | D3D9.CreateFlags.Multithreaded | D3D9.CreateFlags.FpuPreserve,
666                         param);
667                 }
668                 catch
669                 {
670                     throw new PlatformNotSupportedException("DirectX9デバイスの作成に失敗しました");
671                 }
672             }
673             finally
674             {
675                 d3dex.Dispose();
676             }
677         }
678
679         void DestructDevice()
680         {
681             if (this.device != null)
682             {
683                 this.device.Dispose();
684                 this.device = null;
685             }
686             if (this.device9 != null)
687             {
688                 this.device9.Dispose();
689                 this.device9 = null;
690             }
691         }
692
693         D2D.RenderTarget ConstructRenderHandler(D2D.Factory factory, D2D.RenderTargetProperties prop, double width, double height)
694         {
695             D3D10.Texture2DDescription desc = new D3D10.Texture2DDescription();
696             desc.Width = (int)width;
697             desc.Height = (int)height;
698             desc.MipLevels = 1;
699             desc.ArraySize = 1;
700             desc.Format = DXGI.Format.B8G8R8A8_UNorm;
701             desc.SampleDescription = new DXGI.SampleDescription(1, 0);
702             desc.Usage = D3D10.ResourceUsage.Default;
703             desc.BindFlags = D3D10.BindFlags.RenderTarget | D3D10.BindFlags.ShaderResource;
704             desc.CpuAccessFlags = D3D10.CpuAccessFlags.None;
705             desc.OptionFlags = D3D10.ResourceOptionFlags.Shared;
706             this.texture = new D3D10.Texture2D(this.device, desc);
707
708             this.surface = this.texture.QueryInterface<DXGI.Surface>();
709
710             DXGI.Resource resource = this.texture.QueryInterface<DXGI.Resource>();
711             IntPtr handel = resource.SharedHandle;
712             D3D9.Texture texture = new D3D9.Texture(
713                 this.device9,
714                 this.texture.Description.Width,
715                 this.texture.Description.Height,
716                 1,
717                 D3D9.Usage.RenderTarget,
718                 D3D9.Format.A8R8G8B8,
719                 D3D9.Pool.Default,
720                 ref handel);
721             this.surface9 = texture.GetSurfaceLevel(0);
722             resource.Dispose();
723             texture.Dispose();
724
725             this.render = new D2D.RenderTarget(factory, this.surface, prop);
726             return this.render;
727         }
728
729         void ConstructedResourceHandler()
730         {
731             this.common.Foreground = this.ToColor4(this.ForegroundColor);
732             this.common.Background = this.ToColor4(this.BackgroundColor);
733             this.common.ControlChar = this.ToColor4(this.ControlCharColor);
734             this.common.Url = this.ToColor4(this.UrlColor);
735             this.common.Keyword1 = this.ToColor4(this.Keyword1Color);
736             this.common.Keyword2 = this.ToColor4(this.Keyword2Color);
737             this.common.Literal = this.ToColor4(this.LiteralColor);
738             this.common.Comment = this.ToColor4(this.CommentColor);
739             this.common.Hilight = this.ToColor4(this.HilightColor);
740             this.common.LineMarker = this.ToColor4(this.LineMarkerColor);
741             this.common.InsertCaret = this.ToColor4(this.InsertCaretColor);
742             this.common.OverwriteCaret = this.ToColor4(this.OverwriteCaretColor);
743         }
744
745         void DestructRenderHandler()
746         {
747             if (this.texture != null)
748                 this.texture.Dispose();
749             if (this.surface != null)
750                 this.surface.Dispose();
751             if (this.surface9 != null)
752                 this.surface9.Dispose();
753             if (this.render != null)
754                 this.render.Dispose();
755         }
756     }
757 }