/* * Copyright (C) 2013 FooProject * * 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 * the Free Software Foundation; either version 3 of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Input; using System.Windows.Interop; using FooEditEngine; using DotNetTextStore; using DotNetTextStore.UnmanagedAPI.TSF; using DotNetTextStore.UnmanagedAPI.WinDef; using SharpDX; using D2D = SharpDX.Direct2D1; using DW = SharpDX.DirectWrite; using D3D11 = SharpDX.Direct3D11; using D3D9 = SharpDX.Direct3D9; using DXGI = SharpDX.DXGI; namespace FooEditEngine.WPF { sealed class D2DRender : D2DRenderCommon, IEditorRender { DotNetTextStore.TextStore store; D3D11.Texture2D texture; DXGI.Surface surface; D3D11.Device device; D3D9.Device device9; D3D9.Surface surface9; double fontSize; FontFamily fontFamily; FontWeight fontWeigth; FontStyle fontStyle; D3DImage imageSource; public D2DRender(FooTextBox textbox, double width, double height, Image image) { this.fontFamily = textbox.FontFamily; this.fontSize = textbox.FontSize; this.fontWeigth = textbox.FontWeight; this.fontStyle = textbox.FontStyle; this.Foreground = ToColor4(textbox.Foreground); this.Background = ToColor4(textbox.Background); this.ControlChar = ToColor4(textbox.ControlChar); this.Hilight = ToColor4(textbox.Hilight); this.Comment = ToColor4(textbox.Comment); this.Url = ToColor4(textbox.URL); this.Keyword1 = ToColor4(textbox.Keyword1); this.Keyword2 = ToColor4(textbox.Keyword2); this.Literal = ToColor4(textbox.Literal); this.InsertCaret = ToColor4(textbox.InsertCaret); this.OverwriteCaret = ToColor4(textbox.OverwriteCaret); this.LineMarker = ToColor4(textbox.LineMarker); this.UpdateArea = ToColor4(textbox.UpdateArea); this.LineNumber = ToColor4(textbox.LineNumber); this.HilightForeground = ToColor4(textbox.HilightForeground); this.store = textbox.TextStore; this.CreateDevice(); this.ConstructRenderAndResource(width, height); this.InitTextFormat(this.fontFamily.Source, (float)this.fontSize, this.GetDWFontWeigth(this.fontWeigth), this.GetDWFontStyle(this.fontStyle)); this.imageSource = new D3DImage(); this.imageSource.Lock(); this.imageSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, this.surface9.NativePointer); //設定しないとロード時に例外が発生する this.imageSource.Unlock(); image.Source = this.imageSource; } public FontFamily FontFamily { get { return this.fontFamily; } set { this.fontFamily = value; this.InitTextFormat(this.fontFamily.Source, (float)this.fontSize, this.GetDWFontWeigth(this.fontWeigth), this.GetDWFontStyle(this.fontStyle)); this.TabWidthChar = this.TabWidthChar; } } public double FontSize { get { return this.fontSize; } set { this.fontSize = value; this.InitTextFormat(this.fontFamily.Source, (float)value, this.GetDWFontWeigth(this.fontWeigth), this.GetDWFontStyle(this.fontStyle)); this.TabWidthChar = this.TabWidthChar; } } public FontWeight FontWeigth { get { return this.fontWeigth; } set { this.fontWeigth = value; this.InitTextFormat(this.fontFamily.Source, (float)this.fontSize, this.GetDWFontWeigth(value), this.GetDWFontStyle(this.fontStyle)); } } public FontStyle FontStyle { get { return this.fontStyle; } set { this.fontStyle = value; this.InitTextFormat(this.fontFamily.Source, (float)this.fontSize, this.GetDWFontWeigth(this.fontWeigth), this.GetDWFontStyle(this.fontStyle)); } } public static Color4 ToColor4(System.Windows.Media.Color color) { return new Color4(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, color.A / 255.0f); } public bool Resize(double width, double height) { if (Math.Floor(width) != Math.Floor(this.imageSource.Width) || Math.Floor(height) != Math.Floor(this.imageSource.Height)) { this.ReConstructRenderAndResource(width, height); this.imageSource.Lock(); this.imageSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, this.surface9.NativePointer); this.imageSource.Unlock(); return true; } return false; } public void ReConstructRenderAndResource(double width, double height) { this.DestructRenderAndResource(); this.ConstructRenderAndResource(width, height); } public void DrawContent(EditView view, bool IsEnabled, Rectangle updateRect) { if (this.imageSource.IsFrontBufferAvailable) { this.imageSource.Lock(); this.imageSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, this.surface9.NativePointer); base.BegineDraw(); if (IsEnabled) view.Draw(updateRect); else this.FillBackground(updateRect); base.EndDraw(); this.device.ImmediateContext.Flush(); this.imageSource.AddDirtyRect(new Int32Rect(0, 0, (int)this.imageSource.PixelWidth, (int)this.imageSource.PixelHeight)); this.imageSource.Unlock(); } } public void DrawOneLine(Document doc, LineToIndexTable lti, int row, double x, double y) { PreDrawOneLineHandler PreDrawOneLine = null; if (InputMethod.Current.ImeState == InputMethodState.On) PreDrawOneLine = this.DrawImeConversionLine; base.DrawOneLine(doc, lti, row, x, y, PreDrawOneLine ); } private void DrawImeConversionLine(MyTextLayout layout, LineToIndexTable lti, int row, double x, double y) { using (Unlocker locker = this.store.LockDocument(false)) { int lineIndex = lti.GetIndexFromLineNumber(row); int lineLength = lti.GetLengthFromLineNumber(row); foreach (TextDisplayAttribute attr in this.store.EnumAttributes(lineIndex, lineIndex + lineLength)) { if (attr.startIndex == attr.endIndex) continue; int length = attr.endIndex - attr.startIndex; int start = attr.startIndex - lineIndex; HilightType type = HilightType.None; Color4? color = null; switch (attr.attribute.lsStyle) { case TF_DA_LINESTYLE.TF_LS_DOT: type = HilightType.Dot; color = this.GetColor4(attr.attribute.crLine); break; case TF_DA_LINESTYLE.TF_LS_SOLID: type = HilightType.Sold; color = this.GetColor4(attr.attribute.crLine); break; case TF_DA_LINESTYLE.TF_LS_DASH: type = HilightType.Dash; color = this.GetColor4(attr.attribute.crLine); break; case TF_DA_LINESTYLE.TF_LS_SQUIGGLE: type = HilightType.Squiggle; color = this.GetColor4(attr.attribute.crLine); break; } if (attr.attribute.crBk.type != TF_DA_COLORTYPE.TF_CT_NONE) { type = HilightType.Select; color = this.GetColor4(attr.attribute.crBk); } this.DrawMarkerEffect(layout, type, start, length, x, y, attr.attribute.fBoldLine, color); color = this.GetColor4(attr.attribute.crText); if (color != null) { this.SetTextColor(layout, start, length, color); layout.Invaild = true; } } } } private Color4? GetColor4(TF_DA_COLOR cr) { COLORREF colorref; switch (cr.type) { case TF_DA_COLORTYPE.TF_CT_SYSCOLOR: colorref = new COLORREF(NativeMethods.GetSysColor((int)cr.indexOrColorRef)); break; case TF_DA_COLORTYPE.TF_CT_COLORREF: colorref = new COLORREF(cr.indexOrColorRef); break; default: return null; } return new Color4(colorref.R / 255.0f, colorref.G / 255.0f, colorref.B / 255.0f, 1); } DW.FontStyle GetDWFontStyle(FontStyle style) { return (DW.FontStyle)Enum.Parse(typeof(DW.FontStyle), style.ToString()); } DW.FontWeight GetDWFontWeigth(FontWeight weigth) { return (DW.FontWeight)Enum.Parse(typeof(DW.FontWeight), weigth.ToString()); } public override void DrawCachedBitmap(Rectangle rect) { if (this.render == null || this.render.IsDisposed || this.cachedBitMap == null || this.cachedBitMap.IsDisposed) return; render.DrawBitmap(this.cachedBitMap, rect, 1.0f, D2D.BitmapInterpolationMode.Linear, rect); } public override void CacheContent() { if (this.render == null || this.cachedBitMap == null || this.cachedBitMap.IsDisposed || this.render.IsDisposed) return; render.Flush(); this.cachedBitMap.CopyFromRenderTarget(this.render, new SharpDX.Point(), new SharpDX.Rectangle(0, 0, (int)this.renderSize.Width, (int)this.renderSize.Height)); this.hasCache = true; } void CreateDevice() { SharpDX.Direct3D.FeatureLevel[] levels = new SharpDX.Direct3D.FeatureLevel[]{ SharpDX.Direct3D.FeatureLevel.Level_11_0, SharpDX.Direct3D.FeatureLevel.Level_10_1, SharpDX.Direct3D.FeatureLevel.Level_10_0, SharpDX.Direct3D.FeatureLevel.Level_9_3, SharpDX.Direct3D.FeatureLevel.Level_9_2, SharpDX.Direct3D.FeatureLevel.Level_9_1}; foreach (var level in levels) { try { this.device = new D3D11.Device(SharpDX.Direct3D.DriverType.Hardware, D3D11.DeviceCreationFlags.BgraSupport, level); break; } catch { continue; } } if (this.device == null) throw new PlatformNotSupportedException("DirectX10デバイスの作成に失敗しました"); IntPtr DesktopWnd = NativeMethods.GetDesktopWindow(); D3D9.Direct3DEx d3dex = new D3D9.Direct3DEx(); D3D9.PresentParameters param = new D3D9.PresentParameters(); param.Windowed = true; param.SwapEffect = D3D9.SwapEffect.Discard; param.DeviceWindowHandle = DesktopWnd; param.PresentationInterval = D3D9.PresentInterval.Default; try { this.device9 = new D3D9.DeviceEx( d3dex, 0, D3D9.DeviceType.Hardware, DesktopWnd, D3D9.CreateFlags.HardwareVertexProcessing | D3D9.CreateFlags.Multithreaded | D3D9.CreateFlags.FpuPreserve, param); } catch { try { this.device9 = new D3D9.DeviceEx( d3dex, 0, D3D9.DeviceType.Hardware, DesktopWnd, D3D9.CreateFlags.SoftwareVertexProcessing | D3D9.CreateFlags.Multithreaded | D3D9.CreateFlags.FpuPreserve, param); } catch { throw new PlatformNotSupportedException("DirectX9デバイスの作成に失敗しました"); } } finally { d3dex.Dispose(); } } void DestructDevice() { if (this.device != null) { this.device.Dispose(); this.device = null; } if (this.device9 != null) { this.device9.Dispose(); this.device9 = null; } } public void ConstructRenderAndResource(double width, double height) { float dpiX, dpiY; this.GetDpi(out dpiX, out dpiY); D2D.RenderTargetProperties prop = new D2D.RenderTargetProperties( D2D.RenderTargetType.Default, new D2D.PixelFormat(DXGI.Format.B8G8R8A8_UNorm, D2D.AlphaMode.Premultiplied), dpiX, dpiY, D2D.RenderTargetUsage.None, D2D.FeatureLevel.Level_DEFAULT); D3D11.Texture2DDescription desc = new D3D11.Texture2DDescription(); desc.Width = (int)width; desc.Height = (int)height; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = DXGI.Format.B8G8R8A8_UNorm; desc.SampleDescription = new DXGI.SampleDescription(1, 0); desc.Usage = D3D11.ResourceUsage.Default; desc.BindFlags = D3D11.BindFlags.RenderTarget | D3D11.BindFlags.ShaderResource; desc.CpuAccessFlags = D3D11.CpuAccessFlags.None; desc.OptionFlags = D3D11.ResourceOptionFlags.Shared; this.texture = new D3D11.Texture2D(this.device, desc); this.surface = this.texture.QueryInterface(); DXGI.Resource resource = this.texture.QueryInterface(); IntPtr handel = resource.SharedHandle; D3D9.Texture texture = new D3D9.Texture( this.device9, this.texture.Description.Width, this.texture.Description.Height, 1, D3D9.Usage.RenderTarget, D3D9.Format.A8R8G8B8, D3D9.Pool.Default, ref handel); this.surface9 = texture.GetSurfaceLevel(0); resource.Dispose(); texture.Dispose(); this.render = new D2D.RenderTarget(D2DRenderShared.D2DFactory, this.surface, prop); D2D.BitmapProperties bmpProp = new D2D.BitmapProperties(); bmpProp.DpiX = dpiX; bmpProp.DpiY = dpiY; bmpProp.PixelFormat = new D2D.PixelFormat(DXGI.Format.B8G8R8A8_UNorm, D2D.AlphaMode.Premultiplied); this.cachedBitMap = new D2D.Bitmap(this.render, new SharpDX.Size2((int)width, (int)height), bmpProp); this.hasCache = false; this.textRender = new CustomTextRenderer(this.Brushes, this.Strokes, this.Foreground); this.renderSize = new Size(width, height); } public void DestructRenderAndResource() { this.hasCache = false; if (this.cachedBitMap != null) this.cachedBitMap.Dispose(); this.Brushes.Clear(); this.Strokes.Clear(); if (this.textRender != null) this.textRender.Dispose(); if (this.texture != null) this.texture.Dispose(); if (this.surface != null) this.surface.Dispose(); if (this.surface9 != null) this.surface9.Dispose(); if (this.render != null) this.render.Dispose(); } public override void GetDpi(out float dpix, out float dpiy) { var dpiXProperty = typeof(SystemParameters).GetProperty("DpiX", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); var dpiYProperty = typeof(SystemParameters).GetProperty("Dpi", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); dpix = (int)dpiXProperty.GetValue(null, null); dpiy = (int)dpiYProperty.GetValue(null, null); } protected override void Dispose(bool dispose) { base.Dispose(dispose); this.DestructRenderAndResource(); this.DestructDevice(); } } }