Skip to content

Commit 21c6294

Browse files
amartya4256HeikoKlare
authored andcommitted
Handle local resource references in Edge#setText()
This contribution allows Edge browser for win32 to serve webpages using setText method where the set html may refer to local resources. about:blank doesn't allow referencing local resources and hence, this contribution uses the URL to a temporary file to navigate to and serve the html allowing references to local resources. The temporary URL is not exposed to the clients and the APIs mimic about:blank in all the places where this URL is used to keep the consistency. contributes to #213
1 parent 2592408 commit 21c6294

File tree

2 files changed

+70
-31
lines changed

2 files changed

+70
-31
lines changed

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

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313
*******************************************************************************/
1414
package org.eclipse.swt.browser;
1515

16+
import java.io.*;
1617
import java.net.*;
1718
import java.nio.charset.*;
19+
import java.nio.file.*;
20+
import java.nio.file.Path;
1821
import java.time.*;
1922
import java.util.*;
2023
import java.util.function.*;
@@ -43,6 +46,13 @@ class Edge extends WebBrowser {
4346
static final String DATA_DIR_PROP = "org.eclipse.swt.browser.EdgeDataDir";
4447
static final String LANGUAGE_PROP = "org.eclipse.swt.browser.EdgeLanguage";
4548
static final String VERSIONT_PROP = "org.eclipse.swt.browser.EdgeVersion";
49+
/**
50+
* The URI_FOR_CUSTOM_TEXT_PAGE is the path to a temporary html file which is used
51+
* by Edge browser to navigate to for setting html content in the
52+
* DOM of the browser to enable it to load local resources.
53+
*/
54+
private static final URI URI_FOR_CUSTOM_TEXT_PAGE = setupAndGetLocationForCustomTextPage();
55+
private static final String ABOUT_BLANK = "about:blank";
4656

4757
private record WebViewEnvironment(ICoreWebView2Environment environment, ArrayList<Edge> instances) {
4858
public WebViewEnvironment(ICoreWebView2Environment environment) {
@@ -66,6 +76,8 @@ public WebViewEnvironment(ICoreWebView2Environment environment) {
6676
HashMap<Long, LocationEvent> navigations = new HashMap<>();
6777
private boolean ignoreFocus;
6878

79+
private String lastCustomText;
80+
6981
static {
7082
NativeClearSessions = () -> {
7183
ICoreWebView2CookieManager manager = getCookieManager();
@@ -173,6 +185,18 @@ public WebViewEnvironment(ICoreWebView2Environment environment) {
173185
};
174186
}
175187

188+
private static URI setupAndGetLocationForCustomTextPage() {
189+
URI absolutePath;
190+
try {
191+
Path tempFile = Files.createTempFile("base", ".html");
192+
absolutePath = tempFile.toUri();
193+
tempFile.toFile().deleteOnExit();
194+
} catch (IOException e) {
195+
absolutePath = URI.create(ABOUT_BLANK);
196+
}
197+
return absolutePath;
198+
}
199+
176200
static String wstrToString(long psz, boolean free) {
177201
if (psz == 0) return "";
178202
int len = OS.wcslen(psz);
@@ -447,6 +471,8 @@ public void create(Composite parent, int style) {
447471
handler.Release();
448472
}
449473

474+
addProgressListener(ProgressListener.completedAdapter(__ -> writeToDefaultPathDOM()));
475+
450476
IUnknown hostDisp = newHostObject(this::handleCallJava);
451477
long[] hostObj = { COM.VT_DISPATCH, hostDisp.getAddress(), 0 }; // VARIANT
452478
webView.AddHostObjectToScript("swt\0".toCharArray(), hostObj);
@@ -559,7 +585,11 @@ public String getText() {
559585
public String getUrl() {
560586
long ppsz[] = new long[1];
561587
webView.get_Source(ppsz);
562-
return wstrToString(ppsz[0], true);
588+
return getExposedUrl(wstrToString(ppsz[0], true));
589+
}
590+
591+
private String getExposedUrl(String url) {
592+
return isLocationForCustomText(url) ? ABOUT_BLANK : url;
563593
}
564594

565595
int handleCloseRequested(long pView, long pArgs) {
@@ -625,7 +655,7 @@ int handleNavigationStarting(long pView, long pArgs, boolean top) {
625655
long[] ppszUrl = new long[1];
626656
int hr = args.get_Uri(ppszUrl);
627657
if (hr != COM.S_OK) return hr;
628-
String url = wstrToString(ppszUrl[0], true);
658+
String url = getExposedUrl(wstrToString(ppszUrl[0], true));
629659
long[] pNavId = new long[1];
630660
args.get_NavigationId(pNavId);
631661
LocationEvent event = new LocationEvent(browser);
@@ -666,7 +696,7 @@ int handleSourceChanged(long pView, long pArgs) {
666696
long[] ppsz = new long[1];
667697
int hr = webView.get_Source(ppsz);
668698
if (hr != COM.S_OK) return hr;
669-
String url = wstrToString(ppsz[0], true);
699+
String url = getExposedUrl(wstrToString(ppsz[0], true));
670700
browser.getDisplay().asyncExec(() -> {
671701
if (browser.isDisposed()) return;
672702
LocationEvent event = new LocationEvent(browser);
@@ -954,22 +984,40 @@ public void stop() {
954984
webView.Stop();
955985
}
956986

987+
private boolean isLocationForCustomText(String location) {
988+
try {
989+
return URI_FOR_CUSTOM_TEXT_PAGE.equals(new URI(location));
990+
} catch (URISyntaxException e) {
991+
return false;
992+
}
993+
}
994+
995+
private void writeToDefaultPathDOM() {
996+
if(lastCustomText != null && getUrl().equals(ABOUT_BLANK)) {
997+
boolean test = jsEnabled;
998+
jsEnabled = true;
999+
execute("document.open(); document.write(`" + lastCustomText + "`); document.close();");
1000+
jsEnabled = test;
1001+
this.lastCustomText = null;
1002+
}
1003+
}
1004+
9571005
@Override
9581006
public boolean setText(String html, boolean trusted) {
959-
char[] data = new char[html.length() + 1];
960-
html.getChars(0, html.length(), data, 0);
961-
return webView.NavigateToString(data) == COM.S_OK;
1007+
return setWebpageData(URI_FOR_CUSTOM_TEXT_PAGE.toASCIIString(), null, null, html);
9621008
}
9631009

964-
@Override
965-
public boolean setUrl(String url, String postData, String[] headers) {
1010+
private boolean setWebpageData(String url, String postData, String[] headers, String html) {
9661011
// Feature in WebView2. Partial URLs like "www.example.com" are not accepted.
9671012
// Prepend the protocol if it's missing.
9681013
if (!url.matches("[a-z][a-z0-9+.-]*:.*")) {
9691014
url = "http://" + url;
9701015
}
9711016
int hr;
9721017
char[] pszUrl = stringToWstr(url);
1018+
if(isLocationForCustomText(url)) {
1019+
this.lastCustomText = html;
1020+
}
9731021
if (postData != null || headers != null) {
9741022
if (environment2 == null || webView_2 == null) {
9751023
SWT.error(SWT.ERROR_NOT_IMPLEMENTED, null, " [WebView2 version 88+ is required to set postData and headers]");
@@ -1004,4 +1052,9 @@ public boolean setUrl(String url, String postData, String[] headers) {
10041052
return hr == COM.S_OK;
10051053
}
10061054

1055+
@Override
1056+
public boolean setUrl(String url, String postData, String[] headers) {
1057+
return setWebpageData(url, postData, headers, null);
1058+
}
1059+
10071060
}

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

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,6 @@ public void test_isLocationForCustomText_setUrlAfterDisposedThrowsSwtException()
527527

528528
@Test
529529
public void test_isLocationForCustomText_isSetUrlNotCustomTextUrlAfterSetText() {
530-
assumeFalse("behavior is not (yet) supported by Edge browser", isEdge); // Edge doesn't fire a changed event if the URL is the same as the previous location.
531530
String url = getValidUrl();
532531
AtomicBoolean locationChanged = new AtomicBoolean(false);
533532
browser.addLocationListener(changedAdapter(event -> {
@@ -544,7 +543,6 @@ public void test_isLocationForCustomText_isSetUrlNotCustomTextUrlAfterSetText()
544543

545544
@Test
546545
public void test_isLocationForCustomText_isFirstSetTextURLStillCustomTextUrlAfterSetUrl() {
547-
assumeFalse("behavior is not (yet) supported by Edge browser", isEdge); // Edge doesn't fire a changed event if the URL is the same as the previous location.
548546
AtomicBoolean locationChanged = new AtomicBoolean(false);
549547
browser.addLocationListener(changedAdapter(event -> locationChanged.set(true)));
550548
String url = getValidUrl();
@@ -582,7 +580,6 @@ public void test_isLocationForCustomText_isSetUrlNotCustomTextUrl() {
582580

583581
@Test
584582
public void test_isLocationForCustomText() {
585-
assumeFalse("behavior is not (yet) supported by Edge browser", isEdge); // Edge doesn't fire a changed event if the URL is the same as the previous location.
586583
AtomicBoolean locationChanged = new AtomicBoolean(false);
587584
browser.addLocationListener(changedAdapter(e -> locationChanged.set(true)));
588585
browser.setText("Hello world");
@@ -601,7 +598,6 @@ public void test_LocationListener_changing() {
601598
}
602599
@Test
603600
public void test_LocationListener_changed() {
604-
assumeFalse("behavior is not (yet) supported by Edge browser", isEdge);
605601

606602
AtomicBoolean changedFired = new AtomicBoolean(false);
607603
browser.addLocationListener(changedAdapter(e -> changedFired.set(true)));
@@ -612,8 +608,6 @@ public void test_LocationListener_changed() {
612608
}
613609
@Test
614610
public void test_LocationListener_changingAndOnlyThenChanged() {
615-
assumeFalse("behavior is not (yet) supported by Edge browser", isEdge);
616-
617611
// Test proper order of events.
618612
// Check that 'changed' is only fired after 'changing' has fired at least once.
619613
AtomicBoolean changingFired = new AtomicBoolean(false);
@@ -657,8 +651,6 @@ else if (!changingFired.get())
657651

658652
@Test
659653
public void test_LocationListener_then_ProgressListener() {
660-
assumeFalse("behavior is not (yet) supported by Edge browser", isEdge);
661-
662654
AtomicBoolean locationChanged = new AtomicBoolean(false);
663655
AtomicBoolean progressChanged = new AtomicBoolean(false);
664656
AtomicBoolean progressChangedAfterLocationChanged = new AtomicBoolean(false);
@@ -752,8 +744,6 @@ public void changed(LocationEvent event) {
752744
@Test
753745
/** Ensue that only one changed and one completed event are fired for url changes */
754746
public void test_LocationListener_ProgressListener_noExtraEvents() {
755-
assumeFalse("behavior is not (yet) supported by Edge browser", isEdge);
756-
757747
AtomicInteger changedCount = new AtomicInteger(0);
758748
AtomicInteger completedCount = new AtomicInteger(0);
759749

@@ -860,7 +850,6 @@ public void test_OpenWindowListener_open_ChildPopup() {
860850
/** Validate event order : Child's visibility should come before progress completed event */
861851
@Test
862852
public void test_OpenWindow_Progress_Listener_ValidateEventOrder() {
863-
assumeFalse("behavior is not (yet) supported by Edge browser", isEdge);
864853

865854
AtomicBoolean windowOpenFired = new AtomicBoolean(false);
866855
AtomicBoolean childCompleted = new AtomicBoolean(false);
@@ -1105,7 +1094,6 @@ public void test_TitleListener_event() {
11051094
assertTrue(errMsg, passed);
11061095
}
11071096

1108-
11091097
@Test
11101098
public void test_setText() {
11111099
String expectedTitle = "Website Title";
@@ -1199,16 +1187,16 @@ private void validateTitleChanged(String expectedTitle, Runnable browserSetFunc)
11991187
browserSetFunc.run();
12001188
shell.open();
12011189

1202-
boolean hasFinished = waitForPassCondition(() -> actualTitle.get().length() != 0
1203-
&& !actualTitle.get().contains("about:blank")); // Windows sometimes does 2 loads, one "about:blank", and one actual load.
1204-
boolean passed = hasFinished && actualTitle.get().equals(expectedTitle);
1190+
boolean passed = waitForPassCondition(() -> actualTitle.get().equals(expectedTitle));
12051191
String errMsg = "";
1206-
if (!hasFinished)
1207-
errMsg = "Test timed out. TitleListener not fired";
1208-
else if (!actualTitle.get().equals(expectedTitle)) {
1209-
errMsg = "\nExpected title and actual title do not match."
1210-
+ "\nExpected: " + expectedTitle
1211-
+ "\nActual: " + actualTitle;
1192+
if (!passed) {
1193+
if (actualTitle.get().length() == 0) {
1194+
errMsg = "Test timed out. TitleListener not fired";
1195+
} else {
1196+
errMsg = "\nExpected title and actual title do not match."
1197+
+ "\nExpected: " + expectedTitle
1198+
+ "\nActual: " + actualTitle;
1199+
}
12121200
}
12131201
assertTrue(errMsg + testLog.toString(), passed);
12141202
}
@@ -1328,8 +1316,6 @@ public void completed(ProgressEvent event) {
13281316
*/
13291317
@Test
13301318
public void test_VisibilityWindowListener_eventSize() {
1331-
assumeFalse("behavior is not (yet) supported by Edge browser", isEdge);
1332-
13331319
shell.setSize(200,300);
13341320
AtomicBoolean childCompleted = new AtomicBoolean(false);
13351321
AtomicReference<Point> result = new AtomicReference<>(new Point(0,0));

0 commit comments

Comments
 (0)