Skip to content

Commit df9b49b

Browse files
authored
Merge 1d19085 into c944774
2 parents c944774 + 1d19085 commit df9b49b

11 files changed

+433
-37
lines changed

CefSharp.BrowserSubprocess.Core/BindObjectAsyncHandler.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ namespace CefSharp
2525
{
2626
private:
2727
gcroot<RegisterBoundObjectRegistry^> _callbackRegistry;
28-
gcroot<Dictionary<String^, JavascriptObject^>^> _javascriptObjects;
28+
gcroot<IDictionary<String^, JavascriptObject^>^> _javascriptObjects;
2929
gcroot<CefBrowserWrapper^> _browserWrapper;
3030

3131
public:
32-
BindObjectAsyncHandler(RegisterBoundObjectRegistry^ callbackRegistery, Dictionary<String^, JavascriptObject^>^ javascriptObjects, CefBrowserWrapper^ browserWrapper)
32+
BindObjectAsyncHandler(RegisterBoundObjectRegistry^ callbackRegistery, IDictionary<String^, JavascriptObject^>^ javascriptObjects, CefBrowserWrapper^ browserWrapper)
3333
{
3434
_callbackRegistry = callbackRegistery;
3535
_javascriptObjects = javascriptObjects;

CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,7 @@ namespace CefSharp
8282
{
8383
auto javascriptObjects = DeserializeJsObjects(objects, 0);
8484

85-
for each (JavascriptObject ^ obj in Enumerable::OfType<JavascriptObject^>(javascriptObjects))
86-
{
87-
//Using LegacyBinding with multiple ChromiumWebBrowser instances that share the same
88-
//render process and using LegacyBinding will cause problems for the limited caching implementation
89-
//that exists at the moment, for now we'll remove an object if already exists, same behaviour
90-
//as the new binding method.
91-
//TODO: This should be removed when https://github.com/cefsharp/CefSharp/issues/2306
92-
//Is complete as objects will be stored at the browser level
93-
if (_javascriptObjects->ContainsKey(obj->JavascriptName))
94-
{
95-
_javascriptObjects->Remove(obj->JavascriptName);
96-
}
97-
_javascriptObjects->Add(obj->JavascriptName, obj);
98-
}
85+
_javascriptObjectCache->InsertOrUpdate(browser->GetIdentifier(), javascriptObjects);
9986
}
10087
}
10188

@@ -118,6 +105,8 @@ namespace CefSharp
118105
_onBrowserDestroyed->Invoke(wrapper);
119106
delete wrapper;
120107
}
108+
109+
_javascriptObjectCache->ClearCache(browser->GetIdentifier());
121110
};
122111

123112
void CefAppUnmanagedWrapper::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
@@ -141,9 +130,11 @@ namespace CefSharp
141130

142131
if (_legacyBindingEnabled)
143132
{
144-
if (_javascriptObjects->Count > 0 && rootObject != nullptr)
133+
auto values = _javascriptObjectCache->GetCacheValues(browser->GetIdentifier());
134+
135+
if (values->Count > 0 && rootObject != nullptr)
145136
{
146-
rootObject->Bind(_javascriptObjects->Values, context->GetGlobal());
137+
rootObject->Bind(values, context->GetGlobal());
147138
}
148139
}
149140

@@ -153,13 +144,14 @@ namespace CefSharp
153144
auto global = context->GetGlobal();
154145
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
155146
auto processId = System::Diagnostics::Process::GetCurrentProcess()->Id;
147+
auto objectCache = _javascriptObjectCache->GetCache(browser->GetIdentifier());
156148

157149
//TODO: JSB: Split functions into their own classes
158150
//Browser wrapper is only used for BindObjectAsync
159-
auto bindObjAsyncFunction = CefV8Value::CreateFunction(kBindObjectAsync, new BindObjectAsyncHandler(_registerBoundObjectRegistry, _javascriptObjects, browserWrapper));
160-
auto unBindObjFunction = CefV8Value::CreateFunction(kDeleteBoundObject, new RegisterBoundObjectHandler(_javascriptObjects));
161-
auto removeObjectFromCacheFunction = CefV8Value::CreateFunction(kRemoveObjectFromCache, new RegisterBoundObjectHandler(_javascriptObjects));
162-
auto isObjectCachedFunction = CefV8Value::CreateFunction(kIsObjectCached, new RegisterBoundObjectHandler(_javascriptObjects));
151+
auto bindObjAsyncFunction = CefV8Value::CreateFunction(kBindObjectAsync, new BindObjectAsyncHandler(_registerBoundObjectRegistry, objectCache, browserWrapper));
152+
auto unBindObjFunction = CefV8Value::CreateFunction(kDeleteBoundObject, new RegisterBoundObjectHandler(objectCache));
153+
auto removeObjectFromCacheFunction = CefV8Value::CreateFunction(kRemoveObjectFromCache, new RegisterBoundObjectHandler(objectCache));
154+
auto isObjectCachedFunction = CefV8Value::CreateFunction(kIsObjectCached, new RegisterBoundObjectHandler(objectCache));
163155
auto postMessageFunction = CefV8Value::CreateFunction(kPostMessage, new JavascriptPostMessageHandler(rootObject == nullptr ? nullptr : rootObject->CallbackRegistry));
164156
auto promiseHandlerFunction = CefV8Value::CreateFunction(kSendEvalScriptResponse, new JavascriptPromiseHandler());
165157

