Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ namespace CefSharp
}
}
}

_jsBindingPropertyName = extraInfo->GetString("JsBindingPropertyName");
_jsBindingPropertyNameCamelCase = extraInfo->GetString("JsBindingPropertyNameCamelCase");
}

void CefAppUnmanagedWrapper::OnBrowserDestroyed(CefRefPtr<CefBrowser> browser)
Expand Down Expand Up @@ -123,13 +126,6 @@ namespace CefSharp
auto global = context->GetGlobal();
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());

auto cefSharpObj = CefV8Value::CreateObject(NULL, NULL);
global->SetValue("CefSharp", cefSharpObj, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);

//We'll support both CefSharp and cefSharp, for those who prefer the JS style
auto cefSharpObjCamelCase = CefV8Value::CreateObject(NULL, NULL);
global->SetValue("cefSharp", cefSharpObjCamelCase, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);

//TODO: JSB: Split functions into their own classes
//Browser wrapper is only used for BindObjectAsync
auto bindObjAsyncFunction = CefV8Value::CreateFunction(kBindObjectAsync, new BindObjectAsyncHandler(_registerBoundObjectRegistry, _javascriptObjects, browserWrapper));
Expand All @@ -138,11 +134,21 @@ namespace CefSharp
auto isObjectCachedFunction = CefV8Value::CreateFunction(kIsObjectCached, new RegisterBoundObjectHandler(_javascriptObjects));
auto postMessageFunction = CefV8Value::CreateFunction(kPostMessage, new JavascriptPostMessageHandler(rootObject == nullptr ? nullptr : rootObject->CallbackRegistry));

