Skip to content

Commit 3c5f786

Browse files
authored
Merge fcc0cdb into 3a749c0
2 parents 3a749c0 + fcc0cdb commit 3c5f786

File tree

7 files changed

+183
-33
lines changed

7 files changed

+183
-33
lines changed

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)
@@ -135,9 +124,11 @@ namespace CefSharp
135124

136125
if (_legacyBindingEnabled)
137126
{
138-
if (_javascriptObjects->Count > 0 && rootObject != nullptr)
127+
auto values = _javascriptObjectCache->GetCacheValues(browser->GetIdentifier());
128+
129+
if (values->Count > 0 && rootObject != nullptr)
139130
{
140-
rootObject->Bind(_javascriptObjects->Values, context->GetGlobal());
131+
rootObject->Bind(values, context->GetGlobal());
141132
}
142133
}
143134

@@ -147,13 +138,14 @@ namespace CefSharp
147138
auto global = context->GetGlobal();
148139
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
149140
auto processId = System::Diagnostics::Process::GetCurrentProcess()->Id;
141+
auto objectCache = _javascriptObjectCache->GetCache(browser->GetIdentifier());
150142

151143
//TODO: JSB: Split functions into their own classes
152144
//Browser wrapper is only used for BindObjectAsync
153-
auto bindObjAsyncFunction = CefV8Value::CreateFunction(kBindObjectAsync, new BindObjectAsyncHandler(_registerBoundObjectRegistry, _javascriptObjects, browserWrapper));
154-
auto unBindObjFunction = CefV8Value::CreateFunction(kDeleteBoundObject, new RegisterBoundObjectHandler(_javascriptObjects));
155-
auto removeObjectFromCacheFunction = CefV8Value::CreateFunction(kRemoveObjectFromCache, new RegisterBoundObjectHandler(_javascriptObjects));
156-
auto isObjectCachedFunction = CefV8Value::CreateFunction(kIsObjectCached, new RegisterBoundObjectHandler(_javascriptObjects));
145+
auto bindObjAsyncFunction = CefV8Value::CreateFunction(kBindObjectAsync, new BindObjectAsyncHandler(_registerBoundObjectRegistry, objectCache, browserWrapper));
146+
auto unBindObjFunction = CefV8Value::CreateFunction(kDeleteBoundObject, new RegisterBoundObjectHandler(objectCache));
147+
auto removeObjectFromCacheFunction = CefV8Value::CreateFunction(kRemoveObjectFromCache, new RegisterBoundObjectHandler(objectCache));
148+
auto isObjectCachedFunction = CefV8Value::CreateFunction(kIsObjectCached, new RegisterBoundObjectHandler(objectCache));
157149
auto postMessageFunction = CefV8Value::CreateFunction(kPostMessage, new JavascriptPostMessageHandler(rootObject == nullptr ? nullptr : rootObject->CallbackRegistry));
158150
auto promiseHandlerFunction = CefV8Value::CreateFunction(kSendEvalScriptResponse, new JavascriptPromiseHandler());
159151

@@ -627,15 +619,7 @@ namespace CefSharp
627619
auto javascriptObjects = DeserializeJsObjects(argList, 1);
628620

629621
//Caching of JavascriptObjects
630-
//TODO: JSB Should caching be configurable? On a per object basis?
631-
for each (JavascriptObject ^ obj in Enumerable::OfType<JavascriptObject^>(javascriptObjects))
632-
{
633-
if (_javascriptObjects->ContainsKey(obj->JavascriptName))
634-
{
635-
_javascriptObjects->Remove(obj->JavascriptName);
636-
}
637-
_javascriptObjects->Add(obj->JavascriptName, obj);
638-
}
622+
_javascriptObjectCache->InsertOrUpdate(browser->GetIdentifier(), javascriptObjects);
639623

640624
auto rootObject = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
641625

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/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()

