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.
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.
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/>.
12 using System.Collections.Generic;
16 using System.Windows.Controls;
17 using System.Windows.Media;
18 using System.Windows.Input;
19 using System.Windows.Interop;
21 using DotNetTextStore;
22 using DotNetTextStore.UnmanagedAPI.TSF;
23 using DotNetTextStore.UnmanagedAPI.WinDef;
25 using D2D = SharpDX.Direct2D1;
26 using DW = SharpDX.DirectWrite;
27 using D3D11 = SharpDX.Direct3D11;
28 using D3D9 = SharpDX.Direct3D9;
29 using DXGI = SharpDX.DXGI;
31 namespace FooEditEngine.WPF
33 sealed class D2DRender : D2DRenderCommon, IEditorRender
35 DotNetTextStore.TextStore store;
36 D3D11.Texture2D texture;
40 D3D9.Surface surface9;
42 FontFamily fontFamily;
43 FontWeight fontWeigth;
47 public D2DRender(FooTextBox textbox, double width, double height, Image image)
49 this.fontFamily = textbox.FontFamily;
50 this.fontSize = textbox.FontSize;
51 this.fontWeigth = textbox.FontWeight;
52 this.fontStyle = textbox.FontStyle;
53 this.Foreground = ToColor4(textbox.Foreground);
54 this.Background = ToColor4(textbox.Background);
55 this.ControlChar = ToColor4(textbox.ControlChar);
56 this.Hilight = ToColor4(textbox.Hilight);
57 this.Comment = ToColor4(textbox.Comment);
58 this.Url = ToColor4(textbox.URL);
59 this.Keyword1 = ToColor4(textbox.Keyword1);
60 this.Keyword2 = ToColor4(textbox.Keyword2);
61 this.Literal = ToColor4(textbox.Literal);
62 this.InsertCaret = ToColor4(textbox.InsertCaret);
63 this.OverwriteCaret = ToColor4(textbox.OverwriteCaret);
64 this.LineMarker = ToColor4(textbox.LineMarker);
65 this.UpdateArea = ToColor4(textbox.UpdateArea);
66 this.LineNumber = ToColor4(textbox.LineNumber);
67 this.HilightForeground = ToColor4(textbox.HilightForeground);
68 this.store = textbox.TextStore;
72 this.ConstructRenderAndResource(width, height);
73 this.InitTextFormat(this.fontFamily.Source, (float)this.fontSize, this.GetDWFontWeigth(this.fontWeigth), this.GetDWFontStyle(this.fontStyle));
75 this.imageSource = new D3DImage();
76 this.imageSource.Lock();
77 this.imageSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, this.surface9.NativePointer); //設定しないとロード時に例外が発生する
78 this.imageSource.Unlock();
80 image.Source = this.imageSource;
83 public FontFamily FontFamily
85 get { return this.fontFamily; }
88 this.fontFamily = value;
89 this.InitTextFormat(this.fontFamily.Source, (float)this.fontSize, this.GetDWFontWeigth(this.fontWeigth), this.GetDWFontStyle(this.fontStyle));
90 this.TabWidthChar = this.TabWidthChar;
94 public double FontSize
96 get { return this.fontSize; }
99 this.fontSize = value;
100 this.InitTextFormat(this.fontFamily.Source, (float)value, this.GetDWFontWeigth(this.fontWeigth), this.GetDWFontStyle(this.fontStyle));
101 this.TabWidthChar = this.TabWidthChar;
105 public FontWeight FontWeigth
109 return this.fontWeigth;
113 this.fontWeigth = value;
114 this.InitTextFormat(this.fontFamily.Source, (float)this.fontSize, this.GetDWFontWeigth(value), this.GetDWFontStyle(this.fontStyle));
118 public FontStyle FontStyle
122 return this.fontStyle;
126 this.fontStyle = value;
127 this.InitTextFormat(this.fontFamily.Source, (float)this.fontSize, this.GetDWFontWeigth(this.fontWeigth), this.GetDWFontStyle(this.fontStyle));
131 public static Color4 ToColor4(System.Windows.Media.Color color)
133 return new Color4(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, color.A / 255.0f);
136 public bool Resize(double width, double height)
138 if (Math.Floor(width) != Math.Floor(this.imageSource.Width) || Math.Floor(height) != Math.Floor(this.imageSource.Height))
140 this.ReConstructRenderAndResource(width, height);
141 this.imageSource.Lock();
142 this.imageSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, this.surface9.NativePointer);
143 this.imageSource.Unlock();
149 public void ReConstructRenderAndResource(double width, double height)
151 this.DestructRenderAndResource();
152 this.ConstructRenderAndResource(width, height);
155 public void DrawContent(EditView view, bool IsEnabled, Rectangle updateRect)
157 if (this.imageSource.IsFrontBufferAvailable)
159 this.imageSource.Lock();
160 this.imageSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, this.surface9.NativePointer);
164 view.Draw(updateRect);
166 this.FillBackground(updateRect);
168 this.device.ImmediateContext.Flush();
170 this.imageSource.AddDirtyRect(new Int32Rect(0, 0, (int)this.imageSource.PixelWidth, (int)this.imageSource.PixelHeight));
171 this.imageSource.Unlock();
175 public void DrawOneLine(Document doc, LineToIndexTable lti, int row, double x, double y)
177 PreDrawOneLineHandler PreDrawOneLine = null;
179 if (InputMethod.Current.ImeState == InputMethodState.On)
180 PreDrawOneLine = this.DrawImeConversionLine;
182 base.DrawOneLine(doc,
191 private void DrawImeConversionLine(MyTextLayout layout, LineToIndexTable lti, int row, double x, double y)
193 using (Unlocker locker = this.store.LockDocument(false))
195 int lineIndex = lti.GetIndexFromLineNumber(row);
196 int lineLength = lti.GetLengthFromLineNumber(row);
197 foreach (TextDisplayAttribute attr in this.store.EnumAttributes(lineIndex, lineIndex + lineLength))
199 if (attr.startIndex == attr.endIndex)
201 int length = attr.endIndex - attr.startIndex;
202 int start = attr.startIndex - lineIndex;
204 HilightType type = HilightType.None;
205 Color4? color = null;
206 switch (attr.attribute.lsStyle)
208 case TF_DA_LINESTYLE.TF_LS_DOT:
209 type = HilightType.Dot;
210 color = this.GetColor4(attr.attribute.crLine);
212 case TF_DA_LINESTYLE.TF_LS_SOLID:
213 type = HilightType.Sold;
214 color = this.GetColor4(attr.attribute.crLine);
216 case TF_DA_LINESTYLE.TF_LS_DASH:
217 type = HilightType.Dash;
218 color = this.GetColor4(attr.attribute.crLine);
220 case TF_DA_LINESTYLE.TF_LS_SQUIGGLE:
221 type = HilightType.Squiggle;
222 color = this.GetColor4(attr.attribute.crLine);
226 if (attr.attribute.crBk.type != TF_DA_COLORTYPE.TF_CT_NONE)
228 type = HilightType.Select;
229 color = this.GetColor4(attr.attribute.crBk);
232 this.DrawMarkerEffect(layout, type, start, length, x, y, attr.attribute.fBoldLine, color);
234 color = this.GetColor4(attr.attribute.crText);
237 this.SetTextColor(layout, start, length, color);
238 layout.Invaild = true;
245 private Color4? GetColor4(TF_DA_COLOR cr)
250 case TF_DA_COLORTYPE.TF_CT_SYSCOLOR:
251 colorref = new COLORREF(NativeMethods.GetSysColor((int)cr.indexOrColorRef));
253 case TF_DA_COLORTYPE.TF_CT_COLORREF:
254 colorref = new COLORREF(cr.indexOrColorRef);
259 return new Color4(colorref.R / 255.0f, colorref.G / 255.0f, colorref.B / 255.0f, 1);
262 DW.FontStyle GetDWFontStyle(FontStyle style)
264 return (DW.FontStyle)Enum.Parse(typeof(DW.FontStyle), style.ToString());
267 DW.FontWeight GetDWFontWeigth(FontWeight weigth)
269 return (DW.FontWeight)Enum.Parse(typeof(DW.FontWeight), weigth.ToString());
272 public override void DrawCachedBitmap(Rectangle rect)
274 if (this.render == null || this.render.IsDisposed || this.cachedBitMap == null || this.cachedBitMap.IsDisposed)
276 render.DrawBitmap(this.cachedBitMap, rect, 1.0f, D2D.BitmapInterpolationMode.Linear, rect);
279 public override void CacheContent()
281 if (this.render == null || this.cachedBitMap == null || this.cachedBitMap.IsDisposed || this.render.IsDisposed)
284 this.cachedBitMap.CopyFromRenderTarget(this.render, new SharpDX.Point(), new SharpDX.Rectangle(0, 0, (int)this.renderSize.Width, (int)this.renderSize.Height));
285 this.hasCache = true;
290 SharpDX.Direct3D.FeatureLevel[] levels = new SharpDX.Direct3D.FeatureLevel[]{
291 SharpDX.Direct3D.FeatureLevel.Level_11_0,
292 SharpDX.Direct3D.FeatureLevel.Level_10_1,
293 SharpDX.Direct3D.FeatureLevel.Level_10_0,
294 SharpDX.Direct3D.FeatureLevel.Level_9_3,
295 SharpDX.Direct3D.FeatureLevel.Level_9_2,
296 SharpDX.Direct3D.FeatureLevel.Level_9_1};
297 foreach (var level in levels)
301 this.device = new D3D11.Device(SharpDX.Direct3D.DriverType.Hardware, D3D11.DeviceCreationFlags.BgraSupport, level);
309 if (this.device == null)
310 throw new PlatformNotSupportedException("DirectX10デバイスの作成に失敗しました");
312 IntPtr DesktopWnd = NativeMethods.GetDesktopWindow();
313 D3D9.Direct3DEx d3dex = new D3D9.Direct3DEx();
315 D3D9.PresentParameters param = new D3D9.PresentParameters();
316 param.Windowed = true;
317 param.SwapEffect = D3D9.SwapEffect.Discard;
318 param.DeviceWindowHandle = DesktopWnd;
319 param.PresentationInterval = D3D9.PresentInterval.Default;
323 this.device9 = new D3D9.DeviceEx(
326 D3D9.DeviceType.Hardware,
328 D3D9.CreateFlags.HardwareVertexProcessing | D3D9.CreateFlags.Multithreaded | D3D9.CreateFlags.FpuPreserve,
335 this.device9 = new D3D9.DeviceEx(
338 D3D9.DeviceType.Hardware,
340 D3D9.CreateFlags.SoftwareVertexProcessing | D3D9.CreateFlags.Multithreaded | D3D9.CreateFlags.FpuPreserve,
345 throw new PlatformNotSupportedException("DirectX9デバイスの作成に失敗しました");
354 void DestructDevice()
356 if (this.device != null)
358 this.device.Dispose();
361 if (this.device9 != null)
363 this.device9.Dispose();
368 public void ConstructRenderAndResource(double width, double height)
371 this.GetDpi(out dpiX, out dpiY);
372 D2D.RenderTargetProperties prop = new D2D.RenderTargetProperties(
373 D2D.RenderTargetType.Default,
374 new D2D.PixelFormat(DXGI.Format.B8G8R8A8_UNorm, D2D.AlphaMode.Premultiplied),
377 D2D.RenderTargetUsage.None,
378 D2D.FeatureLevel.Level_DEFAULT);
380 D3D11.Texture2DDescription desc = new D3D11.Texture2DDescription();
381 desc.Width = (int)width;
382 desc.Height = (int)height;
385 desc.Format = DXGI.Format.B8G8R8A8_UNorm;
386 desc.SampleDescription = new DXGI.SampleDescription(1, 0);
387 desc.Usage = D3D11.ResourceUsage.Default;
388 desc.BindFlags = D3D11.BindFlags.RenderTarget | D3D11.BindFlags.ShaderResource;
389 desc.CpuAccessFlags = D3D11.CpuAccessFlags.None;
390 desc.OptionFlags = D3D11.ResourceOptionFlags.Shared;
391 this.texture = new D3D11.Texture2D(this.device, desc);
393 this.surface = this.texture.QueryInterface<DXGI.Surface>();
395 DXGI.Resource resource = this.texture.QueryInterface<DXGI.Resource>();
396 IntPtr handel = resource.SharedHandle;
397 D3D9.Texture texture = new D3D9.Texture(
399 this.texture.Description.Width,
400 this.texture.Description.Height,
402 D3D9.Usage.RenderTarget,
403 D3D9.Format.A8R8G8B8,
406 this.surface9 = texture.GetSurfaceLevel(0);
410 this.render = new D2D.RenderTarget(this.D2DFactory, this.surface, prop);
412 D2D.BitmapProperties bmpProp = new D2D.BitmapProperties();
415 bmpProp.PixelFormat = new D2D.PixelFormat(DXGI.Format.B8G8R8A8_UNorm, D2D.AlphaMode.Premultiplied);
416 this.cachedBitMap = new D2D.Bitmap(this.render, new SharpDX.Size2((int)width, (int)height), bmpProp);
417 this.hasCache = false;
419 this.textRender = new CustomTextRenderer(this.render, this.Brushes, this.Strokes, this.Foreground);
421 this.renderSize = new Size(width, height);
424 public void DestructRenderAndResource()
426 this.hasCache = false;
427 if (this.cachedBitMap != null)
428 this.cachedBitMap.Dispose();
429 this.Brushes.Clear();
430 this.Strokes.Clear();
431 if (this.textRender != null)
432 this.textRender.Dispose();
433 if (this.texture != null)
434 this.texture.Dispose();
435 if (this.surface != null)
436 this.surface.Dispose();
437 if (this.surface9 != null)
438 this.surface9.Dispose();
439 if (this.render != null)
440 this.render.Dispose();
443 public override void GetDpi(out float dpix, out float dpiy)
445 var dpiXProperty = typeof(SystemParameters).GetProperty("DpiX", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
446 var dpiYProperty = typeof(SystemParameters).GetProperty("Dpi", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
448 dpix = (int)dpiXProperty.GetValue(null, null);
449 dpiy = (int)dpiYProperty.GetValue(null, null);
452 protected override void Dispose(bool dispose)
454 base.Dispose(dispose);
455 this.DestructRenderAndResource();
456 this.DestructDevice();