Skip to content

Commit 04fe8b2

Browse files
authored
Merge f18c0ff into 6d33757
2 parents 6d33757 + f18c0ff commit 04fe8b2

7 files changed

+183
-33
lines changed

CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp

+13-29
Original file line numberDiff line numberDiff line change
@@ -77,20 +77,7 @@ namespace CefSharp
7777
{
7878
auto javascriptObjects = DeserializeJsObjects(objects, 0);
7979

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

@@ -113,6 +100,8 @@ namespace CefSharp
113100
_onBrowserDestroyed->Invoke(wrapper);
114101
delete wrapper;
115102
}
103+
104+
_javascriptObjectCache->ClearCache(browser->GetIdentifier());
116105
};
117106

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

131120
if (_legacyBindingEnabled)
132121
{
133-
if (_javascriptObjects->Count > 0 && rootObject != nullptr)
122+
auto values = _javascriptObjectCache->GetCacheValues(browser->GetIdentifier());
123+
124+
if (values->Count > 0 && rootObject != nullptr)
134125
{
135-
rootObject->Bind(_javascriptObjects->Values, context->GetGlobal());
126+
rootObject->Bind(values, context->GetGlobal());
136127
}
137128
}
138129

@@ -142,13 +133,14 @@ namespace CefSharp
142133
auto global = context->GetGlobal();
143134
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
144135
auto processId = System::Diagnostics::Process::GetCurrentProcess()->Id;
136+
auto objectCache = _javascriptObjectCache->GetCache(browser->GetIdentifier());
145137

146138
//TODO: JSB: Split functions into their own classes
147139
//Browser wrapper is only used for BindObjectAsync
148-
auto bindObjAsyncFunction = CefV8Value::CreateFunction(kBindObjectAsync, new BindObjectAsyncHandler(_registerBoundObjectRegistry, _javascriptObjects, browserWrapper));
149-
auto unBindObjFunction = CefV8Value::CreateFunction(kDeleteBoundObject, new RegisterBoundObjectHandler(_javascriptObjects));
150-
auto removeObjectFromCacheFunction = CefV8Value::CreateFunction(kRemoveObjectFromCache, new RegisterBoundObjectHandler(_javascriptObjects));
151-
auto isObjectCachedFunction = CefV8Value::CreateFunction(kIsObjectCached, new RegisterBoundObjectHandler(_javascriptObjects));
140+
auto bindObjAsyncFunction = CefV8Value::CreateFunction(kBindObjectAsync, new BindObjectAsyncHandler(_registerBoundObjectRegistry, objectCache, browserWrapper));
141+
auto unBindObjFunction = CefV8Value::CreateFunction(kDeleteBoundObject, new RegisterBoundObjectHandler(objectCache));
142+
auto removeObjectFromCacheFunction = CefV8Value::CreateFunction(kRemoveObjectFromCache, new RegisterBoundObjectHandler(objectCache));
143+
auto isObjectCachedFunction = CefV8Value::CreateFunction(kIsObjectCached, new RegisterBoundObjectHandler(objectCache));
152144
auto postMessageFunction = CefV8Value::CreateFunction(kPostMessage, new JavascriptPostMessageHandler(rootObject == nullptr ? nullptr : rootObject->CallbackRegistry));
153145
auto promiseHandlerFunction = CefV8Value::CreateFunction(kSendEvalScriptResponse, new JavascriptPromiseHandler());
154146

@@ -621,15 +613,7 @@ namespace CefSharp
621613
auto javascriptObjects = DeserializeJsObjects(argList, 1);
622614

623615
//Caching of JavascriptObjects
624-
//TODO: JSB Should caching be configurable? On a per object basis?
625-
for each (JavascriptObject ^ obj in Enumerable::OfType<JavascriptObject^>(javascriptObjects))
626-
{
627-
if (_javascriptObjects->ContainsKey(obj->JavascriptName))
628-
{
629-
_javascriptObjects->Remove(obj->JavascriptName);
630-
}
631-
_javascriptObjects->Add(obj->JavascriptName, obj);
632-
}
616+
_javascriptObjectCache->InsertOrUpdate(browser->GetIdentifier(), javascriptObjects);
633617

634618
auto rootObject = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
635619

CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h

+11-3
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

+2-1
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

+1
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
}
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+
}
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+
}
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)