CefSharp/Internals/CefSharpArguments.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public static class CefSharpArguments
1010
public const string HostProcessIdArgument = "--host-process-id";
1111
public const string CustomSchemeArgument = "--custom-scheme";
1212
public const string FocusedNodeChangedEnabledArgument = "--focused-node-enabled";
13+
public const string PerBrowserJavaScriptObjectCache = "--jsb-cache-perbrowser";
1314
public const string SubProcessTypeArgument = "--type";
1415
public const string ExitIfParentProcessClosed = "--cefsharpexitsub";
1516
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright © 2023 The CefSharp Authors. All rights reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
4+
5+
using System.Collections.Generic;
6+
7+
namespace CefSharp.Internals
8+
{
9+
/// <summary>
10+
/// Render Process JavaScript Binding (JSB) object cache
11+
/// </summary>
12+
public interface IJavaScriptObjectCache
13+
{
14+
/// <summary>
15+
/// Remove the Browser specific Cache
16+
/// </summary>
17+
/// <param name="browserId">browser Id</param>
18+
void ClearCache(int browserId);
19+
/// <summary>
20+
/// Gets the browser specific cache (dictionary) based on it's Id
21+
/// </summary>
22+
/// <param name="browserId">browser Id</param>
23+
/// <returns>Dictionary of cache <see cref="JavascriptObject"/>'s.</returns>
24+
/// <exception cref="InvalidOperationException"></exception>
25+
Dictionary<string, JavascriptObject> GetCache(int browserId);
26+
/// <summary>
27+
/// Gets a collection of <see cref="JavascriptObject"/>s
28+
/// for the given <paramref name="browserId"/>
29+
/// </summary>
30+
/// <param name="browserId">browser Id</param>
31+
/// <returns>Collection of current bound objects for the browser</returns>
32+
/// <exception cref="InvalidOperationException"></exception>
33+
ICollection<JavascriptObject> GetCacheValues(int browserId);
34+
/// <summary>
35+
/// Insert or Update the <paramref name="javascriptObject"/> within the Cache
36+
/// </summary>
37+
/// <param name="browserId">browser id</param>
38+
/// <param name="javascriptObject">JavaScript object</param>
39+
/// <exception cref="InvalidOperationException"></exception>
40+
void InsertOrUpdate(int browserId, IList<JavascriptObject> javascriptObjects);
41+
}
42+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright © 2023 The CefSharp Authors. All rights reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
4+
5+
using System.Collections.Generic;
6+
7+
namespace CefSharp.Internals
8+
{
9+
/// <summary>
10+
/// Render Process JavaScript Binding (JSB) object cache
11+
/// Legacy Behaviour, objects are cache per process.
12+
/// </summary>
13+
public class LegacyJavaScriptObjectCache : IJavaScriptObjectCache
14+
{
15+
private readonly Dictionary<string, JavascriptObject> cache
16+
= new Dictionary<string, JavascriptObject>();
17+
18+
/// <inheritdoc/>
19+
public void ClearCache(int browserId)
20+
{
21+
// NO OP
22+
}
23+
24+
/// <inheritdoc/>
25+
public void InsertOrUpdate(int browserId, IList<JavascriptObject> javascriptObjects)
26+
{
27+
foreach (var obj in javascriptObjects)
28+
{
29+
cache[obj.Name] = obj;
30+
}
31+
}
32+
33+
/// <inheritdoc/>
34+
public ICollection<JavascriptObject> GetCacheValues(int browserId)
35+
{
36+
return cache.Values;
37+
}
38+
39+
/// <inheritdoc/>
40+
public Dictionary<string, JavascriptObject> GetCache(int browserId)
41+
{
42+
return cache;
43+
}
44+
}
45+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright © 2023 The CefSharp Authors. All rights reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
8+
namespace CefSharp.Internals
9+
{
10+
/// <summary>
11+
/// Render Process JavaScript Binding (JSB) object cache
12+
/// Stores bound objects per CefBrowser.
13+
/// </summary>
14+
public class PerBrowserJavaScriptObjectCache : IJavaScriptObjectCache
15+
{
16+
private readonly Dictionary<int, Dictionary<string, JavascriptObject>> cache
17+
= new Dictionary<int, Dictionary<string, JavascriptObject>>();
18+
19+
/// <inheritdoc/>
20+
public void ClearCache(int browserId)
21+
{
22+
cache.Remove(browserId);
23+
}
24+
25+
/// <inheritdoc/>
26+
public void InsertOrUpdate(int browserId, IList<JavascriptObject> javascriptObjects)
27+
{
28+
var dict = GetCacheInternal(browserId);
29+
30+
foreach (var obj in javascriptObjects)
31+
{
32+
dict[obj.Name] = obj;
33+
}
34+
}
35+
36+
/// <inheritdoc/>
37+
public ICollection<JavascriptObject> GetCacheValues(int browserId)
38+
{
39+
if (cache.TryGetValue(browserId, out var dict))
40+
{
41+
return dict.Values;
42+
}
43+
44+
return new List<JavascriptObject>();
45+
}
46+
47+
/// <inheritdoc/>
48+
public Dictionary<string, JavascriptObject> GetCache(int browserId)
49+
{
50+
var dict = GetCacheInternal(browserId);
51+
52+
return dict;
53+
}
54+
55+
private Dictionary<string, JavascriptObject> GetCacheInternal(int browserId)
56+
{
57+
Dictionary<string, JavascriptObject> dict;
58+
59+
if (!cache.TryGetValue(browserId, out dict))
60+
{
61+
dict = new Dictionary<string, JavascriptObject>();
62+
63+
cache.Add(browserId, dict);
64+
}
65+
66+
return dict;
67+
}
68+
}
69+
}

0 commit comments

Comments
 (0)