WebInterfaceJSScripting.h
3.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Engine/Source/Runtime/WebBrowser/Private/WebJSScripting.h
#pragma once
#include "CoreMinimal.h"
#include "Misc/Guid.h"
#include "WebInterfaceJSFunction.h"
#include "UObject/GCObject.h"
class Error;
/**
* Implements handling of bridging UObjects client side with JavaScript renderer side.
*/
class FWebInterfaceJSScripting
: public FGCObject
{
public:
FWebInterfaceJSScripting(bool bInJSBindingToLoweringEnabled)
: BaseGuid(FGuid::NewGuid())
, bJSBindingToLoweringEnabled(bInJSBindingToLoweringEnabled)
{}
virtual void BindUObject(const FString& Name, UObject* Object, bool bIsPermanent = true) =0;
virtual void UnbindUObject(const FString& Name, UObject* Object = nullptr, bool bIsPermanent = true) =0;
virtual void InvokeJSFunction(FGuid FunctionId, int32 ArgCount, FWebInterfaceJSParam Arguments[], bool bIsError=false) =0;
virtual void InvokeJSErrorResult(FGuid FunctionId, const FString& Error) =0;
FString GetBindingName(const FString& Name, UObject* Object) const
{
return bJSBindingToLoweringEnabled ? Name.ToLower() : Name;
}
FString GetBindingName(const FFieldVariant& Property) const
{
return bJSBindingToLoweringEnabled ? Property.GetName().ToLower() : Property.GetName();
}
public:
// FGCObject API
virtual void AddReferencedObjects( FReferenceCollector& Collector ) override
{
// Ensure bound UObjects are not garbage collected as long as this object is valid.
for (auto& Binding : BoundObjects)
{
Collector.AddReferencedObject(Binding.Key);
}
}
protected:
// Creates a reversible memory addres -> psuedo-guid mapping.
// This is done by xoring the address with the first 64 bits of a base guid owned by the instance.
// Used to identify UObjects from the render process withough exposing internal pointers.
FGuid PtrToGuid(UObject* Ptr)
{
FGuid Guid = BaseGuid;
if (Ptr == nullptr)
{
Guid.Invalidate();
}
else
{
UPTRINT IntPtr = reinterpret_cast<UPTRINT>(Ptr);
if (sizeof(UPTRINT) > 4)
{
Guid[0] ^= (static_cast<uint64>(IntPtr) >> 32);
}
Guid[1] ^= IntPtr & 0xFFFFFFFF;
}
return Guid;
}
// In addition to reversing the mapping, it verifies that we are currently holding on to an instance of that UObject
UObject* GuidToPtr(const FGuid& Guid)
{
UPTRINT IntPtr = 0;
if (sizeof(UPTRINT) > 4)
{
IntPtr = static_cast<UPTRINT>(static_cast<uint64>(Guid[0] ^ BaseGuid[0]) << 32);
}
IntPtr |= (Guid[1] ^ BaseGuid[1]) & 0xFFFFFFFF;
UObject* Result = reinterpret_cast<UObject*>(IntPtr);
if (BoundObjects.Contains(Result))
{
return Result;
}
else
{
return nullptr;
}
}
void RetainBinding(UObject* Object)
{
if (BoundObjects.Contains(Object))
{
if(!BoundObjects[Object].bIsPermanent)
{
BoundObjects[Object].Refcount++;
}
}
else
{
BoundObjects.Add(Object, {false, 1});
}
}
void ReleaseBinding(UObject* Object)
{
if (BoundObjects.Contains(Object))
{
auto& Binding = BoundObjects[Object];
if(!Binding.bIsPermanent)
{
Binding.Refcount--;
if (Binding.Refcount <= 0)
{
BoundObjects.Remove(Object);
}
}
}
}
struct ObjectBinding
{
bool bIsPermanent;
int32 Refcount;
};
/** Private data */
FGuid BaseGuid;
/** UObjects currently visible on the renderer side. */
TMap<UObject*, ObjectBinding> BoundObjects;
/** Reverse lookup for permanent bindings */
TMap<FString, UObject*> PermanentUObjectsByName;
/** The to-lowering option enable for the binding names. */
const bool bJSBindingToLoweringEnabled;
};