Skip to content

Commit 0af390d

Browse files
committed
Merge branch 'main' into quickjs
2 parents 875e9f5 + 322d105 commit 0af390d

30 files changed

+1401
-54
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
using System;
2+
using ReactUnity.Styling;
3+
using ReactUnity.Styling.Converters;
4+
using ReactUnity.Types;
5+
using ReactUnity.UIToolkit;
6+
using UnityEngine;
7+
using UnityEngine.UIElements;
8+
9+
namespace ReactUnity.UIToolkit
10+
{
11+
public class SvgComponent : UIToolkitComponent<SvgElement>
12+
{
13+
private string content;
14+
15+
private string innerContent;
16+
17+
private object source;
18+
19+
public SvgComponent(UIToolkitContext context, string tag) : base(context, tag)
20+
{
21+
}
22+
23+
public string Content
24+
{
25+
get => content;
26+
set
27+
{
28+
if (source != null && !string.IsNullOrWhiteSpace(value))
29+
throw new InvalidOperationException("Content cannot be set when source is already set");
30+
31+
if (content == value) return;
32+
content = value;
33+
InnerContent = value;
34+
}
35+
}
36+
37+
public string InnerContent
38+
{
39+
get => innerContent;
40+
private set
41+
{
42+
innerContent = value;
43+
RefreshValue();
44+
}
45+
}
46+
47+
public object Source
48+
{
49+
get => source;
50+
set
51+
{
52+
if (source == value) return;
53+
source = value;
54+
SetSource(value);
55+
}
56+
}
57+
58+
public override void SetProperty(string propertyName, object value)
59+
{
60+
switch (propertyName)
61+
{
62+
case "content":
63+
Content = value?.ToString();
64+
break;
65+
case "source":
66+
Source = value;
67+
break;
68+
default:
69+
base.SetProperty(propertyName, value);
70+
break;
71+
}
72+
}
73+
74+
private void SetSource(object value)
75+
{
76+
if (!AllConverters.TextReferenceConverter.TryGetConstantValue(value,
77+
out TextReference reference)) InnerContent = Content;
78+
else
79+
reference?.Get(Context, text => {
80+
if (value != Source) return;
81+
InnerContent = text.text;
82+
FireEvent("onLoad", new { type = "load" });
83+
});
84+
}
85+
86+
protected void RefreshValue()
87+
{
88+
#if !REACT_VECTOR_GRAPHICS
89+
Debug.LogError(
90+
"UnityEngine.VectorGraphics is not enabled, enable this package through REACT_VECTOR_GRAPHICS to allow for svg");
91+
#else
92+
Element.RawSvg = InnerContent;
93+
#endif
94+
}
95+
96+
97+
protected override void ApplyStylesSelf()
98+
{
99+
base.ApplyStylesSelf();
100+
101+
Element.tintColor = ComputedStyle.HasValue(StyleProperties.color)
102+
? ComputedStyle.color
103+
: Color.white;
104+
}
105+
}
106+
}

Runtime/Frameworks/UIToolkit/Components/SvgComponent.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/Frameworks/UIToolkit/General/UIToolkitContext.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public static Dictionary<string, Func<string, string, UIToolkitContext, IReactCo
5151
{ "list", (tag, text, context) => new BindableComponent<ListView>(context, tag) }, // TODO:
5252
{ "imgui", (tag, text, context) => new IMGUIComponent(context) },
5353
{ "template", (tag, text, context) => new BindableComponent<TemplateContainer>(context, tag) },
54+
{ "svg", (tag, text, context) => new SvgComponent(context, tag) },
5455
#if UNITY_2021_2_OR_NEWER
5556
{ "progress", (tag, text, context) => new ValueComponent<ProgressBar, float>(context, tag) },
5657
#endif

Runtime/Frameworks/UIToolkit/ReactUnity.UIToolkit.asmdef

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"references": [
55
"GUID:ed4a920eac98dc342ba18a6baa202849",
66
"GUID:6055be8ebefd69e48b49212b09b47b2f",
7-
"GUID:9a66a2efedc711946b7428ea9b41cc0d"
7+
"GUID:9a66a2efedc711946b7428ea9b41cc0d",
8+
"GUID:68550284b645f4b9894995579f34290a"
89
],
910
"includePlatforms": [],
1011
"excludePlatforms": [],
@@ -26,6 +27,11 @@
2627
"name": "com.unity.textmeshpro",
2728
"expression": "",
2829
"define": "REACT_TMP"
30+
},
31+
{
32+
"name": "com.unity.vectorgraphics",
33+
"expression": "",
34+
"define": "REACT_VECTOR_GRAPHICS"
2935
}
3036
],
3137
"noEngineReferences": false