cefSharpObj->SetValue(kBindObjectAsync, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kDeleteBoundObject, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kRemoveObjectFromCache, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kIsObjectCached, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kPostMessage, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
if (!_jsBindingPropertyName.empty())
{
auto cefSharpObj = CefV8Value::CreateObject(NULL, NULL);
global->SetValue(_jsBindingPropertyName, cefSharpObj, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);

cefSharpObj->SetValue(kBindObjectAsync, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kDeleteBoundObject, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kRemoveObjectFromCache, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kIsObjectCached, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kPostMessage, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
}

//We'll support both CefSharp and cefSharp, for those who prefer the JS style
auto cefSharpObjCamelCase = CefV8Value::CreateObject(NULL, NULL);
global->SetValue(_jsBindingPropertyNameCamelCase, cefSharpObjCamelCase, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);

cefSharpObjCamelCase->SetValue(kBindObjectAsyncCamelCase, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kDeleteBoundObjectCamelCase, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
Expand Down
4 changes: 4 additions & 0 deletions CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ namespace CefSharp
bool _focusedNodeChangedEnabled;
bool _legacyBindingEnabled;

// The property names used to call binded objects
CefString _jsBindingPropertyName;
CefString _jsBindingPropertyNameCamelCase;

// The serialized registered object data waiting to be used.
gcroot<Dictionary<String^, JavascriptObject^>^> _javascriptObjects;

Expand Down
22 changes: 21 additions & 1 deletion CefSharp.Core/ManagedCefBrowserAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ void ManagedCefBrowserAdapter::CreateBrowser(IWindowInfo^ windowInfo, BrowserSet

legacyBindingEnabled = objectRepository->HasBoundObjects;

//For legacy binding we only add values if we have bond objects
//For legacy binding we only add values if we have bond objects.
if (legacyBindingEnabled)
{
auto listValue = CefListValue::Create();
Expand All @@ -61,6 +61,26 @@ void ManagedCefBrowserAdapter::CreateBrowser(IWindowInfo^ windowInfo, BrowserSet

extraInfo->SetBool("LegacyBindingEnabled", legacyBindingEnabled);

// Retrieve the configurable binding property names, throw exception if empty or illegal characters
auto jsBindingPropertyName = _javaScriptObjectRepository->Settings->WindowPropertyName;
if (!StringCheck::EnsureLettersAndNumbers(jsBindingPropertyName))
{
throw gcnew InvalidOperationException("CefBrowserHost::CreateBrowser invalid or illegal characters used for binding property names. Alphanumeric and underscores characters only.");
}

if (_javaScriptObjectRepository->Settings->IsWindowPropertyNameCamelCase())
{
extraInfo->SetString("JsBindingPropertyNameCamelCase", StringUtils::ToNative(jsBindingPropertyName));
}
else
{
extraInfo->SetString("JsBindingPropertyName", StringUtils::ToNative(jsBindingPropertyName));

// Convert to camelCase
auto camelCasePropertyName = _javaScriptObjectRepository->ConvertStringToCamelCase(jsBindingPropertyName);
extraInfo->SetString("JsBindingPropertyNameCamelCase", StringUtils::ToNative(camelCasePropertyName));
}

if (!CefBrowserHost::CreateBrowser(*cefWindowInfoWrapper->GetWindowInfo(), _clientAdapter.get(), addressNative,
*browserSettings->_browserSettings, extraInfo, static_cast<CefRefPtr<CefRequestContext>>(requestContext)))
{
Expand Down
2 changes: 2 additions & 0 deletions CefSharp/CefSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
<Compile Include="DefaultApp.cs" />
<Compile Include="Enums\SchemeOptions.cs" />
<Compile Include="Internals\IBrowserRefCounter.cs" />
<Compile Include="Internals\JavascriptObjectRepositorySettings.cs" />
<Compile Include="Internals\MimeTypeMapping.cs" />
<Compile Include="Internals\NoOpBrowserRefCounter.cs" />
<Compile Include="Internals\PathCheck.cs" />
Expand All @@ -112,6 +113,7 @@
<Compile Include="Internals\CookieManagerDecorator.cs" />
<Compile Include="Internals\ParentProcessMonitor.cs" />
<Compile Include="Internals\HeaderNameValueCollection.cs" />
<Compile Include="Internals\StringCheck.cs" />
<Compile Include="Internals\TaskScheduler\LimitedConcurrencyLevelTaskScheduler.cs" />
<Compile Include="IUrlRequest.cs" />
<Compile Include="IUrlRequestClient.cs" />
Expand Down
2 changes: 2 additions & 0 deletions CefSharp/IJavascriptObjectRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System;
using CefSharp.Event;
using CefSharp.Internals;

namespace CefSharp
{
Expand All @@ -13,6 +14,7 @@ namespace CefSharp
/// </summary>
public interface IJavascriptObjectRepository : IDisposable
{
JavascriptObjectRepositorySettings Settings { get; }
/// <summary>
/// Register an object for binding in Javascript. You can either
/// register an object in advance or as part of the <see cref="ResolveObject"/>
Expand Down
15 changes: 15 additions & 0 deletions CefSharp/Internals/JavascriptObjectRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ public bool HasBoundObjects
get { return objects.Count > 0; }
}

/// <summary>
/// Configurable settings for this repository, such as setting the property name CefSharp injects into the window.
/// </summary>
public JavascriptObjectRepositorySettings Settings { get; }

public JavascriptObjectRepository()
{
Settings = new JavascriptObjectRepositorySettings();
}

public bool IsBound(string name)
{
return objects.Values.Any(x => x.Name == name);
Expand Down Expand Up @@ -540,6 +550,11 @@ private static string GetJavascriptName(string str, bool camelCaseJavascriptName
return str;
}

return ConvertStringToCamelCase(str);
}

public static string ConvertStringToCamelCase(string str)
{
if (string.IsNullOrEmpty(str))
{
return string.Empty;
Expand Down
21 changes: 21 additions & 0 deletions CefSharp/Internals/JavascriptObjectRepositorySettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright © 2020 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

namespace CefSharp.Internals
{
public class JavascriptObjectRepositorySettings
{
public string WindowPropertyName { get; set; }

public JavascriptObjectRepositorySettings()
{
WindowPropertyName = "CefSharp";
}

public bool IsWindowPropertyNameCamelCase()
{
return StringCheck.IsFirstCharacterLowercase(WindowPropertyName);
}
}
}
39 changes: 39 additions & 0 deletions CefSharp/Internals/StringCheck.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright © 2020 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

using System.Text.RegularExpressions;

namespace CefSharp.Internals
{
public static class StringCheck
{
/// <summary>
/// Regex check to ensure string contains only letters, numbers and underscores.
/// </summary>
/// <param name="stringToCheck"></param>
/// <returns></returns>
public static bool EnsureLettersAndNumbers(string stringToCheck)
{
if (!string.IsNullOrWhiteSpace(stringToCheck))
{
return Regex.IsMatch(stringToCheck, @"^\w+$");
}

return false;
}

public static bool IsFirstCharacterLowercase(string str)
{
if (!string.IsNullOrEmpty(str))
{
if (char.IsLetter(str[0]))
{
return char.IsLower(str[0]);
}
}

return false;
}
}
}