@@ -633,15 +625,7 @@ namespace CefSharp
633625
auto javascriptObjects = DeserializeJsObjects(argList, 1);
634626

635627
//Caching of JavascriptObjects
636-
//TODO: JSB Should caching be configurable? On a per object basis?
637-
for each (JavascriptObject ^ obj in Enumerable::OfType<JavascriptObject^>(javascriptObjects))
638-
{
639-
if (_javascriptObjects->ContainsKey(obj->JavascriptName))
640-
{
641-
_javascriptObjects->Remove(obj->JavascriptName);
642-
}
643-
_javascriptObjects->Add(obj->JavascriptName, obj);
644-
}
628+
_javascriptObjectCache->InsertOrUpdate(browser->GetIdentifier(), javascriptObjects);
645629

646630
auto rootObject = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
647631

CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,33 @@ namespace CefSharp
3535
CefString _jsBindingPropertyNameCamelCase;
3636

3737
// The serialized registered object data waiting to be used.
38-
gcroot<Dictionary<String^, JavascriptObject^>^> _javascriptObjects;
38+
gcroot<IJavaScriptObjectCache^> _javascriptObjectCache;
3939

4040
gcroot<RegisterBoundObjectRegistry^> _registerBoundObjectRegistry;
4141

4242
public:
4343
static const CefString kPromiseCreatorScript;
4444

45-
CefAppUnmanagedWrapper(IRenderProcessHandler^ handler, List<CefCustomScheme^>^ schemes, bool enableFocusedNodeChanged, Action<CefBrowserWrapper^>^ onBrowserCreated, Action<CefBrowserWrapper^>^ onBrowserDestroyed) : SubProcessApp(schemes)
45+
CefAppUnmanagedWrapper(IRenderProcessHandler^ handler, List<CefCustomScheme^>^ schemes, bool jsbCachePerBrowser, bool enableFocusedNodeChanged, Action<CefBrowserWrapper^>^ onBrowserCreated, Action<CefBrowserWrapper^>^ onBrowserDestroyed) : SubProcessApp(schemes)
4646
{
4747
_handler = handler;
4848
_onBrowserCreated = onBrowserCreated;
4949
_onBrowserDestroyed = onBrowserDestroyed;
5050
_browserWrappers = gcnew ConcurrentDictionary<int, CefBrowserWrapper^>();
5151
_focusedNodeChangedEnabled = enableFocusedNodeChanged;
52-
_javascriptObjects = gcnew Dictionary<String^, JavascriptObject^>();
5352
_registerBoundObjectRegistry = gcnew RegisterBoundObjectRegistry();
5453
_legacyBindingEnabled = false;
5554
_jsBindingPropertyName = "CefSharp";
5655
_jsBindingPropertyNameCamelCase = "cefSharp";
56+
57+
if (jsbCachePerBrowser)
58+
{
59+
_javascriptObjectCache = gcnew PerBrowserJavaScriptObjectCache();
60+
}
61+
else
62+
{
63+
_javascriptObjectCache = gcnew LegacyJavaScriptObjectCache();
64+
}
5765
}
5866

5967
~CefAppUnmanagedWrapper()

CefSharp.BrowserSubprocess.Core/RegisterBoundObjectHandler.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ namespace CefSharp
2727
private class RegisterBoundObjectHandler : public CefV8Handler
2828
{
2929
private:
30-
gcroot<Dictionary<String^, JavascriptObject^>^> _javascriptObjects;
30+
gcroot<IDictionary<String^, JavascriptObject^>^> _javascriptObjects;
3131

3232
public:
33-
RegisterBoundObjectHandler(Dictionary<String^, JavascriptObject^>^ javascriptObjects)
33+
RegisterBoundObjectHandler(IDictionary<String^, JavascriptObject^>^ javascriptObjects)
3434
{
3535
_javascriptObjects = javascriptObjects;
3636
}

CefSharp.BrowserSubprocess.Core/SubProcess.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ namespace CefSharp
3333
auto onBrowserCreated = gcnew Action<CefBrowserWrapper^>(this, &SubProcess::OnBrowserCreated);
3434
auto onBrowserDestroyed = gcnew Action<CefBrowserWrapper^>(this, &SubProcess::OnBrowserDestroyed);
3535
auto schemes = CefCustomScheme::ParseCommandLineArguments(args);
36+
auto jsbCachePerBrowser = CommandLineArgsParser::HasArgument(args, CefSharpArguments::PerBrowserJavaScriptObjectCache);
3637
auto enableFocusedNodeChanged = CommandLineArgsParser::HasArgument(args, CefSharpArguments::FocusedNodeChangedEnabledArgument);
3738

38-
_cefApp = new CefAppUnmanagedWrapper(handler, schemes, enableFocusedNodeChanged, onBrowserCreated, onBrowserDestroyed);
39+
_cefApp = new CefAppUnmanagedWrapper(handler, schemes, jsbCachePerBrowser, enableFocusedNodeChanged, onBrowserCreated, onBrowserDestroyed);
3940
}
4041