Runtime/Frameworks/UIToolkit/VisualElements.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Reflection;
5+
using UnityEngine;
6+
using UnityEngine.UIElements;
7+
using Object = UnityEngine.Object;
8+
9+
#if REACT_VECTOR_GRAPHICS
10+
using Unity.VectorGraphics;
11+
#endif
12+
13+
namespace ReactUnity.UIToolkit
14+
{
15+
public class SvgElement : Image
16+
{
17+
protected static readonly string styleName = "TabButtonStyles";
18+
protected static readonly string UxmlName = "Svg";
19+
20+
private static Type _vectorImageUtilsType;
21+
private static MethodInfo _makeVectorImageAsset;
22+
23+
#if REACT_VECTOR_GRAPHICS
24+
#if !UNITY_WEBGL && !UNITY_IOS && !UNITY_IPHONE && !UNITY_WSA && !UNITY_WSA_10_0
25+
private static MakeVectorDelegate _makeVectorHook;
26+
27+
/// <summary>
28+
/// Delegate of MakeVector method
29+
/// </summary>
30+
/// <remarks>This method is not supported on iOS and Web, and needs to fallback to standard reflection</remarks>
31+
delegate void MakeVectorDelegate(List<VectorUtils.Geometry> geometry, uint gradientResolution, out Object asset,
32+
out Texture2D texture2D);
33+
#endif
34+
#endif
35+
36+
[SerializeField]
37+
private string rawSvg;
38+
39+
40+
public SvgElement()
41+
{
42+
}
43+
44+
public SvgElement(string svg)
45+
{
46+
RawSvg = svg;
47+
}
48+
49+
#if REACT_VECTOR_GRAPHICS
50+
/// <summary>
51+
/// Get cacheable type of Unity.VectorGraphics.VectorImageUtils
52+
/// </summary>
53+
private static Type VectorImageUtilsType =>
54+
_vectorImageUtilsType = _vectorImageUtilsType ?? typeof(VectorUtils).Assembly.GetType("Unity.VectorGraphics.VectorImageUtils");
55+
56+
/// <summary>
57+
/// Get cacheable method info of Unity.VectorGraphics.VectorImageUtils.MakeVectorImageAsset(...);
58+
/// </summary>
59+
/// <remarks>
60+
/// Keep all flags just to make sure this call stays relevant even if unity decides someday to expose this method :/
61+
/// </remarks>
62+
private static MethodInfo MakeVectorImageAssetMethodInfo =>
63+
_makeVectorImageAsset = _makeVectorImageAsset ?? VectorImageUtilsType.GetMethod("MakeVectorImageAsset",
64+
BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
65+
66+
#if !UNITY_WEBGL && !UNITY_IOS && !UNITY_IPHONE && !UNITY_WSA && !UNITY_WSA_10_0
67+
/// <summary>
68+
/// Speedup reflection execution by wrapping method inside a delegate
69+
/// </summary>
70+
private static MakeVectorDelegate MakeVectorHook => _makeVectorHook = _makeVectorHook ??
71+
(MakeVectorDelegate) Delegate.CreateDelegate(typeof(MakeVectorDelegate), MakeVectorImageAssetMethodInfo);
72+
#endif
73+
#endif
74+
75+
76+
public string RawSvg
77+
{
78+
get => rawSvg;
79+
set
80+
{
81+
if (rawSvg == value) return;
82+
83+
rawSvg = value;
84+
RebuildSvg();
85+
MarkDirtyRepaint();
86+
}
87+
}
88+
89+
90+
/// <summary>
91+
/// Read svg string and assign background image of current visualElement
92+
/// </summary>
93+
private void RebuildSvg()
94+
{
95+
#if REACT_VECTOR_GRAPHICS
96+
SVGParser.SceneInfo sceneInfo;
97+
using (var stream = new StringReader(RawSvg))
98+
{
99+
sceneInfo = SVGParser.ImportSVG(stream, ViewportOptions.DontPreserve, 0, 1, 100, 100);
100+
}
101+
102+
var stepDist = 0.5f;
103+
float samplingStepDist = 300;
104+
var maxCord = float.MaxValue;
105+
var maxTangent = Mathf.PI * 0.5f;
106+
107+
// Automatically compute sensible tessellation options from the
108+
// vector scene's bouding box and target resolution
109+
//ComputeTessellationOptions(sceneInfo, TargetResolution, ResolutionMultiplier, out stepDist, out maxCord, out maxTangent);
110+
111+
var tessOptions = new VectorUtils.TessellationOptions();
112+
tessOptions.MaxCordDeviation = maxCord;
113+
tessOptions.MaxTanAngleDeviation = maxTangent;
114+
tessOptions.SamplingStepSize = 1.0f / samplingStepDist;
115+
tessOptions.StepDistance = stepDist;
116+
117+
var geometry = VectorUtils.TessellateScene(sceneInfo.Scene, tessOptions, sceneInfo.NodeOpacity);
118+
119+
vectorImage = GenerateVectorImageAsset(geometry);
120+
sourceRect = sceneInfo.SceneViewport;
121+
#else
122+
Debug.LogError(
123+
"Unity.VectorGraphics module is required to use SVG components");
124+
#endif
125+
}
126+
127+
#if REACT_VECTOR_GRAPHICS
128+
/// <summary>
129+
/// Compute tesselation for target resolution instead of relying on predefined values
130+
/// </summary>
131+
/// <param name="sceneInfo"></param>
132+
/// <param name="targetResolution"></param>
133+
/// <param name="multiplier"></param>
134+
/// <param name="stepDist"></param>
135+
/// <param name="maxCord"></param>
136+
/// <param name="maxTangent"></param>
137+
private void ComputeTessellationOptions(SVGParser.SceneInfo sceneInfo, int targetResolution, float multiplier,
138+
out float stepDist, out float maxCord, out float maxTangent)
139+
{
140+
// These tessellation options were found by trial and error to find values that made
141+
// visual sense with a variety of SVG assets.
142+
143+
// "Pixels per Unit" doesn't make sense for UI Toolkit since it will be displayed in
144+
// a pixels space. We adjust the magic values below accordingly.
145+
var ppu = 1.0f;
146+
147+
var bbox = VectorUtils.ApproximateSceneNodeBounds(sceneInfo.Scene.Root);
148+
var maxDim = Mathf.Max(bbox.width, bbox.height) / ppu;
149+
150+
// The scene ratio gives a rough estimate of coverage % of the vector scene on the screen.
151+
// Higher values should result in a more dense tessellation.
152+
var sceneRatio = maxDim / (targetResolution * multiplier);
153+
154+
stepDist = float.MaxValue; // No need for uniform step distance
155+
maxCord = Mathf.Max(0.01f, 2.0f * sceneRatio);
156+
maxTangent = Mathf.Max(0.1f, 3.0f * sceneRatio);
157+
}
158+
159+
160+
/// <summary>
161+
/// Generate Vector Image Asset using reflection
162+
/// </summary>
163+
/// <param name="geometry"></param>
164+
/// <returns></returns>
165+
private VectorImage GenerateVectorImageAsset(List<VectorUtils.Geometry> geometry)
166+
{
167+
var gradientResolution = 64u;
168+
169+
#if !UNITY_WEBGL && !UNITY_IOS && !UNITY_IPHONE && !UNITY_WSA && !UNITY_WSA_10_0
170+
MakeVectorHook(geometry, gradientResolution, out var asset, out _);
171+
#else
172+
object[] vParams = { geometry, gradientResolution, null, null };
173+
MakeVectorImageAssetMethodInfo.Invoke(null, BindingFlags.InvokeMethod, null, vParams, null);
174+
175+
var asset = vParams[2];
176+
#endif
177+
178+
if (asset == null)
179+
{
180+
Debug.LogError("UIElement asset generation failed");
181+
return null;
182+
}
183+
184+
return asset as VectorImage;
185+
}
186+
#endif
187+
188+
new internal class UxmlFactory : UxmlFactory<SvgElement, UxmlTraits>
189+
{
190+
}
191+
192+
new internal class UxmlTraits : VisualElement.UxmlTraits
193+
{
194+
private readonly UxmlStringAttributeDescription Svg = new UxmlStringAttributeDescription { name = "svg" };
195+
196+
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
197+
{
198+
base.Init(ve, bag, cc);
199+
SvgElement item = ve as SvgElement;
200+
201+
item.RawSvg = Svg.GetValueFromBag(bag, cc);
202+
}
203+
}
204+
}
205+
}

Runtime/Frameworks/UIToolkit/VisualElements/SvgElement.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/ReactUnity.asmdef

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@
6464
"name": "Unity",
6565
"expression": "",
6666
"define": "REACT_DISABLE_YANTRA"
67+
},
68+
{
69+
"name": "Unity",
70+
"expression": "2021.2.0a",
71+
"define": "REACT_UITOOLKIT"
6772
}
6873
],
6974
"noEngineReferences": false

Runtime/Yoga/Facebook.Yoga.asmdef

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "Facebook.Yoga",
33
"rootNamespace": "Facebook.Yoga",
4-
"references": [],
4+
"references": ["GUID:343deaaf83e0cee4ca978e7df0b80d21","GUID:2bafac87e7f4b9b418d9448d219b01ab"],
55
"includePlatforms": [],
66
"excludePlatforms": [],
77
"allowUnsafeCode": false,
3.04 KB
Loading

0 commit comments

Comments
 (0)