diff --git a/.idea/libraries/jcef.xml b/.idea/libraries/jcef.xml
index d881e46aca0b..f7133d54c689 100644
--- a/.idea/libraries/jcef.xml
+++ b/.idea/libraries/jcef.xml
@@ -1,12 +1,12 @@
-
+
-
+
-
+
\ No newline at end of file
diff --git a/platform/platform-api/src/com/intellij/ui/jcef/JBCefApp.java b/platform/platform-api/src/com/intellij/ui/jcef/JBCefApp.java
index 2b58a92dde82..bb96de044ff6 100644
--- a/platform/platform-api/src/com/intellij/ui/jcef/JBCefApp.java
+++ b/platform/platform-api/src/com/intellij/ui/jcef/JBCefApp.java
@@ -34,6 +34,7 @@ import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.intellij.ui.jcef.JBCefFileSchemeHandler.FILE_SCHEME_NAME;
+import static com.intellij.ui.jcef.JBCefHtmlStringSchemeHandler.HTML_STRING_SCHEME_NAME;
/**
* A wrapper over {@link CefApp}.
@@ -60,7 +61,7 @@ public abstract class JBCefApp {
private static final List ourSchemeHandlerFactoryList = Collections.synchronizedList(new ArrayList<>());
private JBCefApp() {
- CefApp.startup();
+ CefApp.startup(ArrayUtil.EMPTY_STRING_ARRAY);
//noinspection AbstractMethodCallInConstructor
CefAppConfig config = getCefAppConfig();
config.mySettings.windowless_rendering_enabled = false;
@@ -176,19 +177,20 @@ public abstract class JBCefApp {
@Override
protected CefAppConfig getCefAppConfig() {
String ALT_CEF_FRAMEWORK_DIR = System.getenv("ALT_CEF_FRAMEWORK_DIR");
- String ALT_CEF_BROWSER_SUBPROCESS = System.getenv("ALT_CEF_BROWSER_SUBPROCESS");
- if (ALT_CEF_FRAMEWORK_DIR == null || ALT_CEF_BROWSER_SUBPROCESS == null) {
+ String ALT_CEF_HELPER_APP_DIR = System.getenv("ALT_CEF_HELPER_APP_DIR");
+ if (ALT_CEF_FRAMEWORK_DIR == null || ALT_CEF_HELPER_APP_DIR == null) {
String CONTENTS_PATH = System.getProperty("java.home") + "/..";
if (ALT_CEF_FRAMEWORK_DIR == null) {
ALT_CEF_FRAMEWORK_DIR = CONTENTS_PATH + "/Frameworks/Chromium Embedded Framework.framework";
}
- if (ALT_CEF_BROWSER_SUBPROCESS == null) {
- ALT_CEF_BROWSER_SUBPROCESS = CONTENTS_PATH + "/Helpers/jcef Helper.app/Contents/MacOS/jcef Helper";
+ if (ALT_CEF_HELPER_APP_DIR == null) {
+ ALT_CEF_HELPER_APP_DIR = CONTENTS_PATH + "/Frameworks/jcef Helper.app";
}
}
return new CefAppConfig(new CefSettings(), new String[] {
"--framework-dir-path=" + normalize(ALT_CEF_FRAMEWORK_DIR),
- "--browser-subprocess-path=" + normalize(ALT_CEF_BROWSER_SUBPROCESS),
+ "--browser-subprocess-path=" + normalize(ALT_CEF_HELPER_APP_DIR + "/Contents/MacOS/jcef Helper"),
+ "--main-bundle-path=" + normalize(ALT_CEF_HELPER_APP_DIR),
"--disable-in-process-stack-traces",
"--use-mock-keychain"
});
@@ -296,6 +298,13 @@ public abstract class JBCefApp {
return FILE_SCHEME_NAME.equals(schemeName) ? new JBCefFileSchemeHandler(browser, frame) : null;
}
});
+
+ getInstance().myCefApp.registerSchemeHandlerFactory(HTML_STRING_SCHEME_NAME, "", new CefSchemeHandlerFactory() {
+ @Override
+ public CefResourceHandler create(CefBrowser browser, CefFrame frame, String schemeName, CefRequest request) {
+ return HTML_STRING_SCHEME_NAME.equals(schemeName) ? new JBCefHtmlStringSchemeHandler(browser, frame) : null;
+ }
+ });
}
}
}
diff --git a/platform/platform-api/src/com/intellij/ui/jcef/JBCefBrowser.java b/platform/platform-api/src/com/intellij/ui/jcef/JBCefBrowser.java
index 4dc31d0e6882..e9b42798bf7a 100644
--- a/platform/platform-api/src/com/intellij/ui/jcef/JBCefBrowser.java
+++ b/platform/platform-api/src/com/intellij/ui/jcef/JBCefBrowser.java
@@ -11,7 +11,6 @@ import org.cef.callback.CefMenuModel;
import org.cef.handler.*;
import org.cef.network.CefCookieManager;
import org.jetbrains.annotations.ApiStatus;
-import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -35,6 +34,9 @@ import static org.cef.callback.CefMenuModel.MenuId.MENU_ID_USER_LAST;
public class JBCefBrowser implements JBCefDisposable {
private static final String BLANK_URI = "about:blank";
+ private static final String JBCEFBROWSER_INSTANCE_PROP = "JBCefBrowser.instance";
+ private static final String HTML_STRING_URL = JBCefHtmlStringSchemeHandler.HTML_STRING_SCHEME_NAME + "://jbcefbrowser/loadstring";
+
@NotNull private final JBCefClient myCefClient;
@NotNull private final MyComponent myComponent;
@NotNull private final CefBrowser myCefBrowser;
@@ -74,7 +76,7 @@ public class JBCefBrowser implements JBCefDisposable {
SwingUtilities.invokeLater(
myHtml == null ?
() -> browser.loadURL(myUrl) :
- () -> browser.loadString(myHtml, myUrl));
+ () -> loadString(browser, myHtml, myUrl));
}
}
@@ -105,7 +107,9 @@ public class JBCefBrowser implements JBCefDisposable {
myCefBrowser = cefBrowser != null ?
cefBrowser : myCefClient.getCefClient().createBrowser(url != null ? url : BLANK_URI, false, false);
- myComponent.add(myCefBrowser.getUIComponent(), BorderLayout.CENTER);
+ JComponent uiComp = (JComponent)myCefBrowser.getUIComponent();
+ uiComp.putClientProperty(JBCEFBROWSER_INSTANCE_PROP, this);
+ myComponent.add(uiComp, BorderLayout.CENTER);
if (cefBrowser == null) {
myCefClient.addLifeSpanHandler(myLifeSpanHandler = new CefLifeSpanHandlerAdapter() {
@@ -165,7 +169,7 @@ public class JBCefBrowser implements JBCefDisposable {
*/
public void loadHTML(@NotNull String html, @NotNull String url) {
if (myIsCefBrowserCreated) {
- myCefBrowser.loadString(html, url);
+ loadString(myCefBrowser, html, url);
}
else {
myLoadDeferrer = LoadDeferrer.htmlDeferrer(html, url);
@@ -179,6 +183,12 @@ public class JBCefBrowser implements JBCefDisposable {
loadHTML(html, BLANK_URI);
}
+ private static void loadString(CefBrowser cefBrowser, String html, String url) {
+ String loadUrl = HTML_STRING_URL + "?url=" + url;
+ JBCefHtmlStringSchemeHandler.registerRequest(cefBrowser, html, loadUrl);
+ cefBrowser.loadURL(loadUrl);
+ }
+
/**
* Creates a browser with default {@link JBCefClient}. The default client is disposed with this browser and may not be used with other browsers.
*/
@@ -289,11 +299,11 @@ public class JBCefBrowser implements JBCefDisposable {
return myDisposeHelper.isDisposed();
}
- @SuppressWarnings("unused")
- @Contract("null->null; !null->!null")
- protected static JBCefBrowser getJBCefBrowser(CefBrowser browser) {
- if (browser == null) return null;
- return ((MyComponent)browser.getUIComponent().getParent()).getJBCefBrowser();
+ /**
+ * Returns {@code JBCefBrowser} instance associated with this {@code CefBrowser}.
+ */
+ public static JBCefBrowser getJBCefBrowser(@NotNull CefBrowser browser) {
+ return (JBCefBrowser)((JComponent)browser.getUIComponent()).getClientProperty(JBCEFBROWSER_INSTANCE_PROP);
}
protected class DefaultCefContextMenuHandler extends CefContextMenuHandlerAdapter {
diff --git a/platform/platform-api/src/com/intellij/ui/jcef/JBCefClient.java b/platform/platform-api/src/com/intellij/ui/jcef/JBCefClient.java
index 5bf901158331..5b6624207e1b 100644
--- a/platform/platform-api/src/com/intellij/ui/jcef/JBCefClient.java
+++ b/platform/platform-api/src/com/intellij/ui/jcef/JBCefClient.java
@@ -12,10 +12,7 @@ import org.cef.browser.CefFrame;
import org.cef.callback.*;
import org.cef.handler.*;
import org.cef.misc.BoolRef;
-import org.cef.misc.StringRef;
import org.cef.network.CefRequest;
-import org.cef.network.CefResponse;
-import org.cef.network.CefURLRequest;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -420,56 +417,31 @@ public class JBCefClient implements JBCefDisposable {
}
@Override
- public boolean onBeforeResourceLoad(CefBrowser browser, CefFrame frame, CefRequest request) {
+ public CefResourceRequestHandler getResourceRequestHandler(CefBrowser browser,
+ CefFrame frame,
+ CefRequest request,
+ boolean isNavigation,
+ boolean isDownload,
+ String requestInitiator,
+ BoolRef disableDefaultHandling)
+ {
return myRequestHandler.handleNotNull(browser, handler -> {
- return handler.onBeforeResourceLoad(browser, frame, request);
- });
- }
-
- @Override
- public CefResourceHandler getResourceHandler(CefBrowser browser, CefFrame frame, CefRequest request) {
- return myRequestHandler.handle(browser, handler -> {
- return handler.getResourceHandler(browser, frame, request);
- });
- }
-
- @Override
- public void onResourceRedirect(CefBrowser browser, CefFrame frame, CefRequest request, CefResponse response, StringRef new_url) {
- myRequestHandler.handle(browser, handler -> {
- handler.onResourceRedirect(browser, frame, request, response, new_url);
- });
- }
-
- @Override
- public boolean onResourceResponse(CefBrowser browser, CefFrame frame, CefRequest request, CefResponse response) {
- return myRequestHandler.handleNotNull(browser, handler -> {
- return handler.onResourceResponse(browser, frame, request, response);
- });
- }
-
- @Override
- public void onResourceLoadComplete(CefBrowser browser,
- CefFrame frame,
- CefRequest request,
- CefResponse response,
- CefURLRequest.Status status,
- long receivedContentLength) {
- myRequestHandler.handle(browser, handler -> {
- handler.onResourceLoadComplete(browser, frame, request, response, status, receivedContentLength);
+ return handler.getResourceRequestHandler(browser, frame, request, isNavigation, isDownload, requestInitiator, disableDefaultHandling);
});
}
@Override
public boolean getAuthCredentials(CefBrowser browser,
- CefFrame frame,
+ String origin_url,
boolean isProxy,
String host,
int port,
String realm,
String scheme,
- CefAuthCallback callback) {
+ CefAuthCallback callback)
+ {
return myRequestHandler.handleNotNull(browser, handler -> {
- return handler.getAuthCredentials(browser, frame, isProxy, host, port, realm, scheme, callback);
+ return handler.getAuthCredentials(browser, origin_url, isProxy, host, port, realm, scheme, callback);
});
}
@@ -480,13 +452,6 @@ public class JBCefClient implements JBCefDisposable {
});
}
- @Override
- public void onProtocolExecution(CefBrowser browser, String url, BoolRef allow_os_execution) {
- myRequestHandler.handle(browser, handler -> {
- handler.onProtocolExecution(browser, url, allow_os_execution);
- });
- }
-
@Override
public boolean onCertificateError(CefBrowser browser,
CefLoadHandler.ErrorCode cert_error,
diff --git a/platform/platform-api/src/com/intellij/ui/jcef/JBCefFileSchemeHandler.java b/platform/platform-api/src/com/intellij/ui/jcef/JBCefFileSchemeHandler.java
index bc445ae87f59..8c00b21f6a52 100644
--- a/platform/platform-api/src/com/intellij/ui/jcef/JBCefFileSchemeHandler.java
+++ b/platform/platform-api/src/com/intellij/ui/jcef/JBCefFileSchemeHandler.java
@@ -30,15 +30,16 @@ class JBCefFileSchemeHandler extends CefResourceHandlerAdapter {
public static final String FILE_SCHEME_NAME = "file";
- @NotNull private final CefBrowser myBrowser;
- @NotNull private final CefFrame myFrame;
+ //@NotNull private final CefBrowser myBrowser;
+ //@NotNull private final CefFrame myFrame;
@Nullable private Path myPath;
@Nullable private InputStream myInputStream;
+ @SuppressWarnings("unused")
JBCefFileSchemeHandler(@NotNull CefBrowser browser, @NotNull CefFrame frame) {
- myBrowser = browser;
- myFrame = frame;
+ //myBrowser = browser;
+ //myFrame = frame;
}
@Override
@@ -78,14 +79,27 @@ class JBCefFileSchemeHandler extends CefResourceHandlerAdapter {
}
response.setStatus(myInputStream != null ? 200 : 404);
}
-
@Override
public boolean readResponse(byte@NotNull[] data_out, int bytes_to_read, IntRef bytes_read, CefCallback callback) {
+ boolean inProgress = readResponse(myInputStream, data_out, bytes_to_read, bytes_read, callback);
+ if (!inProgress) {
+ myPath = null;
+ myInputStream = null;
+ }
+ return inProgress;
+ }
+
+ static boolean readResponse(@Nullable InputStream inputStream,
+ byte@NotNull[] data_out,
+ int bytes_to_read,
+ IntRef bytes_read,
+ @SuppressWarnings("unused") CefCallback callback)
+ {
try {
- int availableSize = myInputStream != null ? myInputStream.available() : 0;
+ int availableSize = inputStream != null ? inputStream.available() : 0;
if (availableSize > 0) {
int bytesToRead = Math.min(bytes_to_read, availableSize);
- bytesToRead = myInputStream.read(data_out, 0, bytesToRead);
+ bytesToRead = inputStream.read(data_out, 0, bytesToRead);
bytes_read.set(bytesToRead);
return true;
}
@@ -94,20 +108,18 @@ class JBCefFileSchemeHandler extends CefResourceHandlerAdapter {
LOG.error(e);
}
bytes_read.set(0);
- myPath = null;
- if (myInputStream != null) {
+ if (inputStream != null) {
try {
- myInputStream.close();
+ inputStream.close();
}
catch (IOException e) {
LOG.error(e);
}
- myInputStream = null;
}
return false;
}
- private static boolean checkAccessAllowed(Path path) {
+ private static boolean checkAccessAllowed(@SuppressWarnings("unused") Path path) {
// tav: todo Ask the user or query the settings for JCEF FS access.
return true;
}
diff --git a/platform/platform-api/src/com/intellij/ui/jcef/JBCefHtmlStringSchemeHandler.java b/platform/platform-api/src/com/intellij/ui/jcef/JBCefHtmlStringSchemeHandler.java
new file mode 100644
index 000000000000..5079d3f2b2ae
--- /dev/null
+++ b/platform/platform-api/src/com/intellij/ui/jcef/JBCefHtmlStringSchemeHandler.java
@@ -0,0 +1,104 @@
+// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.ui.jcef;
+
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.Disposer;
+import org.cef.browser.CefBrowser;
+import org.cef.browser.CefFrame;
+import org.cef.callback.CefCallback;
+import org.cef.handler.CefLoadHandler;
+import org.cef.handler.CefResourceHandlerAdapter;
+import org.cef.misc.IntRef;
+import org.cef.misc.StringRef;
+import org.cef.network.CefRequest;
+import org.cef.network.CefResponse;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A custom scheme handler for serving the {@link JBCefBrowser#loadHTML(String, String)} method.
+ *
+ * @author tav
+ */
+class JBCefHtmlStringSchemeHandler extends CefResourceHandlerAdapter implements Disposable {
+ private static final Logger LOG = Logger.getInstance(JBCefHtmlStringSchemeHandler.class);
+
+ public static final String HTML_STRING_SCHEME_NAME = "jb-html-string";
+
+ private static final Map> LOAD_REQUEST_MAP = new HashMap<>();
+
+ @NotNull private final CefBrowser myBrowser;
+ @Nullable private InputStream myInputStream;
+
+ JBCefHtmlStringSchemeHandler(@NotNull CefBrowser browser, @SuppressWarnings("unused") @NotNull CefFrame frame) {
+ myBrowser = browser;
+ Disposer.register(JBCefBrowser.getJBCefBrowser(browser), this);
+ }
+
+ @Override
+ public void dispose() {
+ LOAD_REQUEST_MAP.remove(myBrowser);
+ }
+
+ public static void registerRequest(@NotNull CefBrowser browser, @NotNull String html, @NotNull String url) {
+ getInitMap(browser).put(url, html);
+ }
+
+ @NotNull
+ private static Map getInitMap(@NotNull CefBrowser browser) {
+ Map map = LOAD_REQUEST_MAP.get(browser);
+ if (map == null) {
+ synchronized (LOAD_REQUEST_MAP) {
+ map = LOAD_REQUEST_MAP.get(browser);
+ if (map == null) {
+ LOAD_REQUEST_MAP.put(browser, map = Collections.synchronizedMap(new HashMap<>()));
+ }
+ }
+ }
+ return map;
+ }
+
+ @Override
+ public boolean processRequest(@NotNull CefRequest request, @NotNull CefCallback callback) {
+ Map map = LOAD_REQUEST_MAP.get(myBrowser);
+ if (map != null) {
+ String html = map.get(request.getURL());
+ if (html != null) {
+ myInputStream = new ByteArrayInputStream(html.getBytes(Charset.defaultCharset()));
+ callback.Continue();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void getResponseHeaders(@NotNull CefResponse response, IntRef response_length, StringRef redirectUrl) {
+ response.setMimeType("text/html");
+ if (myInputStream == null) {
+ response.setError(CefLoadHandler.ErrorCode.ERR_INSUFFICIENT_RESOURCES);
+ response.setStatusText("The HTML string is null");
+ LOG.error("JBCefHtmlStringSchemeHandler.getResponseHeaders: the HTML string is null");
+ response.setStatus(400);
+ return;
+ }
+ response.setStatus(200);
+ }
+
+ @Override
+ public boolean readResponse(byte@NotNull[] data_out, int bytes_to_read, IntRef bytes_read, CefCallback callback) {
+ boolean inProgress = JBCefFileSchemeHandler.readResponse(myInputStream, data_out, bytes_to_read, bytes_read, callback);
+ if (!inProgress) {
+ myInputStream = null;
+ }
+ return inProgress;
+ }
+}