4142
!SubProcess()
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
using System.Collections.Generic;
2+
using CefSharp.Internals;
3+
using Xunit;
4+
5+
namespace CefSharp.Test.JavascriptBinding
6+
{
7+
public class LegacyJavaScriptObjectCacheTests
8+
{
9+
private const int BrowserId = 1;
10+
11+
[Fact]
12+
public void InsertOrUpdateShouldAddObjectsToCache()
13+
{
14+
var cache = new LegacyJavaScriptObjectCache();
15+
var javascriptObjects = new List<JavascriptObject>
16+
{
17+
new JavascriptObject { Name = "Object1" },
18+
new JavascriptObject { Name = "Object2" }
19+
};
20+
21+
cache.InsertOrUpdate(BrowserId, javascriptObjects);
22+
23+
var cachedValues = cache.GetCacheValues(BrowserId);
24+
Assert.Contains(javascriptObjects[0], cachedValues);
25+
Assert.Contains(javascriptObjects[1], cachedValues);
26+
}
27+
28+
[Fact]
29+
public void GetCacheValuesShouldReturnAllCachedObjects()
30+
{
31+
var cache = new LegacyJavaScriptObjectCache();
32+
var javascriptObjects = new List<JavascriptObject>
33+
{
34+
new JavascriptObject { Name = "Object1" },
35+
new JavascriptObject { Name = "Object2" }
36+
};
37+
cache.InsertOrUpdate(BrowserId, javascriptObjects);
38+
39+
var cachedValues = cache.GetCacheValues(BrowserId);
40+
41+
Assert.Equal(2, cachedValues.Count);
42+
}
43+
44+
[Fact]
45+
public void GetCacheShouldReturnUnderlyingDictionary()
46+
{
47+
var cache = new LegacyJavaScriptObjectCache();
48+
var javascriptObjects = new List<JavascriptObject>
49+
{
50+
new JavascriptObject { Name = "Object1" }
51+
};
52+
cache.InsertOrUpdate(BrowserId, javascriptObjects);
53+
54+
var cachedDictionary = cache.GetCache(BrowserId);
55+
56+
Assert.Single(cachedDictionary);
57+
Assert.True(cachedDictionary.ContainsKey("Object1"));
58+
}
59+
60+
[Fact]
61+
public void InsertOrUpdateShouldReplaceExistingObjects()
62+
{
63+
var cache = new LegacyJavaScriptObjectCache();
64+
var initialObjects = new List<JavascriptObject>
65+
{
66+
new JavascriptObject { Name = "Object1" }
67+
};
68+
var updatedObjects = new List<JavascriptObject>
69+
{
70+
new JavascriptObject { Name = "Object1" }
71+
};
72+
cache.InsertOrUpdate(BrowserId, initialObjects);
73+
74+
cache.InsertOrUpdate(BrowserId, updatedObjects);
75+
76+
var cachedValues = cache.GetCacheValues(BrowserId);
77+
Assert.DoesNotContain(initialObjects[0], cachedValues);
78+
Assert.Contains(updatedObjects[0], cachedValues);
79+
}
80+
81+
[Fact]
82+
public void InsertOrUpdateShouldAppendObjectsWithDifferentNames()
83+
{
84+
var cache = new LegacyJavaScriptObjectCache();
85+
var initialObjects = new List<JavascriptObject>
86+
{
87+
new JavascriptObject { Name = "Object1" }
88+
};
89+
var updatedObjects = new List<JavascriptObject>
90+
{
91+
new JavascriptObject { Name = "Object2" }
92+
};
93+
cache.InsertOrUpdate(BrowserId, initialObjects);
94+
95+
cache.InsertOrUpdate(BrowserId, updatedObjects);
96+
97+
var cachedValues = cache.GetCacheValues(BrowserId);
98+
Assert.Contains(initialObjects[0], cachedValues);
99+
Assert.Contains(updatedObjects[0], cachedValues);
100+
}
101+
102+
[Fact]
103+
public void ClearCacheShouldDoNothing()
104+
{
105+
var cache = new LegacyJavaScriptObjectCache();
106+
var javascriptObjects = new List<JavascriptObject>
107+
{
108+
new JavascriptObject { Name = "Object1" }
109+
};
110+
cache.InsertOrUpdate(BrowserId, javascriptObjects);
111+
112+
cache.ClearCache(BrowserId);
113+
114+
var cachedValues = cache.GetCacheValues(BrowserId);
115+
Assert.Contains(javascriptObjects[0], cachedValues);
116+
}
117+
}
118+
}

0 commit comments

Comments
 (0)