OSDN Git Service

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