Multi-platform .NET bindings to the Ultralight project.
at master 6.9 kB view raw
1using System; 2using System.IO; 3using System.Runtime.CompilerServices; 4using System.Runtime.InteropServices; 5using UnityEngine; 6using ImpromptuNinjas.UltralightSharp; 7using UltralightSharp.Enums; 8using Unity.Collections.LowLevel.Unsafe; 9using UnityEngine.Experimental.Rendering; 10using Renderer = ImpromptuNinjas.UltralightSharp.Renderer; 11using String = ImpromptuNinjas.UltralightSharp.String; 12 13[RequireComponent(typeof(UnityEngine.Renderer))] 14public class UltralightBrowserDemo : MonoBehaviour { 15 16 [NonSerialized] 17 private unsafe Renderer* _ulRenderer; 18 19 [NonSerialized] 20 private unsafe View* _ulView; 21 22 [NonSerialized] 23 private Texture2D _texture; 24 25 [SerializeField] 26 private string url; 27 28 [NonSerialized] 29 private bool _isDomReady; 30 31 [NonSerialized] 32 private bool _isWindowReady; 33 34 [NonSerialized] 35 private bool _failed; 36 37 [NonSerialized] 38 private bool _isLoaded; 39 40 private bool _willRender; 41 42 public unsafe string Title => _ulView != null ? _ulView->GetTitle()->Read() : null; 43 44 public unsafe bool IsLoading => _ulView != null && _ulView->IsLoading(); 45 46 public bool IsDomReady => _isDomReady; 47 48 public bool IsWindowReady => _isWindowReady; 49 50 public bool Failed => _failed; 51 52 public bool IsLoaded => _isLoaded; 53 54 public bool WillRender => _willRender; 55 56 public unsafe string Url { 57 get => url; 58 set { 59 if (_ulView == null) return; 60 61 url = value; 62 var s = String.Create(value); 63 _ulView->LoadUrl(s); 64 s->Destroy(); 65 } 66 } 67 68 // Start is called before the first frame update 69 unsafe void OnEnable() { 70 var texSize = new Vector2(640, 480); 71 _texture = new Texture2D((int) texSize.x, (int) texSize.y, 72 GraphicsFormat.B8G8R8A8_UNorm, TextureCreationFlags.None) { 73 hideFlags = HideFlags.HideAndDontSave 74 }; 75 var cfg = Config.Create(); 76 77 { 78 var cachePath = String.Create(Path.Combine(Application.streamingAssetsPath, "ultralight", "cache")); 79 cfg->SetCachePath(cachePath); 80 cachePath->Destroy(); 81 } 82 83 { 84 // ReSharper disable once AssignNullToNotNullAttribute 85 var resourcePath = String.Create(Path.Combine(Application.streamingAssetsPath, "ultralight", "resources")); 86 cfg->SetResourcePath(resourcePath); 87 resourcePath->Destroy(); 88 } 89 90 cfg->SetUseGpuRenderer(false); 91 cfg->SetEnableImages(true); 92 cfg->SetEnableJavaScript(false); 93 94 AppCore.EnablePlatformFontLoader(); 95 96 { 97 var assetsPath = String.Create(Path.Combine(Application.streamingAssetsPath, "ultralight", "assets")); 98 AppCore.EnablePlatformFileSystem(assetsPath); 99 assetsPath->Destroy(); 100 } 101 102 _ulRenderer = Renderer.Create(cfg); 103 var sessionName = String.Create("Demo"); 104 var session = Session.Create(_ulRenderer, false, sessionName); 105 106 _ulView = View.Create(_ulRenderer, (uint) texSize.x, (uint) texSize.y, false, session); 107 108 GetComponent<UnityEngine.Renderer>().material.mainTexture = _texture; 109 110 var gch = GCHandle.Alloc(this); 111 var gchPtr = (void*) GCHandle.ToIntPtr(gch); 112 113 _ulView->SetAddConsoleMessageCallback((userData, caller, source, level, msg, lineNumber, columnNumber, sourceId) => { 114 switch (level) { 115 default: 116 Debug.Log($"[Ultralight Console] [{level}] {sourceId->Read()}:{lineNumber}:{columnNumber} {msg->Read()}"); 117 break; 118 case MessageLevel.Error: 119 Debug.LogError($"[Ultralight Console] {sourceId->Read()}:{lineNumber}:{columnNumber} {msg->Read()}"); 120 break; 121 case MessageLevel.Warning: 122 Debug.LogError($"[Ultralight Console] {sourceId->Read()}:{lineNumber}:{columnNumber} {msg->Read()}"); 123 break; 124 } 125 }, gchPtr); 126 127 _ulView->SetDomReadyCallback((userData, caller, id, isMainFrame, readyUrl) => { 128 if (!isMainFrame) 129 return; 130 131 var r = (UltralightBrowserDemo) GCHandle.FromIntPtr((IntPtr) userData).Target; 132 133 r._isDomReady = true; 134 }, gchPtr); 135 136 _ulView->SetFailLoadingCallback((userData, caller, id, isMainFrame, failedUrl, failDesc, errorDomain, errorCode) => { 137 if (!isMainFrame) 138 return; 139 140 var r = (UltralightBrowserDemo) GCHandle.FromIntPtr((IntPtr) userData).Target; 141 142 r._failed = true; 143 r._isLoaded = true; 144 }, gchPtr); 145 146 _ulView->SetFinishLoadingCallback((userData, caller, id, isMainFrame, finishedUrl) => { 147 if (!isMainFrame) 148 return; 149 150 var r = (UltralightBrowserDemo) GCHandle.FromIntPtr((IntPtr) userData).Target; 151 152 r._failed = false; 153 r._isLoaded = true; 154 }, gchPtr); 155 156 _ulView->SetWindowObjectReadyCallback((userData, caller, id, isMainFrame, readyUrl) => { 157 if (!isMainFrame) 158 return; 159 160 var r = (UltralightBrowserDemo) GCHandle.FromIntPtr((IntPtr) userData).Target; 161 162 r._isWindowReady = true; 163 }, gchPtr); 164 165 _ulView->SetChangeUrlCallback((userData, caller, newUrl) => { 166 if (!caller->IsLoading()) 167 return; 168 169 var r = (UltralightBrowserDemo) GCHandle.FromIntPtr((IntPtr) userData).Target; 170 171 r._isDomReady = false; 172 r._failed = false; 173 r._isLoaded = false; 174 r._isWindowReady = false; 175 }, gchPtr); 176 177 Url = url; 178 } 179 180 public unsafe void LoadHtml(string htmlString) { 181 if (_ulView == null) 182 return; 183 184 var s = String.Create(htmlString); 185 _ulView->LoadHtml(s); 186 s->Destroy(); 187 } 188 189 private unsafe void OnDisable() { 190 _ulView->Destroy(); 191 _ulView = null; 192 _ulRenderer->Destroy(); 193 _ulRenderer = null; 194 Destroy(_texture); 195 _texture = null; 196 197 _isDomReady = false; 198 _failed = false; 199 _isLoaded = false; 200 _isWindowReady = false; 201 url = null; 202 } 203 204 public unsafe void OnWillRenderObject() { 205 _willRender = true; 206 if (_ulRenderer == null || _ulView == null || _texture == null) 207 return; 208 209 Ultralight.Update(_ulRenderer); 210 Ultralight.Render(_ulRenderer); 211 212 var surface = _ulView->GetSurface(); 213 var bitmap = surface->GetBitmap(); 214 var pixels = bitmap->LockPixels(); 215 var rawData = _texture.GetRawTextureData<byte>(); 216 var size = Math.Min((uint) rawData.Length, bitmap->GetSize().ToUInt32()); 217 Unsafe.CopyBlockUnaligned(rawData.GetUnsafePtr(), pixels, size); 218 _texture.Apply(); 219 bitmap->UnlockPixels(); 220 } 221 222 private void OnPostRender() 223 => _willRender = false; 224 225 static unsafe UltralightBrowserDemo() { 226 // setup logging 227 LoggerLogMessageCallback cb = LoggerCallback; 228 Ultralight.PlatformSetLogger(new ImpromptuNinjas.UltralightSharp.Logger {LogMessage = cb}); 229 } 230 231 private static unsafe void LoggerCallback(LogLevel logLevel, String* msg) { 232 switch (logLevel) { 233 default: 234 Debug.Log($"[Ultralight] [{logLevel}] {msg->Read()}"); 235 break; 236 case LogLevel.Error: 237 Debug.LogError($"[Ultralight] {msg->Read()}"); 238 break; 239 case LogLevel.Warning: 240 Debug.LogError($"[Ultralight] {msg->Read()}"); 241 break; 242 } 243 } 244 245}