Skip to content

Commit ce62574

Browse files
amartya4256fedejeanne
authored andcommitted
Edge:evaluate deadlock fix eclipse-platform#1466
This commit cotributes to replicating the behaviour of Edge:evaluate as it is in WebKit - it must not wait for the execution of script to obtain the result, in case evaluate is called inside a WebView callback. This commit also makes sure that OpenWindowListeners are execute synchronously or asynchronously depending on if the handleNewWindowRequested is called from the evaluate script. Moreover, this enables all the tests which were failing because of Edge:evaluate limitations. contributes to eclipse-platform#1771 and eclipse-platform#1919
1 parent 0fe4a76 commit ce62574

File tree

2 files changed

+28
-11
lines changed

2 files changed

+28
-11
lines changed

bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser/Edge.java

+28-5
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ public WebViewEnvironment(ICoreWebView2Environment environment) {
8181

8282
static boolean inCallback;
8383
boolean inNewWindow;
84+
private boolean inEvaluate;
8485
HashMap<Long, LocationEvent> navigations = new HashMap<>();
8586
private boolean ignoreGotFocus;
8687
private boolean ignoreFocusIn;
@@ -906,11 +907,19 @@ public Object evaluate(String script) throws SWTException {
906907
// Feature in WebView2. ExecuteScript works regardless of IsScriptEnabled setting.
907908
// Disallow programmatic execution manually.
908909
if (!jsEnabled) return null;
909-
910+
if(inCallback) {
911+
execute(script);
912+
return null;
913+
}
910914
String script2 = "(function() {try { " + script + " } catch (e) { return '" + ERROR_ID + "' + e.message; } })();\0";
911915
String[] pJson = new String[1];
912-
int hr = callAndWait(pJson, completion -> webViewProvider.getWebView(true).ExecuteScript(script2.toCharArray(), completion));
913-
if (hr != COM.S_OK) error(SWT.ERROR_FAILED_EVALUATE, hr);
916+
inEvaluate = true;
917+
try {
918+
int hr = callAndWait(pJson, completion -> webViewProvider.getWebView(true).ExecuteScript(script2.toCharArray(), completion));
919+
if (hr != COM.S_OK) error(SWT.ERROR_FAILED_EVALUATE, hr);
920+
} finally {
921+
inEvaluate = false;
922+
}
914923

915924
Object data = JSON.parse(pJson[0]);
916925
if (data instanceof String && ((String) data).startsWith(ERROR_ID)) {
@@ -1319,7 +1328,7 @@ int handleNewWindowRequested(long pView, long pArgs) {
13191328
args.GetDeferral(ppv);
13201329
ICoreWebView2Deferral deferral = new ICoreWebView2Deferral(ppv[0]);
13211330
inNewWindow = true;
1322-
browser.getDisplay().asyncExec(() -> {
1331+
Runnable openWindowHandler = () -> {
13231332
try {
13241333
if (browser.isDisposed()) return;
13251334
WindowEvent openEvent = new WindowEvent(browser);
@@ -1355,7 +1364,21 @@ int handleNewWindowRequested(long pView, long pArgs) {
13551364
args.Release();
13561365
inNewWindow = false;
13571366
}
1358-
});
1367+
};
1368+
1369+
// In case a new window is opened using evaluate with scripts like
1370+
// 'window.open()', there can be a deadlock if we execute the handler
1371+
// asynchronously. And in case a new browser is initialized in the same
1372+
// environment inside an OpenWindowListener of another browser, there can also
1373+
// be a deadlock. Hence, generally it should be run asynchronously. However, a
1374+
// combination of opening a new window from evaluate and starting a new instance
1375+
// of browser inside the OpenWindowListener should be avoided.
1376+
if (inEvaluate) {
1377+
openWindowHandler.run();
1378+
} else {
1379+
browser.getDisplay().asyncExec(openWindowHandler);
1380+
}
1381+
13591382
return COM.S_OK;
13601383
}
13611384

tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java

-6
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,6 @@ public void changed(LocationEvent event) {
745745

746746
@Test
747747
public void test_LocationListener_LocationListener_ordered_changing () {
748-
assumeFalse("Currently broken for Edge", isEdge);
749748
List<String> locations = Collections.synchronizedList(new ArrayList<>());
750749
browser.addLocationListener(changingAdapter(event -> {
751750
locations.add(event.location);
@@ -1578,8 +1577,6 @@ public void completed(ProgressEvent event) {
15781577
*/
15791578
@Test
15801579
public void test_LocationListener_evaluateInCallback() {
1581-
assumeFalse("behavior is not (yet) supported by Edge browser", isEdge);
1582-
15831580
AtomicBoolean changingFinished = new AtomicBoolean(false);
15841581
AtomicBoolean changedFinished = new AtomicBoolean(false);
15851582
browser.addLocationListener(new LocationListener() {
@@ -1628,8 +1625,6 @@ public void changed(LocationEvent event) {
16281625
/** Verify that evaluation works inside an OpenWindowListener */
16291626
@Test
16301627
public void test_OpenWindowListener_evaluateInCallback() {
1631-
assumeFalse("behavior is not (yet) supported by Edge browser", isEdge);
1632-
16331628
AtomicBoolean eventFired = new AtomicBoolean(false);
16341629
browser.addOpenWindowListener(event -> {
16351630
browser.evaluate("SWTopenListener = true");
@@ -2189,7 +2184,6 @@ public void test_evaluate_array_mixedTypes () {
21892184
*/
21902185
@Test
21912186
public void test_BrowserFunction_callback () {
2192-
assumeFalse("Currently broken for Edge", isEdge);
21932187
AtomicBoolean javaCallbackExecuted = new AtomicBoolean(false);
21942188

21952189
class JavascriptCallback extends BrowserFunction { // Note: Local class defined inside method.

0 commit comments

Comments
 (0)