diff --git a/CMakeLists.txt b/CMakeLists.txt index 22d0fc06..598c3f19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,7 +137,7 @@ endif() # Specify the CEF distribution version. if(NOT DEFINED CEF_VERSION) - set(CEF_VERSION "116.0.27+gd8c85ac+chromium-116.0.5845.190") + set(CEF_VERSION "135.0.20+ge7de5c3+chromium-135.0.7049.85") endif() # Determine the platform. diff --git a/java/org/cef/CefApp.java b/java/org/cef/CefApp.java index eff69e01..27de5a71 100644 --- a/java/org/cef/CefApp.java +++ b/java/org/cef/CefApp.java @@ -8,10 +8,7 @@ import org.cef.handler.CefAppHandler; import org.cef.handler.CefAppHandlerAdapter; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.io.File; -import java.io.FilenameFilter; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashSet; @@ -102,6 +99,12 @@ public enum CefAppState { */ INITIALIZED, + /** + * CEF initialization has failed (for example due to a second process using + * the same root_cache_path). + */ + INITIALIZATION_FAILED, + /** * CefApp is in its shutdown process. All CefClients and CefBrowser * instances will be disposed. No new CefClient or CefBrowser is allowed to @@ -272,6 +275,7 @@ public synchronized final void dispose() { case NONE: case SHUTTING_DOWN: case TERMINATED: + case INITIALIZATION_FAILED: // Ignore shutdown, CefApp is already terminated, in shutdown progress // or was never created (shouldn't be possible) break; @@ -384,7 +388,11 @@ private final void initialize() { settings.locales_dir_path = localesPath.normalize().toAbsolutePath().toString(); } - if (N_Initialize(appHandler_, settings)) setState(CefAppState.INITIALIZED); + if (N_Initialize(appHandler_, settings)) { + setState(CefAppState.INITIALIZED); + } else { + setState(CefAppState.INITIALIZATION_FAILED); + } } /** diff --git a/java/org/cef/CefBrowserSettings.java b/java/org/cef/CefBrowserSettings.java new file mode 100644 index 00000000..8733a418 --- /dev/null +++ b/java/org/cef/CefBrowserSettings.java @@ -0,0 +1,31 @@ +// Copyright (c) 2024 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +package org.cef; + +/** + * Browser initialization settings. Specify NULL or 0 to get the recommended + * default values. The consequences of using custom values may not be well + * tested. Many of these and other settings can also configured using command- + * line switches. + */ +public class CefBrowserSettings { + /** + * The maximum rate in frames per second (fps) that CefRenderHandler::OnPaint + * will be called for a windowless browser. The actual fps may be lower if + * the browser cannot generate frames at the requested rate. The minimum + * value is 1 and the maximum value is 60 (default 30). This value can also + * be changed dynamically via {@code CefBrowser#setWindowlessFrameRate} + */ + public int windowless_frame_rate = 0; + + public CefBrowserSettings() {} + + @Override + public CefBrowserSettings clone() { + CefBrowserSettings tmp = new CefBrowserSettings(); + tmp.windowless_frame_rate = windowless_frame_rate; + return tmp; + } +} diff --git a/java/org/cef/CefClient.java b/java/org/cef/CefClient.java index d2d956de..50693328 100644 --- a/java/org/cef/CefClient.java +++ b/java/org/cef/CefClient.java @@ -4,11 +4,7 @@ package org.cef; -import org.cef.browser.CefBrowser; -import org.cef.browser.CefBrowserFactory; -import org.cef.browser.CefFrame; -import org.cef.browser.CefMessageRouter; -import org.cef.browser.CefRequestContext; +import org.cef.browser.*; import org.cef.callback.CefAuthCallback; import org.cef.callback.CefBeforeDownloadCallback; import org.cef.callback.CefCallback; @@ -25,20 +21,15 @@ import org.cef.misc.*; import org.cef.network.CefRequest; import org.cef.network.CefRequest.TransitionType; -import org.cef.network.CefResponse; -import org.cef.network.CefURLRequest; import java.awt.Dimension; import java.awt.Point; import java.awt.Rectangle; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; import java.nio.ByteBuffer; import java.util.Collection; import java.util.HashMap; import java.util.Vector; - -import javax.swing.SwingUtilities; +import java.util.function.Consumer; /** * Client that owns a browser and renderer. @@ -91,13 +82,22 @@ public CefBrowser createBrowser(String url, boolean isTransparent, CefRequestContext context) { if (isDisposed_) throw new IllegalStateException("Can't create browser. CefClient is disposed"); - return CefBrowserFactory.create(this, url, isTransparent, context); + return CefBrowserFactory.create( + this, url, isTransparent, context, null); + } + + public CefBrowser createBrowser(String url, boolean isTransparent, + CefRequestContext context, CefBrowserSettings settings) { + if (isDisposed_) + throw new IllegalStateException("Can't create browser. CefClient is disposed"); + return CefBrowserFactory.create( + this, url, isTransparent, context, settings); } @Override protected CefBrowser getBrowser(int identifier) { synchronized (browser_) { - return browser_.get(new Integer(identifier)); + return browser_.get(Integer.valueOf(identifier)); } } @@ -229,10 +229,11 @@ public void removeDialogHandler() { @Override public boolean onFileDialog(CefBrowser browser, FileDialogMode mode, String title, - String defaultFilePath, Vector acceptFilters, CefFileDialogCallback callback) { + String defaultFilePath, Vector acceptFilters, Vector acceptExtensions, + Vector acceptDescriptions, CefFileDialogCallback callback) { if (dialogHandler_ != null && browser != null) { - return dialogHandler_.onFileDialog( - browser, mode, title, defaultFilePath, acceptFilters, callback); + return dialogHandler_.onFileDialog(browser, mode, title, defaultFilePath, acceptFilters, + acceptExtensions, acceptDescriptions, callback); } return false; } @@ -260,6 +261,12 @@ public void onTitleChange(CefBrowser browser, String title) { displayHandler_.onTitleChange(browser, title); } + @Override + public void onFullscreenModeChange(CefBrowser browser, boolean fullscreen) { + if (displayHandler_ != null && browser != null) + displayHandler_.onFullscreenModeChange(browser, fullscreen); + } + @Override public boolean onTooltip(CefBrowser browser, String text) { if (displayHandler_ != null && browser != null) { @@ -314,10 +321,12 @@ public void removeDownloadHandler() { } @Override - public void onBeforeDownload(CefBrowser browser, CefDownloadItem downloadItem, + public boolean onBeforeDownload(CefBrowser browser, CefDownloadItem downloadItem, String suggestedName, CefBeforeDownloadCallback callback) { if (downloadHandler_ != null && browser != null) - downloadHandler_.onBeforeDownload(browser, downloadItem, suggestedName, callback); + return downloadHandler_.onBeforeDownload( + browser, downloadItem, suggestedName, callback); + return false; } @Override @@ -684,6 +693,15 @@ public void onPaint(CefBrowser browser, boolean popup, Rectangle[] dirtyRects, realHandler.onPaint(browser, popup, dirtyRects, buffer, width, height); } + @Override + public void addOnPaintListener(Consumer listener) {} + + @Override + public void setOnPaintListener(Consumer listener) {} + + @Override + public void removeOnPaintListener(Consumer listener) {} + @Override public boolean startDragging(CefBrowser browser, CefDragData dragData, int mask, int x, int y) { if (browser == null) return false; @@ -759,8 +777,10 @@ public boolean onCertificateError( } @Override - public void onRenderProcessTerminated(CefBrowser browser, TerminationStatus status) { - if (requestHandler_ != null) requestHandler_.onRenderProcessTerminated(browser, status); + public void onRenderProcessTerminated( + CefBrowser browser, TerminationStatus status, int error_code, String error_string) { + if (requestHandler_ != null) + requestHandler_.onRenderProcessTerminated(browser, status, error_code, error_string); } // CefWindowHandler diff --git a/java/org/cef/CefSettings.java b/java/org/cef/CefSettings.java index a094b355..209b6042 100644 --- a/java/org/cef/CefSettings.java +++ b/java/org/cef/CefSettings.java @@ -106,10 +106,39 @@ public ColorType clone() { * The location where cache data will be stored on disk. If empty an in-memory * cache will be used for some features and a temporary disk cache for others. * HTML5 databases such as localStorage will only persist across sessions if a - * cache path is specified. + * cache path is specified. If this is set and root_cache_path is also set, the cache_path + * directory must reside within root_cache_path. */ public String cache_path = null; + /** + * The root directory for installation-specific data and the parent directory + * for profile-specific data. All CefSettings.cache_path and + * CefRequestContextSettings.cache_path values must have this parent + * directory in common. If this value is empty and CefSettings.cache_path is + * non-empty then it will default to the CefSettings.cache_path value. Any + * non-empty value must be an absolute path. If both values are empty then + * the default platform-specific directory will be used + * ("~/.config/cef_user_data" directory on Linux, "~/Library/Application + * Support/CEF/User Data" directory on MacOS, "AppData\Local\CEF\User Data" + * directory under the user profile directory on Windows). Use of the default + * directory is not recommended in production applications (see below). + * + * Multiple application instances writing to the same root_cache_path + * directory could result in data corruption. A process singleton lock based + * on the root_cache_path value is therefore used to protect against this. + * This singleton behavior applies to all CEF-based applications using + * version 120 or newer. You should customize root_cache_path for your + * application and implement CefAppHandler:: + * onAlreadyRunningAppRelaunch, which will then be called on any app relaunch + * with the same root_cache_path value. + * + * Failure to set the root_cache_path value correctly may result in startup + * crashes or other unexpected behaviors (for example, the sandbox blocking + * read/write access to certain files). + */ + public String root_cache_path = null; + /** * To persist session cookies (cookies without an expiry date or validity * interval) by default when using the global cookie manager set this value to @@ -185,15 +214,6 @@ public ColorType clone() { */ public String locales_dir_path = null; - /** - * Set to true to disable loading of pack files for resources and locales. - * A resource bundle handler must be provided for the browser and render - * processes via CefApp::GetResourceBundleHandler() if loading of pack files - * is disabled. Also configurable using the "disable-pack-loading" command- - * line switch. - */ - public boolean pack_loading_disabled = false; - /** * Set to a value between 1024 and 65535 to enable remote debugging on the * specified port. For example, if 8080 is specified the remote debugging URL @@ -245,6 +265,7 @@ public CefSettings clone() { tmp.windowless_rendering_enabled = windowless_rendering_enabled; tmp.command_line_args_disabled = command_line_args_disabled; tmp.cache_path = cache_path; + tmp.root_cache_path = root_cache_path; tmp.persist_session_cookies = persist_session_cookies; tmp.user_agent = user_agent; tmp.user_agent_product = user_agent_product; @@ -254,7 +275,6 @@ public CefSettings clone() { tmp.javascript_flags = javascript_flags; tmp.resources_dir_path = resources_dir_path; tmp.locales_dir_path = locales_dir_path; - tmp.pack_loading_disabled = pack_loading_disabled; tmp.remote_debugging_port = remote_debugging_port; tmp.uncaught_exception_stack_size = uncaught_exception_stack_size; if (background_color != null) tmp.background_color = background_color.clone(); diff --git a/java/org/cef/SystemBootstrap.java b/java/org/cef/SystemBootstrap.java index 0a217ac4..342aaa82 100644 --- a/java/org/cef/SystemBootstrap.java +++ b/java/org/cef/SystemBootstrap.java @@ -13,7 +13,9 @@ public class SystemBootstrap { /** * Simple interface for how a library by name should be loaded. */ - static public interface Loader { public void loadLibrary(String libname); } + static public interface Loader { + public void loadLibrary(String libname); + } /** * Default implementation is to call System.loadLibrary diff --git a/java/org/cef/browser/CefBrowser.java b/java/org/cef/browser/CefBrowser.java index e73bae58..5818e681 100644 --- a/java/org/cef/browser/CefBrowser.java +++ b/java/org/cef/browser/CefBrowser.java @@ -14,7 +14,6 @@ import org.cef.misc.CefPdfPrintSettings; import org.cef.network.CefRequest; -import java.awt.Component; import java.awt.Point; import java.awt.image.BufferedImage; import java.util.Vector; @@ -119,20 +118,20 @@ public interface CefBrowser { * @param identifier The unique frame identifier * @return The frame or NULL if not found */ - public CefFrame getFrame(long identifier); + public CefFrame getFrameByIdentifier(String identifier); /** * Returns the frame with the specified name, or NULL if not found. * @param name The specified name * @return The frame or NULL if not found */ - public CefFrame getFrame(String name); + public CefFrame getFrameByName(String name); /** * Returns the identifiers of all existing frames. * @return All identifiers of existing frames. */ - public Vector getFrameIdentifiers(); + public Vector getFrameIdentifiers(); /** * Returns the names of all existing frames. @@ -331,18 +330,31 @@ public void runFileDialog(FileDialogMode mode, String title, String defaultFileP public void stopFinding(boolean clearSelection); /** - * Get an instance of the dev tools to be displayed in its own window or to be - * embedded within your UI. Only one instance per browser is available. + * Get an instance of the DevTools to be displayed in its own window. */ - public CefBrowser getDevTools(); + public void openDevTools(); /** - * Get an instance of the dev tools to be displayed in its own window or to be - * embedded within your UI. Only one instance per browser is available. + * Open an instance of the DevTools to be displayed in its own window. * * @param inspectAt a position in the UI which should be inspected. */ - public CefBrowser getDevTools(Point inspectAt); + public void openDevTools(Point inspectAt); + + /** + * Close the DevTools. + */ + public void closeDevTools(); + + /** + * Get an instance of a client that can be used to leverage the DevTools + * protocol. Only one instance per browser is available. + * + * @see {@link CefDevToolsClient} + * @return DevTools client, or null if this browser is not yet created + * or if it is closed or closing + */ + public CefDevToolsClient getDevToolsClient(); /** * If a misspelled word is currently selected in an editable node calling @@ -374,4 +386,26 @@ public void runFileDialog(FileDialogMode mode, String title, String defaultFileP * @throws UnsupportedOperationException if not supported */ public CompletableFuture createScreenshot(boolean nativeResolution); + + /** + * Set the maximum rate in frames per second (fps) that {@code CefRenderHandler::onPaint} + * will be called for a windowless browser. The actual fps may be + * lower if the browser cannot generate frames at the requested rate. The + * minimum value is 1, and the maximum value is 60 (default 30). + * + * @param frameRate the maximum frame rate + * @throws UnsupportedOperationException if not supported + */ + public void setWindowlessFrameRate(int frameRate); + + /** + * Returns the maximum rate in frames per second (fps) that {@code CefRenderHandler::onPaint} + * will be called for a windowless browser. The actual fps may be lower if the browser cannot + * generate frames at the requested rate. The minimum value is 1, and the maximum value is 60 + * (default 30). + * + * @return the framerate, 0 if an error occurs + * @throws UnsupportedOperationException if not supported + */ + public CompletableFuture getWindowlessFrameRate(); } diff --git a/java/org/cef/browser/CefBrowserFactory.java b/java/org/cef/browser/CefBrowserFactory.java index 98a1678e..4d1826d0 100644 --- a/java/org/cef/browser/CefBrowserFactory.java +++ b/java/org/cef/browser/CefBrowserFactory.java @@ -4,6 +4,7 @@ package org.cef.browser; +import org.cef.CefBrowserSettings; import org.cef.CefClient; /** @@ -11,7 +12,7 @@ */ public class CefBrowserFactory { public static CefBrowser create(CefClient client, String url, - boolean isTransparent, CefRequestContext context) { - return new CefBrowserOsr(client, url, isTransparent, context); + boolean isTransparent, CefRequestContext context, CefBrowserSettings settings) { + return new CefBrowserOsr(client, url, isTransparent, context, settings); } } diff --git a/java/org/cef/browser/CefBrowserOsr.java b/java/org/cef/browser/CefBrowserOsr.java index cd80d9ba..4bb45052 100644 --- a/java/org/cef/browser/CefBrowserOsr.java +++ b/java/org/cef/browser/CefBrowserOsr.java @@ -4,19 +4,18 @@ package org.cef.browser; +import org.cef.CefBrowserSettings; import org.cef.CefClient; import org.cef.callback.CefDragData; import org.cef.handler.CefRenderHandler; import org.cef.handler.CefScreenInfo; import java.awt.*; -import java.awt.dnd.DnDConstants; -import java.awt.dnd.DragGestureRecognizer; -import java.awt.dnd.DragSource; -import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; /** * This class represents an off-screen rendered browser. @@ -24,139 +23,169 @@ * CefBrowser instance, please use CefBrowserFactory. */ public class CefBrowserOsr extends CefBrowser_N implements CefRenderHandler { - private boolean justCreated_ = false; - protected Rectangle browser_rect_ = new Rectangle(0, 0, 1, 1); // Work around CEF issue #1437. - private Point screenPoint_ = new Point(0, 0); - private double scaleFactor_ = 1.0; - private int depth = 32; - private int depth_per_component = 8; - private boolean isTransparent_; - - public CefBrowserOsr(CefClient client, String url, boolean transparent, CefRequestContext context) { - this(client, url, transparent, context, null, null); - } - - private CefBrowserOsr(CefClient client, String url, boolean transparent, - CefRequestContext context, CefBrowserOsr parent, Point inspectAt) { - super(client, url, context, parent, inspectAt); - isTransparent_ = transparent; - } - - @Override - public void createImmediately() { - justCreated_ = true; - // Create the browser immediately. - createBrowserIfRequired(false); - } - - @Override - public CefRenderHandler getRenderHandler() { - return this; - } - - @Override - protected CefBrowser_N createDevToolsBrowser(CefClient client, String url, CefRequestContext context, CefBrowser_N parent, Point inspectAt) { - return null; - } - - @Override - public Rectangle getViewRect(CefBrowser browser) { - return browser_rect_; - } - - @Override - public Point getScreenPoint(CefBrowser browser, Point viewPoint) { - Point screenPoint = new Point(screenPoint_); - screenPoint.translate(viewPoint.x, viewPoint.y); - return screenPoint; - } - - @Override - public void onPopupShow(CefBrowser browser, boolean show) { - } + private boolean justCreated_ = false; + protected Rectangle browser_rect_ = new Rectangle(0, 0, 1, 1); // Work around CEF issue #1437. + private Point screenPoint_ = new Point(0, 0); + private double scaleFactor_ = 1.0; + private int depth = 32; + private int depth_per_component = 8; + private boolean isTransparent_; + + private CopyOnWriteArrayList> onPaintListeners = new CopyOnWriteArrayList<>(); + + CefBrowserOsr(CefClient client, String url, boolean transparent, CefRequestContext context, + CefBrowserSettings settings) { + this(client, url, transparent, context, null, null, settings); + } + + private CefBrowserOsr(CefClient client, String url, boolean transparent, + CefRequestContext context, CefBrowserOsr parent, Point inspectAt, + CefBrowserSettings settings) { + super(client, url, context, parent, inspectAt, settings); + isTransparent_ = transparent; + } + + @Override + public void createImmediately() { + justCreated_ = true; + // Create the browser immediately. + createBrowserIfRequired(false); + } + + @Override + public CefRenderHandler getRenderHandler() { + return this; + } + + @Override + protected CefBrowser_N createDevToolsBrowser(CefClient client, String url, + CefRequestContext context, CefBrowser_N parent, Point inspectAt) { + return null; + } + + @Override + public Rectangle getViewRect(CefBrowser browser) { + return browser_rect_; + } + + @Override + public Point getScreenPoint(CefBrowser browser, Point viewPoint) { + Point screenPoint = new Point(screenPoint_); + screenPoint.translate(viewPoint.x, viewPoint.y); + return screenPoint; + } + + @Override + public void onPopupShow(CefBrowser browser, boolean show) { + } @Override public void onPopupSize(CefBrowser browser, Rectangle size) { } - @Override - public void onPaint(CefBrowser browser, boolean popup, Rectangle[] dirtyRects, ByteBuffer buffer, int width, int height) { - } - - @Override - public boolean onCursorChange(CefBrowser browser, final int cursorType) { - return true; - } - - private static final class SyntheticDragGestureRecognizer extends DragGestureRecognizer { - public SyntheticDragGestureRecognizer(Component c, int action, MouseEvent triggerEvent) { - super(new DragSource(), c, action); - appendEvent(triggerEvent); - } - - protected void registerListeners() {} - - protected void unregisterListeners() {} - }; - - private static int getDndAction(int mask) { - // Default to copy if multiple operations are specified. - int action = DnDConstants.ACTION_NONE; - if ((mask & CefDragData.DragOperations.DRAG_OPERATION_COPY) - == CefDragData.DragOperations.DRAG_OPERATION_COPY) { - action = DnDConstants.ACTION_COPY; - } else if ((mask & CefDragData.DragOperations.DRAG_OPERATION_MOVE) - == CefDragData.DragOperations.DRAG_OPERATION_MOVE) { - action = DnDConstants.ACTION_MOVE; - } else if ((mask & CefDragData.DragOperations.DRAG_OPERATION_LINK) - == CefDragData.DragOperations.DRAG_OPERATION_LINK) { - action = DnDConstants.ACTION_LINK; - } - return action; - } - - @Override - public boolean startDragging(CefBrowser browser, CefDragData dragData, int mask, int x, int y) { - return true; - } - - @Override - public void updateDragCursor(CefBrowser browser, int operation) { - } - - private void createBrowserIfRequired(boolean hasParent) { - long windowHandle = 0; - if (getNativeRef("CefBrowser") == 0) { - if (getParentBrowser() != null) { - createDevTools(getParentBrowser(), getClient(), windowHandle, true, isTransparent_, - getInspectAt()); - } else { - createBrowser(getClient(), windowHandle, getUrl(), true, isTransparent_, - getRequestContext()); - } - } else if (hasParent && justCreated_) { - notifyAfterParentChanged(); - setFocus(true); - justCreated_ = false; - } - } - - private void notifyAfterParentChanged() { - // With OSR there is no native window to reparent but we still need to send the - // notification. - getClient().onAfterParentChanged(this); - } - - @Override - public boolean getScreenInfo(CefBrowser browser, CefScreenInfo screenInfo) { - screenInfo.Set(scaleFactor_, depth, depth_per_component, false, browser_rect_.getBounds(), - browser_rect_.getBounds()); - - return true; - } - - @Override - public CompletableFuture createScreenshot(boolean nativeResolution) { - return null; - } + @Override + public void addOnPaintListener(Consumer listener) { + onPaintListeners.add(listener); + } + + @Override + public void setOnPaintListener(Consumer listener) { + onPaintListeners.clear(); + onPaintListeners.add(listener); + } + + @Override + public void removeOnPaintListener(Consumer listener) { + onPaintListeners.remove(listener); + } + + @Override + public void onPaint(CefBrowser browser, boolean popup, Rectangle[] dirtyRects, ByteBuffer buffer, int width, + int height) { + if (!onPaintListeners.isEmpty()) { + CefPaintEvent paintEvent = new CefPaintEvent(browser, popup, dirtyRects, buffer, width, height); + for (Consumer l : onPaintListeners) { + l.accept(paintEvent); + } + } + } + + @Override + public boolean onCursorChange(CefBrowser browser, final int cursorType) { + return true; + } + + // private static final class SyntheticDragGestureRecognizer extends + // DragGestureRecognizer { + // public SyntheticDragGestureRecognizer(Component c, int action, MouseEvent + // triggerEvent) { + // super(new DragSource(), c, action); + // appendEvent(triggerEvent); + // } + + // protected void registerListeners() {} + + // protected void unregisterListeners() {} + // }; + + // private static int getDndAction(int mask) { + // // Default to copy if multiple operations are specified. + // int action = DnDConstants.ACTION_NONE; + // if ((mask & CefDragData.DragOperations.DRAG_OPERATION_COPY) + // == CefDragData.DragOperations.DRAG_OPERATION_COPY) { + // action = DnDConstants.ACTION_COPY; + // } else if ((mask & CefDragData.DragOperations.DRAG_OPERATION_MOVE) + // == CefDragData.DragOperations.DRAG_OPERATION_MOVE) { + // action = DnDConstants.ACTION_MOVE; + // } else if ((mask & CefDragData.DragOperations.DRAG_OPERATION_LINK) + // == CefDragData.DragOperations.DRAG_OPERATION_LINK) { + // action = DnDConstants.ACTION_LINK; + // } + // return action; + // } + + @Override + public boolean startDragging(CefBrowser browser, CefDragData dragData, int mask, int x, int y) { + return true; + } + + @Override + public void updateDragCursor(CefBrowser browser, int operation) { + } + + private void createBrowserIfRequired(boolean hasParent) { + long windowHandle = 0; + if (getNativeRef("CefBrowser") == 0) { + if (getParentBrowser() != null) { + createDevTools(getParentBrowser(), getClient(), windowHandle, true, isTransparent_, + getInspectAt()); + } else { + createBrowser(getClient(), windowHandle, getUrl(), true, isTransparent_, + getRequestContext()); + } + } else if (hasParent && justCreated_) { + notifyAfterParentChanged(); + setFocus(true); + justCreated_ = false; + } + } + + private void notifyAfterParentChanged() { + // With OSR there is no native window to reparent but we still need to send the + // notification. + getClient().onAfterParentChanged(this); + } + + @Override + public boolean getScreenInfo(CefBrowser browser, CefScreenInfo screenInfo) { + screenInfo.Set(scaleFactor_, depth, depth_per_component, false, browser_rect_.getBounds(), + browser_rect_.getBounds()); + + return true; + } + + @Override + public CompletableFuture createScreenshot(boolean nativeResolution) { + return null; + } } diff --git a/java/org/cef/browser/CefBrowser_N.java b/java/org/cef/browser/CefBrowser_N.java index 6c3749f9..fde036e9 100644 --- a/java/org/cef/browser/CefBrowser_N.java +++ b/java/org/cef/browser/CefBrowser_N.java @@ -4,8 +4,9 @@ package org.cef.browser; +import org.cef.CefBrowserSettings; import org.cef.CefClient; -import org.cef.browser.CefRequestContext; +import org.cef.browser.CefDevToolsClient.DevToolsException; import org.cef.callback.CefDragData; import org.cef.callback.CefNativeAdapter; import org.cef.callback.CefPdfPrintCallback; @@ -21,14 +22,10 @@ import org.cef.misc.CefPdfPrintSettings; import org.cef.network.CefRequest; -import java.awt.Component; import java.awt.Point; import java.awt.Rectangle; -import java.awt.Window; -import java.awt.event.WindowEvent; import java.util.Vector; - -import javax.swing.SwingUtilities; +import java.util.concurrent.CompletableFuture; /** * This class represents all methods which are connected to the @@ -43,18 +40,23 @@ public abstract class CefBrowser_N extends CefNativeAdapter implements CefBrowse private final CefRequestContext request_context_; private volatile CefBrowser_N parent_ = null; private volatile Point inspectAt_ = null; - private volatile CefBrowser_N devTools_ = null; + private volatile CefDevToolsClient devToolsClient_ = null; private boolean closeAllowed_ = false; private volatile boolean isClosed_ = false; private volatile boolean isClosing_ = false; + private final CefBrowserSettings settings_; protected CefBrowser_N(CefClient client, String url, CefRequestContext context, - CefBrowser_N parent, Point inspectAt) { + CefBrowser_N parent, Point inspectAt, CefBrowserSettings settings) { client_ = client; url_ = url; request_context_ = context; parent_ = parent; inspectAt_ = inspectAt; + if (settings != null) + settings_ = settings.clone(); + else + settings_ = new CefBrowserSettings(); } protected String getUrl() { @@ -114,22 +116,52 @@ public synchronized void onBeforeClose() { if (request_context_ != null) request_context_.dispose(); if (parent_ != null) { parent_.closeDevTools(); - parent_.devTools_ = null; parent_ = null; } + if (devToolsClient_ != null) { + devToolsClient_.close(); + } + } + + @Override + public void openDevTools() { + openDevTools(null); } @Override - public CefBrowser getDevTools() { - return getDevTools(null); + public synchronized void openDevTools(Point inspectAt) { + createDevToolsBrowser(client_, url_, request_context_, this, inspectAt).createImmediately(); } @Override - public synchronized CefBrowser getDevTools(Point inspectAt) { - if (devTools_ == null) { - devTools_ = createDevToolsBrowser(client_, url_, request_context_, this, inspectAt); + public synchronized CefDevToolsClient getDevToolsClient() { + if (!isPending_ || isClosing_ || isClosed_) { + return null; } - return devTools_; + if (devToolsClient_ == null || devToolsClient_.isClosed()) { + devToolsClient_ = new CefDevToolsClient(this); + } + return devToolsClient_; + } + + CompletableFuture executeDevToolsMethod(String method, String parametersAsJson) { + CompletableFuture future = new CompletableFuture<>(); + N_ExecuteDevToolsMethod(method, parametersAsJson, new IntCallback() { + @Override + public void onComplete(int generatedMessageId) { + if (generatedMessageId <= 0) { + future.completeExceptionally(new DevToolsException( + String.format("Failed to execute DevTools method %s", method))); + } else { + future.complete(generatedMessageId); + } + } + }); + return future; + } + + CefRegistration addDevToolsMessageObserver(CefDevToolsMessageObserver observer) { + return N_AddDevToolsMessageObserver(observer); } protected abstract CefBrowser_N createDevToolsBrowser(CefClient client, String url, @@ -142,8 +174,8 @@ protected void createBrowser(CefClientHandler clientHandler, long windowHandle, boolean osr, boolean transparent, CefRequestContext context) { if (getNativeRef("CefBrowser") == 0 && !isPending_) { try { - N_CreateBrowser( - clientHandler, windowHandle, url, osr, transparent, context); + N_CreateBrowser(clientHandler, windowHandle, url, osr, transparent, context, + settings_); } catch (UnsatisfiedLinkError err) { err.printStackTrace(); } @@ -297,9 +329,9 @@ public CefFrame getFocusedFrame() { } @Override - public CefFrame getFrame(long identifier) { + public CefFrame getFrameByIdentifier(String identifier) { try { - return N_GetFrame(identifier); + return N_GetFrameByIdentifier(identifier); } catch (UnsatisfiedLinkError ule) { ule.printStackTrace(); return null; @@ -307,9 +339,9 @@ public CefFrame getFrame(long identifier) { } @Override - public CefFrame getFrame(String name) { + public CefFrame getFrameByName(String name) { try { - return N_GetFrame2(name); + return N_GetFrameByName(name); } catch (UnsatisfiedLinkError ule) { ule.printStackTrace(); return null; @@ -317,7 +349,7 @@ public CefFrame getFrame(String name) { } @Override - public Vector getFrameIdentifiers() { + public Vector getFrameIdentifiers() { try { return N_GetFrameIdentifiers(); } catch (UnsatisfiedLinkError ule) { @@ -366,6 +398,7 @@ public boolean hasDocument() { return false; } + @Override public void viewSource() { try { N_ViewSource(); @@ -374,6 +407,7 @@ public void viewSource() { } } + @Override public void getSource(CefStringVisitor visitor) { try { N_GetSource(visitor); @@ -382,6 +416,7 @@ public void getSource(CefStringVisitor visitor) { } } + @Override public void getText(CefStringVisitor visitor) { try { N_GetText(visitor); @@ -537,7 +572,8 @@ public void stopFinding(boolean clearSelection) { } } - protected final void closeDevTools() { + @Override + public void closeDevTools() { try { N_CloseDevTools(); } catch (UnsatisfiedLinkError ule) { @@ -728,11 +764,38 @@ protected final void notifyMoveOrResizeStarted() { } } + public void setWindowlessFrameRate(int frameRate) { + try { + N_SetWindowlessFrameRate(frameRate); + } catch (UnsatisfiedLinkError ule) { + ule.printStackTrace(); + } + } + + public CompletableFuture getWindowlessFrameRate() { + final CompletableFuture future = new CompletableFuture<>(); + try { + N_GetWindowlessFrameRate(future::complete); + } catch (UnsatisfiedLinkError ule) { + ule.printStackTrace(); + future.complete(0); + } + return future; + } + + private interface IntCallback { + void onComplete(int value); + } + private final native boolean N_CreateBrowser(CefClientHandler clientHandler, long windowHandle, String url, boolean osr, boolean transparent, - CefRequestContext context); + CefRequestContext context, CefBrowserSettings settings); private final native boolean N_CreateDevTools(CefBrowser parent, CefClientHandler clientHandler, long windowHandle, boolean osr, boolean transparent, Point inspectAt); + private final native void N_ExecuteDevToolsMethod( + String method, String parametersAsJson, IntCallback callback); + private final native CefRegistration N_AddDevToolsMessageObserver( + CefDevToolsMessageObserver observer); private final native long N_GetWindowHandle(long surfaceHandle); private final native boolean N_CanGoBack(); private final native void N_GoBack(); @@ -745,9 +808,9 @@ private final native boolean N_CreateDevTools(CefBrowser parent, CefClientHandle private final native int N_GetIdentifier(); private final native CefFrame N_GetMainFrame(); private final native CefFrame N_GetFocusedFrame(); - private final native CefFrame N_GetFrame(long identifier); - private final native CefFrame N_GetFrame2(String name); - private final native Vector N_GetFrameIdentifiers(); + private final native CefFrame N_GetFrameByIdentifier(String identifier); + private final native CefFrame N_GetFrameByName(String name); + private final native Vector N_GetFrameIdentifiers(); private final native Vector N_GetFrameNames(); private final native int N_GetFrameCount(); private final native boolean N_IsPopup(); @@ -790,4 +853,6 @@ private final native void N_DragTargetDragEnter( private final native void N_DragSourceSystemDragEnded(); private final native void N_UpdateUI(Rectangle contentRect, Rectangle browserRect); private final native void N_NotifyMoveOrResizeStarted(); + private final native void N_SetWindowlessFrameRate(int frameRate); + private final native void N_GetWindowlessFrameRate(IntCallback frameRateCallback); } diff --git a/java/org/cef/browser/CefDevToolsClient.java b/java/org/cef/browser/CefDevToolsClient.java new file mode 100644 index 00000000..393ad969 --- /dev/null +++ b/java/org/cef/browser/CefDevToolsClient.java @@ -0,0 +1,165 @@ +// Copyright (c) 2024 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +package org.cef.browser; + +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; + +public class CefDevToolsClient implements AutoCloseable { + private final Map> queuedCommands_ = + Collections.synchronizedMap(new HashMap<>()); + private final Set eventListeners_ = + Collections.synchronizedSet(new LinkedHashSet<>()); + private CefRegistration registration_; + private final CefBrowser_N browser_; + + /** + * Use {@link CefBrowser#getDevToolsClient()} to get an instance of this class. + */ + CefDevToolsClient(CefBrowser_N browser) { + this.browser_ = browser; + + registration_ = browser.addDevToolsMessageObserver(new CefDevToolsMessageObserver() { + @Override + public void onDevToolsMethodResult( + CefBrowser browser, int messageId, boolean success, String result) { + CompletableFuture future = getQueuedCommand(messageId); + if (success) { + future.complete(result); + } else { + future.completeExceptionally( + new DevToolsException("DevTools method failed", result)); + } + } + + @Override + public void onDevToolsEvent(CefBrowser browser, String method, String parameters) { + for (EventListener eventListener : eventListeners_) { + eventListener.onEvent(method, parameters); + } + } + }); + } + + @Override + public void close() { + queuedCommands_.clear(); + eventListeners_.clear(); + registration_ = null; + } + + public boolean isClosed() { + return registration_ == null; + } + + private CompletableFuture getQueuedCommand(Integer messageId) { + return queuedCommands_.computeIfAbsent(messageId, _ -> new CompletableFuture<>()); + } + + /** + * Execute a method call over the DevTools protocol. See the DevTools protocol documentation + * for details of supported methods and the expected syntax for parameters. + * + *

If an error occurs the returned future is completed exceptionally, otherwise its value is + * asynchronously set to the method result. + * + *

Call {@link #addEventListener(String, EventListener)} to subscribe to events. + * + * @param method the method name + * @return return a future with the method result if the method was executed successfully + */ + public CompletableFuture executeDevToolsMethod(String method) { + return executeDevToolsMethod(method, null); + } + + /** + * Execute a method call over the DevTools protocol. See the DevTools protocol documentation + * for details of supported methods and the expected syntax for parameters. + * + *

If an error occurs the returned future is completed exceptionally, otherwise its value is + * asynchronously set to the method result. + * + *

Call {@link #addEventListener(String, EventListener)} to subscribe to events. + * + * @param method the method name + * @param parametersAsJson JSON object with parameters, or null if no parameters are needed + * @return return a future with the method result if the method was executed successfully + */ + public CompletableFuture executeDevToolsMethod(String method, String parametersAsJson) { + if (isClosed()) { + CompletableFuture future = new CompletableFuture<>(); + future.completeExceptionally(new DevToolsException("Client is closed")); + return future; + } + + return browser_.executeDevToolsMethod(method, parametersAsJson) + .thenCompose(this::getQueuedCommand); + } + + /** + * Add an event listener for DevTools protocol events. Events by default are disabled + * and need to be enabled on a per domain basis, e.g. by sending Network.enable to enable + * network related events. + * + * @param eventListener the listener to add + */ + public void addEventListener(EventListener eventListener) { + eventListeners_.add(eventListener); + } + + /** + * Remove an event listener for DevTools protocol events. + * + * @param eventListener the listener to remove + */ + public void removeEventListener(EventListener eventListener) { + eventListeners_.remove(eventListener); + } + + public interface EventListener { + /** + * Method that will be called on receipt of an event. + * @param eventName the event name + * @param messageAsJson JSON object with the event message + */ + void onEvent(String eventName, String messageAsJson); + } + + public static final class DevToolsException extends Exception { + private static final long serialVersionUID = 3952948449841375372L; + + private final String json_; + + public DevToolsException(String message) { + this(message, null); + } + + public DevToolsException(String message, String json) { + super(message); + this.json_ = json; + } + + @Override + public String getMessage() { + String message = super.getMessage(); + if (json_ != null) message += ": " + json_; + return message; + } + + /** + * JSON object with the error details that were passed back by the DevTools + * host, or null if no further details are available. + */ + public String getJson() { + return json_; + } + } +} diff --git a/java/org/cef/browser/CefDevToolsMessageObserver.java b/java/org/cef/browser/CefDevToolsMessageObserver.java new file mode 100644 index 00000000..3a851356 --- /dev/null +++ b/java/org/cef/browser/CefDevToolsMessageObserver.java @@ -0,0 +1,34 @@ +// Copyright (c) 2024 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +package org.cef.browser; + +/** + * Used internally by {@link CefDevToolsClient}. + *

+ * Callback interface for {@link CefBrowser#addDevToolsMessageObserver(CefDevToolsMessageObserver)}. + * The methods of this class will be called on the CEF UI thread. + */ +interface CefDevToolsMessageObserver { + /** + * Method that will be called after attempted execution of a DevTools protocol method. + * + * @param browser the originating browser instance + * @param messageId the ID that identifies the originating method call + * @param success if the method succeeded, |success| will be true and |result| will be a JSON + * object containing the method call result. If the method call failed, |success| will + * be false and |result| will be a JSON object describing the error. + * @param result method call result or an error + */ + void onDevToolsMethodResult(CefBrowser browser, int messageId, boolean success, String result); + + /** + * Method that will be called on receipt of a DevTools protocol event. + * + * @param browser the originating browser instance + * @param method the method name + * @param parameters the event data + */ + void onDevToolsEvent(CefBrowser browser, String method, String parameters); +} diff --git a/java/org/cef/browser/CefFrame.java b/java/org/cef/browser/CefFrame.java index 3a2393fb..a64b4ed9 100644 --- a/java/org/cef/browser/CefFrame.java +++ b/java/org/cef/browser/CefFrame.java @@ -14,11 +14,11 @@ public interface CefFrame { void dispose(); /** - * Returns the globally unique identifier for this frame or < 0 if the + * Returns the globally unique identifier for this frame or an empty string if the * underlying frame does not yet exist. * @return The frame identifier */ - long getIdentifier(); + String getIdentifier(); /** * Emits the URL currently loaded in this frame. @@ -98,4 +98,9 @@ public interface CefFrame { * Execute paste in this frame. */ public void paste(); -} \ No newline at end of file + + /** + * Execute selectAll in this frame. + */ + public void selectAll(); +} diff --git a/java/org/cef/browser/CefFrame_N.java b/java/org/cef/browser/CefFrame_N.java index 8e129f1a..0bd1c6af 100644 --- a/java/org/cef/browser/CefFrame_N.java +++ b/java/org/cef/browser/CefFrame_N.java @@ -30,12 +30,12 @@ public void dispose() { } @Override - public long getIdentifier() { + public String getIdentifier() { try { return N_GetIdentifier(getNativeRef(null)); } catch (UnsatisfiedLinkError ule) { ule.printStackTrace(); - return -1; + return null; } } @@ -148,8 +148,16 @@ public void paste() { } } + public void selectAll() { + try { + N_SelectAll(getNativeRef(null)); + } catch (UnsatisfiedLinkError ule) { + ule.printStackTrace(); + } + } + private final native void N_Dispose(long self); - private final native long N_GetIdentifier(long self); + private final native String N_GetIdentifier(long self); private final native String N_GetURL(long self); private final native String N_GetName(long self); private final native boolean N_IsMain(long self); @@ -162,4 +170,5 @@ public void paste() { private final native void N_Cut(long self); private final native void N_Copy(long self); private final native void N_Paste(long self); + private final native void N_SelectAll(long self); } diff --git a/java/org/cef/browser/CefPaintEvent.java b/java/org/cef/browser/CefPaintEvent.java new file mode 100644 index 00000000..aed9af31 --- /dev/null +++ b/java/org/cef/browser/CefPaintEvent.java @@ -0,0 +1,51 @@ +// Copyright (c) 2024 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +package org.cef.browser; + +import java.awt.*; +import java.nio.ByteBuffer; + +public class CefPaintEvent { + private final CefBrowser browser; + private final boolean popup; + private final Rectangle[] dirtyRects; + private final ByteBuffer renderedFrame; + private final int width; + private final int height; + + public CefPaintEvent(CefBrowser browser, boolean popup, Rectangle[] dirtyRects, + ByteBuffer renderedFrame, int width, int height) { + this.browser = browser; + this.popup = popup; + this.dirtyRects = dirtyRects; + this.renderedFrame = renderedFrame; + this.width = width; + this.height = height; + } + + public CefBrowser getBrowser() { + return browser; + } + + public boolean getPopup() { + return popup; + } + + public Rectangle[] getDirtyRects() { + return dirtyRects; + } + + public ByteBuffer getRenderedFrame() { + return renderedFrame; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } +} \ No newline at end of file diff --git a/java/org/cef/browser/CefRegistration.java b/java/org/cef/browser/CefRegistration.java new file mode 100644 index 00000000..11051404 --- /dev/null +++ b/java/org/cef/browser/CefRegistration.java @@ -0,0 +1,24 @@ +// Copyright (c) 2024 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +package org.cef.browser; + +/** + * Used internally by {@link CefDevToolsClient}. + *

+ * Handle to observer registration, As long as this object is alive, the observer will stay + * registered. + */ +abstract class CefRegistration { + /** + * Removes the native reference from an unused object. + */ + public abstract void dispose(); + + @Override + public void finalize() throws Throwable { + dispose(); + super.finalize(); + } +} diff --git a/java/org/cef/browser/CefRegistration_N.java b/java/org/cef/browser/CefRegistration_N.java new file mode 100644 index 00000000..a7defd13 --- /dev/null +++ b/java/org/cef/browser/CefRegistration_N.java @@ -0,0 +1,33 @@ +// Copyright (c) 2024 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +package org.cef.browser; + +import org.cef.callback.CefNative; + +class CefRegistration_N extends CefRegistration implements CefNative { + // Used internally to store a pointer to the CEF object. + private long N_CefHandle = 0; + + @Override + public void setNativeRef(String identifier, long nativeRef) { + N_CefHandle = nativeRef; + } + + @Override + public long getNativeRef(String identifier) { + return N_CefHandle; + } + + @Override + public void dispose() { + try { + N_Dispose(N_CefHandle); + } catch (UnsatisfiedLinkError ule) { + ule.printStackTrace(); + } + } + + private final native void N_Dispose(long self); +} diff --git a/java/org/cef/handler/CefAppHandler.java b/java/org/cef/handler/CefAppHandler.java index 095e4747..b6ede710 100644 --- a/java/org/cef/handler/CefAppHandler.java +++ b/java/org/cef/handler/CefAppHandler.java @@ -72,4 +72,23 @@ public interface CefAppHandler { * currently pending scheduled call should be cancelled. */ public void onScheduleMessagePumpWork(long delay_ms); + + /** + * Implement this method to provide app-specific behavior when an already + * running app is relaunched with the same CefSettings.root_cache_path value. + * For example, activate an existing app window or create a new app window. + * |command_line| will be read-only. Do not keep a reference to + * |command_line| outside of this method. Return true if the relaunch is + * handled or false for default relaunch behavior. Default behavior will + * create a new default styled Chrome window. + * + * To avoid cache corruption only a single app instance is allowed to run for + * a given CefSettings.root_cache_path value. On relaunch the app checks a + * process singleton lock and then forwards the new launch arguments to the + * already running app process before exiting early. Client apps should + * therefore check the CefInitialize() return value for early exit before + * proceeding. + */ + public boolean onAlreadyRunningAppRelaunch( + CefCommandLine command_line, String current_directory); } diff --git a/java/org/cef/handler/CefAppHandlerAdapter.java b/java/org/cef/handler/CefAppHandlerAdapter.java index d74eee48..9947b74c 100644 --- a/java/org/cef/handler/CefAppHandlerAdapter.java +++ b/java/org/cef/handler/CefAppHandlerAdapter.java @@ -32,9 +32,10 @@ public void onBeforeCommandLineProcessing(String process_type, CefCommandLine co continue; } // Arguments with '--', '-' and, on Windows, '/' prefixes are considered switches. - int switchCnt = arg.startsWith("--") - ? 2 - : arg.startsWith("/") ? 1 : arg.startsWith("-") ? 1 : 0; + int switchCnt = arg.startsWith("--") ? 2 + : arg.startsWith("/") ? 1 + : arg.startsWith("-") ? 1 + : 0; switch (switchCnt) { case 2: // An argument of "--" will terminate switch parsing with all subsequent @@ -47,11 +48,13 @@ public void onBeforeCommandLineProcessing(String process_type, CefCommandLine co case 1: { // Switches can optionally have a value specified using the '=' delimiter // (e.g. "-switch=value"). - String[] switchVals = arg.substring(switchCnt).split("="); - if (switchVals.length == 2) { - command_line.appendSwitchWithValue(switchVals[0], switchVals[1]); + String switchStr = arg.substring(switchCnt); + int index = switchStr.indexOf('='); + if (index > 0) { + command_line.appendSwitchWithValue( + switchStr.substring(0, index), switchStr.substring(index + 1)); } else { - command_line.appendSwitch(switchVals[0]); + command_line.appendSwitch(switchStr); } break; } @@ -88,4 +91,11 @@ public void onContextInitialized() { public void onScheduleMessagePumpWork(long delay_ms) { CefApp.getInstance().doMessageLoopWork(delay_ms); } + + @Override + public boolean onAlreadyRunningAppRelaunch( + CefCommandLine command_line, String current_directory) { + // The default implementation does nothing + return false; + } } diff --git a/java/org/cef/handler/CefDialogHandler.java b/java/org/cef/handler/CefDialogHandler.java index 311de4cb..12ffdea7 100644 --- a/java/org/cef/handler/CefDialogHandler.java +++ b/java/org/cef/handler/CefDialogHandler.java @@ -38,11 +38,17 @@ enum FileDialogMode { * "image/*"), (b) individual file extensions (e.g. ".txt" or ".png"), or (c) * combined description and file extension delimited using "|" and ";" (e.g. * "Image Types|.png;.gif;.jpg"). + * @param acceptExtensions provides the semicolon-delimited expansion of MIME + * types to file extensions (if known, or empty string otherwise). + * @param acceptDescriptions provides the descriptions for MIME types (if known, + * or empty string otherwise). For example, the "image/*" mime type might + * have extensions ".png;.jpg;.bmp;..." and description "Image Files". * @param callback is a callback handler for handling own file dialogs. * * @return To display a custom dialog return true and execute callback. * To display the default dialog return false. */ public boolean onFileDialog(CefBrowser browser, FileDialogMode mode, String title, - String defaultFilePath, Vector acceptFilters, CefFileDialogCallback callback); + String defaultFilePath, Vector acceptFilters, Vector acceptExtensions, + Vector acceptDescriptions, CefFileDialogCallback callback); } diff --git a/java/org/cef/handler/CefDisplayHandler.java b/java/org/cef/handler/CefDisplayHandler.java index 0affefc5..f2a828eb 100644 --- a/java/org/cef/handler/CefDisplayHandler.java +++ b/java/org/cef/handler/CefDisplayHandler.java @@ -28,6 +28,13 @@ public interface CefDisplayHandler { */ public void onTitleChange(CefBrowser browser, String title); + /** + * Browser fullscreen mode changed. + * @param browser The browser generating the event. + * @param fullscreen True if fullscreen mode is on. + */ + public void onFullscreenModeChange(CefBrowser browser, boolean fullscreen); + /** * About to display a tooltip. * @param browser The browser generating the event. diff --git a/java/org/cef/handler/CefDisplayHandlerAdapter.java b/java/org/cef/handler/CefDisplayHandlerAdapter.java index 80ab96b6..90d22d50 100644 --- a/java/org/cef/handler/CefDisplayHandlerAdapter.java +++ b/java/org/cef/handler/CefDisplayHandlerAdapter.java @@ -24,6 +24,11 @@ public void onTitleChange(CefBrowser browser, String title) { return; } + @Override + public void onFullscreenModeChange(CefBrowser browser, boolean fullscreen) { + return; + } + @Override public boolean onTooltip(CefBrowser browser, String text) { return false; diff --git a/java/org/cef/handler/CefDownloadHandler.java b/java/org/cef/handler/CefDownloadHandler.java index 66ea49a4..3f0ee6f2 100644 --- a/java/org/cef/handler/CefDownloadHandler.java +++ b/java/org/cef/handler/CefDownloadHandler.java @@ -15,9 +15,11 @@ */ public interface CefDownloadHandler { /** - * Called before a download begins. By default the download will be canceled. - * Execute callback either asynchronously or in this method to continue the download - * if desired. + * Called before a download begins. Return true and execute |callback| either + * asynchronously or in this method to continue or cancel the download. + * Return false to proceed with default handling (cancel with Alloy style, + * download shelf with Chrome style). Do not keep a reference to + * downloadItem outside of this method. * * @param browser The desired browser. * @param downloadItem The item to be downloaded. Do not keep a reference to it outside this @@ -25,7 +27,7 @@ public interface CefDownloadHandler { * @param suggestedName is the suggested name for the download file. * @param callback start the download by calling the Continue method */ - public void onBeforeDownload(CefBrowser browser, CefDownloadItem downloadItem, + public boolean onBeforeDownload(CefBrowser browser, CefDownloadItem downloadItem, String suggestedName, CefBeforeDownloadCallback callback); /** diff --git a/java/org/cef/handler/CefDownloadHandlerAdapter.java b/java/org/cef/handler/CefDownloadHandlerAdapter.java index 8b1f46aa..f0311637 100644 --- a/java/org/cef/handler/CefDownloadHandlerAdapter.java +++ b/java/org/cef/handler/CefDownloadHandlerAdapter.java @@ -16,8 +16,10 @@ */ public abstract class CefDownloadHandlerAdapter implements CefDownloadHandler { @Override - public void onBeforeDownload(CefBrowser browser, CefDownloadItem downloadItem, - String suggestedName, CefBeforeDownloadCallback callback) {} + public boolean onBeforeDownload(CefBrowser browser, CefDownloadItem downloadItem, + String suggestedName, CefBeforeDownloadCallback callback) { + return false; + } @Override public void onDownloadUpdated( diff --git a/java/org/cef/handler/CefLoadHandler.java b/java/org/cef/handler/CefLoadHandler.java index 37d5a3e8..4f0bb831 100644 --- a/java/org/cef/handler/CefLoadHandler.java +++ b/java/org/cef/handler/CefLoadHandler.java @@ -187,12 +187,8 @@ enum ErrorCode { ERR_INVALID_HTTP_RESPONSE(-370), ERR_CONTENT_DECODING_INIT_FAILED(-371), ERR_HTTP2_RST_STREAM_NO_ERROR_RECEIVED(-372), - ERR_HTTP2_PUSHED_STREAM_NOT_AVAILABLE(-373), - ERR_HTTP2_CLAIMED_PUSHED_STREAM_RESET_BY_SERVER(-374), ERR_TOO_MANY_RETRIES(-375), ERR_HTTP2_STREAM_CLOSED(-376), - ERR_HTTP2_CLIENT_REFUSED_STREAM(-377), - ERR_HTTP2_PUSHED_RESPONSE_DOES_NOT_MATCH(-378), ERR_HTTP_RESPONSE_CODE_FAILURE(-379), ERR_QUIC_CERT_ROOT_NOT_KNOWN(-380), ERR_QUIC_GOAWAY_REQUEST_CAN_BE_RETRIED(-381), @@ -217,13 +213,6 @@ enum ErrorCode { ERR_INVALID_WEB_BUNDLE(-505), ERR_TRUST_TOKEN_OPERATION_FAILED(-506), ERR_TRUST_TOKEN_OPERATION_SUCCESS_WITHOUT_SENDING_REQUEST(-507), - ERR_FTP_FAILED(-601), - ERR_FTP_SERVICE_UNAVAILABLE(-602), - ERR_FTP_TRANSFER_ABORTED(-603), - ERR_FTP_FILE_BUSY(-604), - ERR_FTP_SYNTAX_ERROR(-605), - ERR_FTP_COMMAND_NOT_SUPPORTED(-606), - ERR_FTP_BAD_COMMAND_SEQUENCE(-607), ERR_PKCS12_IMPORT_BAD_PASSWORD(-701), ERR_PKCS12_IMPORT_FAILED(-702), ERR_IMPORT_CA_CERT_NOT_CA(-703), diff --git a/java/org/cef/handler/CefRenderHandler.java b/java/org/cef/handler/CefRenderHandler.java index 0a94bb2f..258df884 100644 --- a/java/org/cef/handler/CefRenderHandler.java +++ b/java/org/cef/handler/CefRenderHandler.java @@ -5,11 +5,13 @@ package org.cef.handler; import org.cef.browser.CefBrowser; +import org.cef.browser.CefPaintEvent; import org.cef.callback.CefDragData; import java.awt.Point; import java.awt.Rectangle; import java.nio.ByteBuffer; +import java.util.function.Consumer; /** * Implement this interface to handle events when window rendering is disabled. @@ -65,6 +67,24 @@ public interface CefRenderHandler { public void onPaint(CefBrowser browser, boolean popup, Rectangle[] dirtyRects, ByteBuffer buffer, int width, int height); + /** + * Add provided listener. + * @param listener Code that gets executed after a frame was rendered. + */ + public void addOnPaintListener(Consumer listener); + + /** + * Remove existing listeners and replace with provided listener. + * @param listener Code that gets executed after a frame was rendered. + */ + public void setOnPaintListener(Consumer listener); + + /** + * Remove provided listener. + * @param listener Code that gets executed after a frame was rendered. + */ + public void removeOnPaintListener(Consumer listener); + /** * Handle cursor changes. * @param browser The browser generating the event. diff --git a/java/org/cef/handler/CefRequestHandler.java b/java/org/cef/handler/CefRequestHandler.java index 7a508323..fef04af0 100644 --- a/java/org/cef/handler/CefRequestHandler.java +++ b/java/org/cef/handler/CefRequestHandler.java @@ -10,7 +10,6 @@ import org.cef.callback.CefCallback; import org.cef.misc.BoolRef; import org.cef.network.CefRequest; -import org.cef.network.CefURLRequest; /** * Implement this interface to handle events related to browser requests. The methods of this class @@ -24,7 +23,10 @@ enum TerminationStatus { TS_ABNORMAL_TERMINATION, //!< Non-zero exit status. TS_PROCESS_WAS_KILLED, //!< SIGKILL or task manager kill. TS_PROCESS_CRASHED, //!< Segmentation fault. - TS_PROCESS_OOM //!< Out of memory. + TS_PROCESS_OOM, //!< Out of memory. + TS_LAUNCH_FAILED, //!< Failed to launch. + TS_INTEGRITY_FAILURE, //!< Integrity check failed. + TS_NUM_VALUES } /** @@ -123,6 +125,9 @@ boolean onCertificateError(CefBrowser browser, CefLoadHandler.ErrorCode cert_err * Called on the browser process UI thread when the render process terminates unexpectedly. * @param browser The corresponding browser. * @param status Indicates how the process was terminated. + * @param error_code The process error code. + * @param error_string A string description of the error. */ - void onRenderProcessTerminated(CefBrowser browser, TerminationStatus status); + void onRenderProcessTerminated( + CefBrowser browser, TerminationStatus status, int error_code, String error_string); } diff --git a/java/org/cef/handler/CefRequestHandlerAdapter.java b/java/org/cef/handler/CefRequestHandlerAdapter.java index dd785529..a6703e91 100644 --- a/java/org/cef/handler/CefRequestHandlerAdapter.java +++ b/java/org/cef/handler/CefRequestHandlerAdapter.java @@ -11,7 +11,6 @@ import org.cef.handler.CefLoadHandler.ErrorCode; import org.cef.misc.BoolRef; import org.cef.network.CefRequest; -import org.cef.network.CefURLRequest; /** * An abstract adapter class for receiving browser request events. @@ -51,5 +50,6 @@ public boolean onCertificateError( } @Override - public void onRenderProcessTerminated(CefBrowser browser, TerminationStatus status) {} + public void onRenderProcessTerminated( + CefBrowser browser, TerminationStatus status, int error_code, String error_string) {} } diff --git a/java/org/cef/misc/CefPdfPrintSettings.java b/java/org/cef/misc/CefPdfPrintSettings.java index 49afdc28..a014d81c 100644 --- a/java/org/cef/misc/CefPdfPrintSettings.java +++ b/java/org/cef/misc/CefPdfPrintSettings.java @@ -105,6 +105,16 @@ public enum MarginType { */ public String footer_template; + /** + * Whether or not to generate tagged (accessible) PDF. + */ + public boolean generate_tagged_pdf; + + /** + * Whether or not to embed the document outline into the PDF. + */ + public boolean generate_document_outline; + public CefPdfPrintSettings() {} @Override @@ -125,6 +135,8 @@ public CefPdfPrintSettings clone() { tmp.display_header_footer = this.display_header_footer; tmp.header_template = this.header_template; tmp.footer_template = this.footer_template; + tmp.generate_tagged_pdf = this.generate_tagged_pdf; + tmp.generate_document_outline = this.generate_document_outline; return tmp; } } diff --git a/java/org/cef/network/CefPostDataElement.java b/java/org/cef/network/CefPostDataElement.java index f8a209b3..2d32219a 100644 --- a/java/org/cef/network/CefPostDataElement.java +++ b/java/org/cef/network/CefPostDataElement.java @@ -16,6 +16,7 @@ public static enum Type { PDE_TYPE_EMPTY, PDE_TYPE_BYTES, PDE_TYPE_FILE, + PDF_TYPE_NUM_VALUES, // probably should be PDE_TYPE, but wrong in CEF too } // This CTOR can't be called directly. Call method create() instead. diff --git a/java/org/cef/network/CefRequest.java b/java/org/cef/network/CefRequest.java index 47e38e92..5ce64451 100644 --- a/java/org/cef/network/CefRequest.java +++ b/java/org/cef/network/CefRequest.java @@ -41,6 +41,7 @@ public enum ResourceType { RT_NAVIGATION_PRELOAD_MAIN_FRAME, //!< A main-frame service worker navigation preload //!< request. RT_NAVIGATION_PRELOAD_SUB_FRAME, //!< A sub-frame service worker navigation preload request. + RT_NUM_VALUES, } /** @@ -317,7 +318,7 @@ public enum ReferrerPolicy { /** * Always the last value in this enumeration. */ - REFERRER_POLICY_LAST_VALUE + REFERRER_POLICY_NUM_VALUES } // This CTOR can't be called directly. Call method create() instead. diff --git a/java/tests/detailed/MainFrame.java b/java/tests/detailed/MainFrame.java index 5b1efeb5..212ff43d 100644 --- a/java/tests/detailed/MainFrame.java +++ b/java/tests/detailed/MainFrame.java @@ -6,29 +6,24 @@ import org.cef.CefApp; import org.cef.CefApp.CefVersion; +import org.cef.CefBrowserSettings; import org.cef.CefClient; import org.cef.CefSettings; -import org.cef.CefSettings.ColorType; -import org.cef.OS; import org.cef.browser.CefBrowser; import org.cef.browser.CefFrame; import org.cef.browser.CefMessageRouter; -import org.cef.browser.CefRequestContext; import org.cef.handler.CefDisplayHandlerAdapter; import org.cef.handler.CefFocusHandlerAdapter; import org.cef.handler.CefLoadHandlerAdapter; -import org.cef.handler.CefRequestContextHandlerAdapter; import org.cef.network.CefCookieManager; import java.awt.BorderLayout; import java.awt.KeyboardFocusManager; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; -import java.io.File; -import java.lang.Thread.UncaughtExceptionHandler; -import javax.swing.JFrame; import javax.swing.JPanel; +import javax.swing.SwingUtilities; import tests.detailed.dialog.DownloadDialog; import tests.detailed.handler.AppHandler; @@ -58,6 +53,7 @@ public static void main(String[] args) { boolean osrEnabledArg = false; boolean transparentPaintingEnabledArg = false; boolean createImmediately = false; + int windowless_frame_rate = 0; for (String arg : args) { arg = arg.toLowerCase(); if (arg.equals("--off-screen-rendering-enabled")) { @@ -66,6 +62,8 @@ public static void main(String[] args) { transparentPaintingEnabledArg = true; } else if (arg.equals("--create-immediately")) { createImmediately = true; + } else if (arg.equals("--windowless-frame-rate-60")) { + windowless_frame_rate = 60; } } @@ -73,10 +71,21 @@ public static void main(String[] args) { // MainFrame keeps all the knowledge to display the embedded browser // frame. - final MainFrame frame = new MainFrame( - osrEnabledArg, transparentPaintingEnabledArg, createImmediately, args); + final MainFrame frame = new MainFrame(osrEnabledArg, transparentPaintingEnabledArg, + createImmediately, windowless_frame_rate, args); frame.setSize(800, 600); frame.setVisible(true); + + if (osrEnabledArg && windowless_frame_rate != 0) { + frame.getBrowser().getWindowlessFrameRate().thenAccept( + framerate -> System.out.println("Framerate is:" + framerate)); + + frame.getBrowser().setWindowlessFrameRate(2); + frame.getBrowser().getWindowlessFrameRate().thenAccept( + framerate -> System.out.println("Framerate is:" + framerate)); + + frame.getBrowser().setWindowlessFrameRate(windowless_frame_rate); + } } private final CefClient client_; @@ -86,9 +95,10 @@ public static void main(String[] args) { private boolean browserFocus_ = true; private boolean osr_enabled_; private boolean transparent_painting_enabled_; + private JPanel contentPanel_; public MainFrame(boolean osrEnabled, boolean transparentPaintingEnabled, - boolean createImmediately, String[] args) { + boolean createImmediately, int windowless_frame_rate, String[] args) { this.osr_enabled_ = osrEnabled; this.transparent_painting_enabled_ = transparentPaintingEnabled; @@ -175,19 +185,25 @@ public void onStatusMessage(CefBrowser browser, String value) { @Override public void onLoadingStateChange(CefBrowser browser, boolean isLoading, boolean canGoBack, boolean canGoForward) { - control_pane_.update(browser, isLoading, canGoBack, canGoForward); - status_panel_.setIsInProgress(isLoading); - - if (!isLoading && !errorMsg_.isEmpty()) { - browser.loadURL(DataUri.create("text/html", errorMsg_)); - errorMsg_ = ""; - } + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + control_pane_.update(browser, isLoading, canGoBack, canGoForward); + status_panel_.setIsInProgress(isLoading); + + if (!isLoading && !errorMsg_.isEmpty()) { + browser.loadURL(DataUri.create("text/html", errorMsg_)); + errorMsg_ = ""; + } + } + }); } @Override public void onLoadError(CefBrowser browser, CefFrame frame, ErrorCode errorCode, String errorText, String failedUrl) { - if (errorCode != ErrorCode.ERR_NONE && errorCode != ErrorCode.ERR_ABORTED) { + if (errorCode != ErrorCode.ERR_NONE && errorCode != ErrorCode.ERR_ABORTED + && frame == browser.getMainFrame()) { errorMsg_ = ""; errorMsg_ += "Error while loading"; errorMsg_ += ""; @@ -200,14 +216,17 @@ public void onLoadError(CefBrowser browser, CefFrame frame, ErrorCode errorCode, } }); + CefBrowserSettings browserSettings = new CefBrowserSettings(); + browserSettings.windowless_frame_rate = windowless_frame_rate; + // Create the browser. - CefBrowser browser = client_.createBrowser( - "http://www.google.com", osrEnabled, null); + CefBrowser browser = client_.createBrowser("http://www.google.com", + transparentPaintingEnabled, null, browserSettings); setBrowser(browser); // Set up the UI for this example implementation. - JPanel contentPanel = createContentPanel(); - getContentPane().add(contentPanel, BorderLayout.CENTER); + contentPanel_ = createContentPanel(); + getContentPane().add(contentPanel_, BorderLayout.CENTER); // Clear focus from the browser when the address field gains focus. control_pane_.getAddressField().addFocusListener(new FocusAdapter() { @@ -238,8 +257,6 @@ public void onTakeFocus(CefBrowser browser, boolean next) { if (createImmediately) browser.createImmediately(); - // Add the browser to the UI. - MenuBar menuBar = new MenuBar( this, browser, control_pane_, downloadDialog, CefCookieManager.getGlobalManager()); @@ -258,6 +275,8 @@ public void onTakeFocus(CefBrowser browser, boolean next) { menuBar.addBookmark("Spellcheck Test", "client://tests/spellcheck.html"); menuBar.addBookmark("LocalStorage Test", "client://tests/localstorage.html"); menuBar.addBookmark("Transparency Test", "client://tests/transparency.html"); + menuBar.addBookmark("Fullscreen Test", + "https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_fullscreen2"); menuBar.addBookmarkSeparator(); menuBar.addBookmark( "javachromiumembedded", "https://bitbucket.org/chromiumembedded/java-cef"); diff --git a/java/tests/detailed/dialog/DevToolsDialog.java b/java/tests/detailed/dialog/DevToolsDialog.java index 74a3a766..07a61809 100644 --- a/java/tests/detailed/dialog/DevToolsDialog.java +++ b/java/tests/detailed/dialog/DevToolsDialog.java @@ -16,19 +16,20 @@ @SuppressWarnings("serial") public class DevToolsDialog extends JDialog { - private final CefBrowser devTools_; + private final CefBrowser browser_; public DevToolsDialog(Frame owner, String title, CefBrowser browser) { this(owner, title, browser, null); } public DevToolsDialog(Frame owner, String title, CefBrowser browser, Point inspectAt) { super(owner, title, false); + browser_ = browser; setLayout(new BorderLayout()); setSize(800, 600); setLocation(owner.getLocation().x + 20, owner.getLocation().y + 20); - devTools_ = browser.getDevTools(inspectAt); + browser.openDevTools(inspectAt); addComponentListener(new ComponentAdapter() { @Override @@ -40,7 +41,7 @@ public void componentHidden(ComponentEvent e) { @Override public void dispose() { - devTools_.close(true); + browser_.closeDevTools(); super.dispose(); } } diff --git a/java/tests/detailed/dialog/DownloadDialog.java b/java/tests/detailed/dialog/DownloadDialog.java index f9717a50..c3ffaeac 100644 --- a/java/tests/detailed/dialog/DownloadDialog.java +++ b/java/tests/detailed/dialog/DownloadDialog.java @@ -143,13 +143,15 @@ void update(CefDownloadItem downloadItem, CefDownloadItemCallback callback) { } @Override - public void onBeforeDownload(CefBrowser browser, CefDownloadItem downloadItem, + public boolean onBeforeDownload(CefBrowser browser, CefDownloadItem downloadItem, String suggestedName, CefBeforeDownloadCallback callback) { callback.Continue(suggestedName, true); DownloadObject dlObject = new DownloadObject(downloadItem, suggestedName); downloadObjects_.put(downloadItem.getId(), dlObject); downloadPanel_.add(dlObject); + + return true; } @Override diff --git a/java/tests/detailed/handler/KeyboardHandler.java b/java/tests/detailed/handler/KeyboardHandler.java index 350d0f3b..6785b550 100644 --- a/java/tests/detailed/handler/KeyboardHandler.java +++ b/java/tests/detailed/handler/KeyboardHandler.java @@ -20,6 +20,32 @@ public boolean onKeyEvent(CefBrowser browser, CefKeyEvent event) { browser.executeJavaScript("alert('You pressed the space bar!');", "", 0); } return true; + } else if (event.type == CefKeyEvent.EventType.KEYEVENT_RAWKEYDOWN && event.is_system_key) { + // CMD+[key] is not working on a Mac. + // This switch statement delegates the common keyboard shortcuts to the browser + switch (event.unmodified_character) { + case 'a': + browser.getFocusedFrame().selectAll(); + break; + case 'c': + browser.getFocusedFrame().copy(); + break; + case 'v': + browser.getFocusedFrame().paste(); + break; + case 'x': + browser.getFocusedFrame().cut(); + break; + case 'z': + browser.getFocusedFrame().undo(); + break; + case 'Z': + browser.getFocusedFrame().redo(); + break; + default: + return false; + } + return true; } return false; } diff --git a/java/tests/detailed/handler/RequestHandler.java b/java/tests/detailed/handler/RequestHandler.java index d80e1251..44d102a5 100644 --- a/java/tests/detailed/handler/RequestHandler.java +++ b/java/tests/detailed/handler/RequestHandler.java @@ -161,7 +161,9 @@ public boolean onCertificateError( } @Override - public void onRenderProcessTerminated(CefBrowser browser, TerminationStatus status) { - System.out.println("render process terminated: " + status); + public void onRenderProcessTerminated( + CefBrowser browser, TerminationStatus status, int error_code, String error_string) { + System.out.println("render process terminated: " + status + " errorCode: " + error_code + + " errorString: " + error_string); } } diff --git a/java/tests/detailed/ui/MenuBar.java b/java/tests/detailed/ui/MenuBar.java index a6fe40bc..d8d2f74c 100644 --- a/java/tests/detailed/ui/MenuBar.java +++ b/java/tests/detailed/ui/MenuBar.java @@ -4,10 +4,9 @@ package tests.detailed.ui; -import org.cef.CefApp; -import org.cef.CefClient; import org.cef.OS; import org.cef.browser.CefBrowser; +import org.cef.browser.CefDevToolsClient; import org.cef.callback.CefPdfPrintCallback; import org.cef.callback.CefRunFileDialogCallback; import org.cef.callback.CefStringVisitor; @@ -21,12 +20,10 @@ import java.awt.Container; import java.awt.Dimension; import java.awt.FlowLayout; -import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; -import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; import java.io.File; @@ -40,16 +37,14 @@ import javax.swing.ImageIcon; import javax.swing.JButton; +import javax.swing.JCheckBoxMenuItem; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; -import javax.swing.JLayeredPane; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JRootPane; import javax.swing.SwingUtilities; import tests.detailed.BrowserFrame; @@ -86,6 +81,7 @@ public void visit(String string) { private final DownloadDialog downloadDialog_; private final CefCookieManager cookieManager_; private boolean reparentPending_ = false; + private CefDevToolsClient devToolsClient_; public MenuBar(MainFrame owner, CefBrowser browser, ControlPanel control_pane, DownloadDialog downloadDialog, CefCookieManager cookieManager) { @@ -382,6 +378,37 @@ public void componentHidden(ComponentEvent e) { }); testMenu.add(showDevTools); + JMenu devToolsProtocolMenu = new JMenu("DevTools Protocol"); + JMenuItem autoDarkMode = devToolsProtocolMenu.add(new JCheckBoxMenuItem("Auto Dark Mode")); + autoDarkMode.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + // Toggle the auto dark mode override + String params = String.format("{ \"enabled\": %s }", autoDarkMode.isSelected()); + executeDevToolsMethod("Emulation.setAutoDarkModeOverride", params); + } + }); + JMenuItem checkContrast = devToolsProtocolMenu.add(new JMenuItem("Check Contrast")); + checkContrast.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + // Check contrast, which usually triggers a series of Audits.issueAdded events + executeDevToolsMethod("Audits.checkContrast"); + } + }); + JMenuItem enableCSS = devToolsProtocolMenu.add(new JMenuItem("Enable CSS Agent")); + enableCSS.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + // Enable the CSS agent, which usually triggers a series of CSS.styleSheetAdded + // events. We can only enable the CSS agent if the DOM agent is enabled first, so we + // need to chain the two commands. + executeDevToolsMethod("DOM.enable") + .thenCompose(_ -> executeDevToolsMethod("CSS.enable")); + } + }); + testMenu.add(devToolsProtocolMenu); + JMenuItem testURLRequest = new JMenuItem("URL Request"); testURLRequest.addActionListener(new ActionListener() { @Override @@ -416,9 +443,6 @@ public void run() { } else { newFrame.removeBrowser(new Runnable() { public void run() { - JRootPane rootPane = (JRootPane) owner_.getComponent(0); - Container container = rootPane.getContentPane(); - JPanel panel = (JPanel) container.getComponent(0); owner_.setBrowser(browser_); owner_.revalidate(); reparentButton.setText("Reparent <"); @@ -439,7 +463,7 @@ public void run() { newwindow.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - final MainFrame frame = new MainFrame(OS.isLinux(), false, false, null); + final MainFrame frame = new MainFrame(OS.isLinux(), false, false, 0, null); frame.setSize(800, 600); frame.setVisible(true); } @@ -547,6 +571,26 @@ private void displayScreenshot(BufferedImage aScreenshot) { frame.pack(); } + private CompletableFuture executeDevToolsMethod(String methodName) { + return executeDevToolsMethod(methodName, null); + } + + private CompletableFuture executeDevToolsMethod( + String methodName, String paramsAsJson) { + if (devToolsClient_ == null) { + devToolsClient_ = browser_.getDevToolsClient(); + devToolsClient_.addEventListener( + (method, json) -> System.out.println("CDP event " + method + ": " + json)); + } + + return devToolsClient_.executeDevToolsMethod(methodName, paramsAsJson) + .handle((error, json) -> { + System.out.println( + "CDP result of " + methodName + ": " + (error != null ? error : json)); + return null; + }); + } + public void addBookmarkSeparator() { bookmarkMenu_.addSeparator(); } diff --git a/java/tests/junittests/TestFrame.java b/java/tests/junittests/TestFrame.java index bdbc26a9..c04520ef 100644 --- a/java/tests/junittests/TestFrame.java +++ b/java/tests/junittests/TestFrame.java @@ -242,7 +242,8 @@ public boolean onCertificateError(CefBrowser browser, CefLoadHandler.ErrorCode c } @Override - public void onRenderProcessTerminated(CefBrowser browser, TerminationStatus status) {} + public void onRenderProcessTerminated( + CefBrowser browser, TerminationStatus status, int error_code, String error_string) {} // CefResourceRequestHandler methods: diff --git a/java/tests/simple/MainFrame.java b/java/tests/simple/MainFrame.java index 822c4c8f..93300397 100644 --- a/java/tests/simple/MainFrame.java +++ b/java/tests/simple/MainFrame.java @@ -8,7 +8,6 @@ import org.cef.CefApp.CefAppState; import org.cef.CefClient; import org.cef.CefSettings; -import org.cef.OS; import org.cef.browser.CefBrowser; import org.cef.browser.CefFrame; import org.cef.handler.CefAppHandlerAdapter; @@ -16,7 +15,6 @@ import org.cef.handler.CefFocusHandlerAdapter; import java.awt.BorderLayout; -import java.awt.Component; import java.awt.KeyboardFocusManager; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index 0368b692..1099cc48 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -54,6 +54,8 @@ set(JCEF_SRCS CefPrintSettings_N.h CefQueryCallback_N.cpp CefQueryCallback_N.h + CefRegistration_N.cpp + CefRegistration_N.h CefRequest_N.cpp CefRequest_N.h CefCallback_N.cpp @@ -83,6 +85,8 @@ set(JCEF_SRCS cookie_visitor.cpp cookie_visitor.h critical_wait.h + devtools_message_observer.cpp + devtools_message_observer.h dialog_handler.cpp dialog_handler.h display_handler.cpp @@ -95,6 +99,8 @@ set(JCEF_SRCS drag_handler.h focus_handler.cpp focus_handler.h + int_callback.cpp + int_callback.h jcef_version.h jni_scoped_helpers.h jni_scoped_helpers.cpp @@ -142,8 +148,6 @@ set(JCEF_SRCS set(JCEF_SRCS_LINUX critical_wait_posix.cpp jni_util_linux.cpp - signal_restore_posix.cpp - signal_restore_posix.h temp_window_x11.cc temp_window_x11.h util_linux.cpp @@ -151,8 +155,6 @@ set(JCEF_SRCS_LINUX ) set(JCEF_SRCS_MAC critical_wait_posix.cpp - signal_restore_posix.cpp - signal_restore_posix.h temp_window_mac.h temp_window_mac.mm util_mac.h diff --git a/native/CefApp.cpp b/native/CefApp.cpp index c1e2eef4..3adb6961 100644 --- a/native/CefApp.cpp +++ b/native/CefApp.cpp @@ -7,7 +7,7 @@ #include #include "include/cef_app.h" -#include "include/cef_version.h" +#include "include/cef_version_info.h" #include "context.h" #include "jcef_version.h" diff --git a/native/CefBrowser_N.cpp b/native/CefBrowser_N.cpp index af6543b7..f4ed2c6e 100644 --- a/native/CefBrowser_N.cpp +++ b/native/CefBrowser_N.cpp @@ -6,12 +6,15 @@ #include "include/base/cef_callback.h" #include "include/cef_browser.h" +#include "include/cef_parser.h" #include "include/cef_task.h" #include "include/wrapper/cef_closure_task.h" #include "browser_process_handler.h" #include "client_handler.h" #include "critical_wait.h" +#include "devtools_message_observer.h" +#include "int_callback.h" #include "jni_util.h" #include "life_span_handler.h" #include "pdf_print_callback.h" @@ -968,6 +971,7 @@ struct JNIObjectsForCreate { ScopedJNIObjectGlobal url; ScopedJNIObjectGlobal jcontext; ScopedJNIObjectGlobal jinspectAt; + ScopedJNIObjectGlobal jbrowserSettings; JNIObjectsForCreate(JNIEnv* env, jobject _jbrowser, @@ -975,7 +979,8 @@ struct JNIObjectsForCreate { jobject _jclientHandler, jstring _url, jobject _jcontext, - jobject _jinspectAt) + jobject _jinspectAt, + jobject _browserSettings) : jbrowser(env, _jbrowser), @@ -983,7 +988,8 @@ struct JNIObjectsForCreate { jclientHandler(env, _jclientHandler), url(env, _url), jcontext(env, _jcontext), - jinspectAt(env, _jinspectAt) {} + jinspectAt(env, _jinspectAt), + jbrowserSettings(env, _browserSettings) {} }; void create(std::shared_ptr objs, @@ -1001,43 +1007,53 @@ void create(std::shared_ptr objs, if (!lifeSpanHandler.get()) return; - CefWindowInfo windowInfo; - windowInfo.SetAsWindowless((CefWindowHandle)windowHandle); + CefRefPtr parentBrowser = + GetCefFromJNIObject(env, objs->jparentBrowser, "CefBrowser"); + CefWindowInfo windowInfo; CefBrowserSettings settings; + // If parentBrowser is set, we want to show the DEV-Tools for that browser. + // Since that cannot be an Alloy-style window, it cannot be integrated into + // Java UI but must be opened as a pop-up. + if (parentBrowser.get() != nullptr) { + CefPoint inspectAt; + if (objs->jinspectAt != nullptr) { + int x, y; + GetJNIPoint(env, objs->jinspectAt, &x, &y); + inspectAt.Set(x, y); + } + + parentBrowser->GetHost()->ShowDevTools(windowInfo, clientHandler.get(), + settings, inspectAt); + JNI_CALL_VOID_METHOD(env, objs->jbrowser, "notifyBrowserCreated", "()V"); + return; + } + + windowInfo.SetAsWindowless((CefWindowHandle)windowHandle); + if (transparent == JNI_FALSE) { // Specify an opaque background color (white) to disable transparency. settings.background_color = CefColorSetARGB(255, 255, 255, 255); } + ScopedJNIClass cefBrowserSettings(env, "org/cef/CefBrowserSettings"); + if (cefBrowserSettings != nullptr && + objs->jbrowserSettings != nullptr) { // Dev-tools settings are null + GetJNIFieldInt(env, cefBrowserSettings, objs->jbrowserSettings, + "windowless_frame_rate", &settings.windowless_frame_rate); + } + CefRefPtr browserObj; CefString strUrl = GetJNIString(env, static_cast(objs->url.get())); CefRefPtr context = GetCefFromJNIObject( env, objs->jcontext, "CefRequestContext"); - CefRefPtr parentBrowser = - GetCefFromJNIObject(env, objs->jparentBrowser, "CefBrowser"); - // Add a global ref that will be released in LifeSpanHandler::OnAfterCreated. jobject globalRef = env->NewGlobalRef(objs->jbrowser); lifeSpanHandler->registerJBrowser(globalRef); - // If parentBrowser is set, we want to show the DEV-Tools for that browser - if (parentBrowser.get() != nullptr) { - CefPoint inspectAt; - if (objs->jinspectAt != nullptr) { - int x, y; - GetJNIPoint(env, objs->jinspectAt, &x, &y); - inspectAt.Set(x, y); - } - parentBrowser->GetHost()->ShowDevTools(windowInfo, clientHandler.get(), - settings, inspectAt); - JNI_CALL_VOID_METHOD(env, objs->jbrowser, "notifyBrowserCreated", "()V"); - return; - } - CefRefPtr extra_info; auto router_configs = BrowserProcessHandler::GetMessageRouterConfigs(); if (router_configs) { @@ -1046,6 +1062,10 @@ void create(std::shared_ptr objs, extra_info->SetList("router_configs", router_configs); } + // JCEF requires Alloy runtime style for "normal" browsers in order for them + // to be integratable into Java UI. + windowInfo.runtime_style = CEF_RUNTIME_STYLE_ALLOY; + bool result = CefBrowserHost::CreateBrowser( windowInfo, clientHandler.get(), strUrl, settings, extra_info, context); if (!result) { @@ -1067,6 +1087,26 @@ void getZoomLevel(CefRefPtr host, } } +void executeDevToolsMethod(CefRefPtr host, + const CefString& method, + const CefString& parametersAsJson, + CefRefPtr callback) { + CefRefPtr parameters = nullptr; + if (!parametersAsJson.empty()) { + CefRefPtr value = CefParseJSON( + parametersAsJson, cef_json_parser_options_t::JSON_PARSER_RFC); + + if (!value || value->GetType() != VTYPE_DICTIONARY) { + callback->onComplete(0); + return; + } + + parameters = value->GetDictionary(); + } + + callback->onComplete(host->ExecuteDevToolsMethod(0, method, parameters)); +} + // Removed because we don't care about when the native parent window changes. // This fixes a compile issue on macOS - ds58 //void OnAfterParentChanged(CefRefPtr browser) { @@ -1087,21 +1127,6 @@ void getZoomLevel(CefRefPtr host, // } //} -jobject NewJNILongVector(JNIEnv* env, const std::vector& vals) { - ScopedJNIObjectLocal jvector(env, "java/util/Vector"); - if (!jvector) - return nullptr; - - std::vector::const_iterator iter; - for (iter = vals.begin(); iter != vals.end(); ++iter) { - ScopedJNIObjectLocal argument( - env, NewJNIObject(env, "java/lang/Long", "(J)V", (jlong)*iter)); - JNI_CALL_VOID_METHOD(env, jvector, "addElement", "(Ljava/lang/Object;)V", - argument.get()); - } - return jvector.Release(); -} - CefPdfPrintSettings GetJNIPdfPrintSettings(JNIEnv* env, jobject obj) { CefString tmp; CefPdfPrintSettings settings; @@ -1169,9 +1194,25 @@ CefPdfPrintSettings GetJNIPdfPrintSettings(JNIEnv* env, jobject obj) { tmp.clear(); } + GetJNIFieldBoolean(env, cls, obj, "generate_tagged_pdf", + &settings.generate_tagged_pdf); + + GetJNIFieldBoolean(env, cls, obj, "generate_document_outline", + &settings.generate_document_outline); + return settings; } +// JNI CefRegistration object. +class ScopedJNIRegistration : public ScopedJNIObject { + public: + ScopedJNIRegistration(JNIEnv* env, CefRefPtr obj) + : ScopedJNIObject(env, + obj, + "org/cef/browser/CefRegistration_N", + "CefRegistration") {} +}; + } // namespace JNIEXPORT jboolean JNICALL @@ -1182,9 +1223,11 @@ Java_org_cef_browser_CefBrowser_1N_N_1CreateBrowser(JNIEnv* env, jstring url, jboolean osr, jboolean transparent, - jobject jcontext) { - std::shared_ptr objs(new JNIObjectsForCreate( - env, jbrowser, nullptr, jclientHandler, url, jcontext, nullptr)); + jobject jcontext, + jobject browserSettings) { + std::shared_ptr objs( + new JNIObjectsForCreate(env, jbrowser, nullptr, jclientHandler, url, + jcontext, nullptr, browserSettings)); if (CefCurrentlyOn(TID_UI)) { create(objs, windowHandle, osr, transparent); } else { @@ -1205,7 +1248,7 @@ Java_org_cef_browser_CefBrowser_1N_N_1CreateDevTools(JNIEnv* env, jobject inspect) { std::shared_ptr objs( new JNIObjectsForCreate(env, jbrowser, jparent, jclientHandler, nullptr, - nullptr, inspect)); + nullptr, inspect, nullptr)); if (CefCurrentlyOn(TID_UI)) { create(objs, windowHandle, osr, transparent); } else { @@ -1215,6 +1258,52 @@ Java_org_cef_browser_CefBrowser_1N_N_1CreateDevTools(JNIEnv* env, return JNI_FALSE; // set asynchronously } +JNIEXPORT void JNICALL +Java_org_cef_browser_CefBrowser_1N_N_1ExecuteDevToolsMethod( + JNIEnv* env, + jobject jbrowser, + jstring method, + jstring parametersAsJson, + jobject jcallback) { + CefRefPtr callback = new IntCallback(env, jcallback); + + CefRefPtr browser = GetJNIBrowser(env, jbrowser); + if (!browser.get()) { + callback->onComplete(0); + return; + } + + CefString strMethod = GetJNIString(env, method); + CefString strParametersAsJson = GetJNIString(env, parametersAsJson); + + if (CefCurrentlyOn(TID_UI)) { + executeDevToolsMethod(browser->GetHost(), strMethod, strParametersAsJson, + callback); + } else { + CefPostTask(TID_UI, + base::BindOnce(executeDevToolsMethod, browser->GetHost(), + strMethod, strParametersAsJson, callback)); + } +} + +JNIEXPORT jobject JNICALL +Java_org_cef_browser_CefBrowser_1N_N_1AddDevToolsMessageObserver( + JNIEnv* env, + jobject jbrowser, + jobject jobserver) { + CefRefPtr browser = + JNI_GET_BROWSER_OR_RETURN(env, jbrowser, NULL); + + CefRefPtr observer = + new DevToolsMessageObserver(env, jobserver); + + CefRefPtr registration = + browser->GetHost()->AddDevToolsMessageObserver(observer); + + ScopedJNIRegistration jregistration(env, registration); + return jregistration.Release(); +} + JNIEXPORT jlong JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetWindowHandle(JNIEnv* env, jobject obj, @@ -1310,11 +1399,12 @@ Java_org_cef_browser_CefBrowser_1N_N_1GetFocusedFrame(JNIEnv* env, } JNIEXPORT jobject JNICALL -Java_org_cef_browser_CefBrowser_1N_N_1GetFrame(JNIEnv* env, - jobject obj, - jlong identifier) { +Java_org_cef_browser_CefBrowser_1N_N_1GetFrameByIdentifier(JNIEnv* env, + jobject obj, + jstring identifier) { CefRefPtr browser = JNI_GET_BROWSER_OR_RETURN(env, obj, nullptr); - CefRefPtr frame = browser->GetFrame(identifier); + CefRefPtr frame = + browser->GetFrameByIdentifier(GetJNIString(env, identifier)); if (!frame) return nullptr; ScopedJNIFrame jframe(env, frame); @@ -1322,11 +1412,11 @@ Java_org_cef_browser_CefBrowser_1N_N_1GetFrame(JNIEnv* env, } JNIEXPORT jobject JNICALL -Java_org_cef_browser_CefBrowser_1N_N_1GetFrame2(JNIEnv* env, - jobject obj, - jstring name) { +Java_org_cef_browser_CefBrowser_1N_N_1GetFrameByName(JNIEnv* env, + jobject obj, + jstring name) { CefRefPtr browser = JNI_GET_BROWSER_OR_RETURN(env, obj, nullptr); - CefRefPtr frame = browser->GetFrame(GetJNIString(env, name)); + CefRefPtr frame = browser->GetFrameByName(GetJNIString(env, name)); if (!frame) return nullptr; ScopedJNIFrame jframe(env, frame); @@ -1343,9 +1433,9 @@ JNIEXPORT jobject JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetFrameIdentifiers(JNIEnv* env, jobject obj) { CefRefPtr browser = JNI_GET_BROWSER_OR_RETURN(env, obj, nullptr); - std::vector identifiers; + std::vector identifiers; browser->GetFrameIdentifiers(identifiers); - return NewJNILongVector(env, identifiers); + return NewJNIStringVector(env, identifiers); } JNIEXPORT jobject JNICALL @@ -1473,7 +1563,6 @@ Java_org_cef_browser_CefBrowser_1N_N_1SetWindowVisibility(JNIEnv* env, } #endif } - JNIEXPORT jdouble JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetZoomLevel(JNIEnv* env, jobject obj) { CefRefPtr browser = JNI_GET_BROWSER_OR_RETURN(env, obj, 0.0); @@ -2068,3 +2157,38 @@ Java_org_cef_browser_CefBrowser_1N_N_1NotifyMoveOrResizeStarted(JNIEnv* env, } #endif } + +JNIEXPORT void JNICALL +Java_org_cef_browser_CefBrowser_1N_N_1SetWindowlessFrameRate(JNIEnv* env, + jobject jbrowser, + jint frameRate) { + CefRefPtr browser = JNI_GET_BROWSER_OR_RETURN(env, jbrowser); + CefRefPtr host = browser->GetHost(); + host->SetWindowlessFrameRate(frameRate); +} + +void getWindowlessFrameRate(CefRefPtr host, + CefRefPtr callback) { + callback->onComplete((jint)host->GetWindowlessFrameRate()); +} + +JNIEXPORT void JNICALL +Java_org_cef_browser_CefBrowser_1N_N_1GetWindowlessFrameRate( + JNIEnv* env, + jobject jbrowser, + jobject jintCallback) { + CefRefPtr callback = new IntCallback(env, jintCallback); + + CefRefPtr browser = GetJNIBrowser(env, jbrowser); + if (!browser.get()) { + callback->onComplete(0); + return; + } + + CefRefPtr host = browser->GetHost(); + if (CefCurrentlyOn(TID_UI)) { + getWindowlessFrameRate(host, callback); + } else { + CefPostTask(TID_UI, base::BindOnce(getWindowlessFrameRate, host, callback)); + } +} diff --git a/native/CefBrowser_N.h b/native/CefBrowser_N.h index bd0fd0d0..4aa37469 100644 --- a/native/CefBrowser_N.h +++ b/native/CefBrowser_N.h @@ -11,7 +11,7 @@ extern "C" { * Class: org_cef_browser_CefBrowser_N * Method: N_CreateBrowser * Signature: - * (Lorg/cef/handler/CefClientHandler;JLjava/lang/String;ZZLjava/awt/Component;Lorg/cef/browser/CefRequestContext;)Z + * (Lorg/cef/handler/CefClientHandler;JLjava/lang/String;ZZLjava/awt/Component;Lorg/cef/browser/CefRequestContext;Lorg/cef/CefBrowserSettings;)Z */ JNIEXPORT jboolean JNICALL Java_org_cef_browser_CefBrowser_1N_N_1CreateBrowser(JNIEnv*, @@ -21,6 +21,7 @@ Java_org_cef_browser_CefBrowser_1N_N_1CreateBrowser(JNIEnv*, jstring, jboolean, jboolean, + jobject, jobject); /* @@ -37,8 +38,32 @@ Java_org_cef_browser_CefBrowser_1N_N_1CreateDevTools(JNIEnv*, jlong, jboolean, jboolean, + jobject, jobject); +/* + * Class: org_cef_browser_CefBrowser_N + * Method: N_ExecuteDevToolsMethod + * Signature: + * (Ljava/lang/String;Ljava/lang/String;Lorg/cef/browser/CefBrowser_N/IntCallback;)V + */ +JNIEXPORT void JNICALL +Java_org_cef_browser_CefBrowser_1N_N_1ExecuteDevToolsMethod(JNIEnv*, + jobject, + jstring, + jstring, + jobject); + +/* + * Class: org_cef_browser_CefBrowser_N + * Method: N_AddDevToolsMessageObserver + * Signature: + * (Lorg/cef/browser/CefDevToolsMessageObserver;)Lorg/cef/browser/CefRegistration; + */ +JNIEXPORT jobject JNICALL +Java_org_cef_browser_CefBrowser_1N_N_1AddDevToolsMessageObserver(JNIEnv*, + jobject); + /* * Class: org_cef_browser_CefBrowser_N * Method: N_GetWindowHandle @@ -137,19 +162,21 @@ Java_org_cef_browser_CefBrowser_1N_N_1GetFocusedFrame(JNIEnv*, jobject); /* * Class: org_cef_browser_CefBrowser_N - * Method: N_GetFrame - * Signature: (J)Lorg/cef/browser/CefFrame; + * Method: N_GetFrameByIdentifier + * Signature: (Ljava/lang/String;)Lorg/cef/browser/CefFrame; */ JNIEXPORT jobject JNICALL -Java_org_cef_browser_CefBrowser_1N_N_1GetFrame(JNIEnv*, jobject, jlong); +Java_org_cef_browser_CefBrowser_1N_N_1GetFrameByIdentifier(JNIEnv*, + jobject, + jstring); /* * Class: org_cef_browser_CefBrowser_N - * Method: N_GetFrame2 + * Method: N_GetFrameByName * Signature: (Ljava/lang/String;)Lorg/cef/browser/CefFrame; */ JNIEXPORT jobject JNICALL -Java_org_cef_browser_CefBrowser_1N_N_1GetFrame2(JNIEnv*, jobject, jstring); +Java_org_cef_browser_CefBrowser_1N_N_1GetFrameByName(JNIEnv*, jobject, jstring); /* * Class: org_cef_browser_CefBrowser_N @@ -346,7 +373,7 @@ Java_org_cef_browser_CefBrowser_1N_N_1PrintToPDF(JNIEnv*, /* * Class: org_cef_browser_CefBrowser_N * Method: N_Find - * Signature: (ILjava/lang/String;ZZZ)V + * Signature: (Ljava/lang/String;ZZZ)V */ JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1Find(JNIEnv*, jobject, @@ -508,6 +535,37 @@ JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1NotifyMoveOrResizeStarted(JNIEnv*, jobject); +/* + * Class: org_cef_browser_CefBrowser_N + * Method: N_SetWindowlessFrameRate + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_org_cef_browser_CefBrowser_1N_N_1SetWindowlessFrameRate(JNIEnv*, + jobject, + jint); + +/* + * Class: org_cef_browser_CefBrowser_N + * Method: N_GetWindowlessFrameRate + * Signature: (Lorg/cef/browser/CefBrowser_N/IntCallback;)V + */ +JNIEXPORT void JNICALL +Java_org_cef_browser_CefBrowser_1N_N_1GetWindowlessFrameRate(JNIEnv*, + jobject, + jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class org_cef_browser_CefBrowser_N_IntCallback */ + +#ifndef _Included_org_cef_browser_CefBrowser_N_IntCallback +#define _Included_org_cef_browser_CefBrowser_N_IntCallback +#ifdef __cplusplus +extern "C" { +#endif #ifdef __cplusplus } #endif diff --git a/native/CefFileDialogCallback_N.h b/native/CefFileDialogCallback_N.h index 1f11dae9..1da3ded8 100644 --- a/native/CefFileDialogCallback_N.h +++ b/native/CefFileDialogCallback_N.h @@ -10,13 +10,12 @@ extern "C" { /* * Class: org_cef_callback_CefFileDialogCallback_N * Method: N_Continue - * Signature: (JILjava/util/Vector;)V + * Signature: (JLjava/util/Vector;)V */ JNIEXPORT void JNICALL Java_org_cef_callback_CefFileDialogCallback_1N_N_1Continue(JNIEnv*, jobject, jlong, - jint, jobject); /* diff --git a/native/CefFrame_N.cpp b/native/CefFrame_N.cpp index 3fc93790..cab338ed 100644 --- a/native/CefFrame_N.cpp +++ b/native/CefFrame_N.cpp @@ -27,14 +27,14 @@ JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1Dispose(JNIEnv* env, ClearSelf(env, obj); } -JNIEXPORT jlong JNICALL +JNIEXPORT jstring JNICALL Java_org_cef_browser_CefFrame_1N_N_1GetIdentifier(JNIEnv* env, jobject obj, jlong self) { CefRefPtr frame = GetSelf(self); if (!frame) - return (jlong)-1; - return (jlong)frame->GetIdentifier(); + return nullptr; + return NewJNIString(env, frame->GetIdentifier()); } JNIEXPORT jstring JNICALL @@ -164,3 +164,14 @@ JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1Paste(JNIEnv* env, frame->Paste(); } + +JNIEXPORT void JNICALL +Java_org_cef_browser_CefFrame_1N_N_1SelectAll(JNIEnv* env, + jobject obj, + jlong self) { + CefRefPtr frame = GetSelf(self); + if (!frame) + return; + + frame->SelectAll(); +} diff --git a/native/CefFrame_N.h b/native/CefFrame_N.h index e1f6b459..a1568181 100644 --- a/native/CefFrame_N.h +++ b/native/CefFrame_N.h @@ -19,9 +19,9 @@ JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1Dispose(JNIEnv*, /* * Class: org_cef_browser_CefFrame_N * Method: N_GetIdentifier - * Signature: (J)J + * Signature: (J)Ljava/lang/String; */ -JNIEXPORT jlong JNICALL +JNIEXPORT jstring JNICALL Java_org_cef_browser_CefFrame_1N_N_1GetIdentifier(JNIEnv*, jobject, jlong); /* @@ -135,6 +135,15 @@ JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1Paste(JNIEnv*, jobject, jlong); +/* + * Class: org_cef_browser_CefFrame_N + * Method: N_SelectAll + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1SelectAll(JNIEnv*, + jobject, + jlong); + #ifdef __cplusplus } #endif diff --git a/native/CefPostDataElement_N.cpp b/native/CefPostDataElement_N.cpp index a756107b..63f4e695 100644 --- a/native/CefPostDataElement_N.cpp +++ b/native/CefPostDataElement_N.cpp @@ -98,6 +98,8 @@ Java_org_cef_network_CefPostDataElement_1N_N_1GetType(JNIEnv* env, jtype); JNI_CASE(env, "org/cef/network/CefPostDataElement$Type", PDE_TYPE_FILE, jtype); + JNI_CASE(env, "org/cef/network/CefPostDataElement$Type", + PDF_TYPE_NUM_VALUES, jtype); } return jtype; } diff --git a/native/CefRegistration_N.cpp b/native/CefRegistration_N.cpp new file mode 100644 index 00000000..dc23751d --- /dev/null +++ b/native/CefRegistration_N.cpp @@ -0,0 +1,14 @@ +// Copyright (c) 2024 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "CefRegistration_N.h" +#include "include/cef_registration.h" +#include "jni_scoped_helpers.h" + +JNIEXPORT void JNICALL +Java_org_cef_browser_CefRegistration_1N_N_1Dispose(JNIEnv* env, + jobject obj, + jlong self) { + SetCefForJNIObject(env, obj, NULL, "CefRegistration"); +} diff --git a/native/CefRegistration_N.h b/native/CefRegistration_N.h new file mode 100644 index 00000000..9747b04b --- /dev/null +++ b/native/CefRegistration_N.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_cef_browser_CefRegistration_N */ + +#ifndef _Included_org_cef_browser_CefRegistration_N +#define _Included_org_cef_browser_CefRegistration_N +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_cef_browser_CefRegistration_N + * Method: N_Dispose + * Signature: (J)V + */ +JNIEXPORT void JNICALL +Java_org_cef_browser_CefRegistration_1N_N_1Dispose(JNIEnv*, jobject, jlong); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/native/CefRequest_N.cpp b/native/CefRequest_N.cpp index b92f2774..626a76e5 100644 --- a/native/CefRequest_N.cpp +++ b/native/CefRequest_N.cpp @@ -126,8 +126,8 @@ Java_org_cef_network_CefRequest_1N_N_1SetReferrer(JNIEnv* env, policy = REFERRER_POLICY_NO_REFERRER; } else if (IsJNIEnumValue(env, jpolicy, "org/cef/network/CefRequest$ReferrerPolicy", - "REFERRER_POLICY_LAST_VALUE")) { - policy = REFERRER_POLICY_LAST_VALUE; + "REFERRER_POLICY_NUM_VALUES")) { + policy = REFERRER_POLICY_NUM_VALUES; } } @@ -399,6 +399,8 @@ Java_org_cef_network_CefRequest_1N_N_1GetResourceType(JNIEnv* env, RT_NAVIGATION_PRELOAD_MAIN_FRAME, result); JNI_CASE(env, "org/cef/network/CefRequest$ResourceType", RT_NAVIGATION_PRELOAD_SUB_FRAME, result); + JNI_CASE(env, "org/cef/network/CefRequest$ResourceType", RT_NUM_VALUES, + result); } return result; } diff --git a/native/browser_process_handler.cpp b/native/browser_process_handler.cpp index 38c8fdca..ad583e87 100644 --- a/native/browser_process_handler.cpp +++ b/native/browser_process_handler.cpp @@ -50,6 +50,31 @@ void BrowserProcessHandler::OnScheduleMessagePumpWork(int64_t delay_ms) { delay_ms); } +bool BrowserProcessHandler::OnAlreadyRunningAppRelaunch( + CefRefPtr command_line, + const CefString& current_directory) { + if (!handle_) + return false; + + ScopedJNIEnv env; + if (!env) + return false; + + ScopedJNIObject jcommandLine( + env, command_line, "org/cef/callback/CefCommandLine_N", "CefCommandLine"); + jcommandLine.SetTemporary(); + ScopedJNIString jcurrentDirectory(env, current_directory); + + jboolean jresult = 0; + + JNI_CALL_BOOLEAN_METHOD( + jresult, env, handle_, "onAlreadyRunningAppRelaunch", + "(Lorg/cef/callback/CefCommandLine;Ljava/lang/String;)Z", + jcommandLine.get(), jcurrentDirectory.get()); + + return jresult; +} + // static CefRefPtr BrowserProcessHandler::GetMessageRouterConfigs() { int idx = 0; diff --git a/native/browser_process_handler.h b/native/browser_process_handler.h index 260ebd66..8bbf29e3 100644 --- a/native/browser_process_handler.h +++ b/native/browser_process_handler.h @@ -34,6 +34,8 @@ class BrowserProcessHandler : public CefBrowserProcessHandler { void OnContextInitialized() override; void OnScheduleMessagePumpWork(int64_t delay_ms) override; + bool OnAlreadyRunningAppRelaunch(CefRefPtr command_line, + const CefString& current_directory) override; static CefRefPtr GetMessageRouterConfigs(); static void AddMessageRouterConfig(const CefMessageRouterConfig& cfg); diff --git a/native/context.cpp b/native/context.cpp index b47a3956..802c930a 100644 --- a/native/context.cpp +++ b/native/context.cpp @@ -13,10 +13,6 @@ #include "util_mac.h" #endif -#if defined(OS_POSIX) -#include "signal_restore_posix.h" -#endif - namespace { Context* g_context = nullptr; @@ -24,6 +20,11 @@ Context* g_context = nullptr; CefSettings GetJNISettings(JNIEnv* env, jobject obj) { CefString tmp; CefSettings settings; + +#if defined(OS_POSIX) && !defined(OS_ANDROID) + settings.disable_signal_handlers = true; +#endif + if (!obj) return settings; @@ -44,6 +45,11 @@ CefSettings GetJNISettings(JNIEnv* env, jobject obj) { CefString(&settings.cache_path) = tmp; tmp.clear(); } + if (GetJNIFieldString(env, cls, obj, "root_cache_path", &tmp) && + !tmp.empty()) { + CefString(&settings.root_cache_path) = tmp; + tmp.clear(); + } GetJNIFieldBoolean(env, cls, obj, "persist_session_cookies", &settings.persist_session_cookies); if (GetJNIFieldString(env, cls, obj, "user_agent", &tmp) && !tmp.empty()) { @@ -111,8 +117,6 @@ CefSettings GetJNISettings(JNIEnv* env, jobject obj) { CefString(&settings.main_bundle_path) = tmp; tmp.clear(); } - GetJNIFieldBoolean(env, cls, obj, "pack_loading_disabled", - &settings.pack_loading_disabled); GetJNIFieldInt(env, cls, obj, "remote_debugging_port", &settings.remote_debugging_port); GetJNIFieldInt(env, cls, obj, "uncaught_exception_stack_size", @@ -231,12 +235,6 @@ bool Context::Initialize(JNIEnv* env, new ClientApp(CefString(&settings.cache_path), env, appHandler)); bool res = false; -#if defined(OS_POSIX) - // CefInitialize will reset signal handlers. Backup/restore the original - // signal handlers to avoid crashes in the JVM (see issue #41). - BackupSignalHandlers(); -#endif - #if defined(OS_MACOSX) res = util_mac::CefInitializeOnMainThread(main_args, settings, client_app.get()); @@ -244,10 +242,6 @@ bool Context::Initialize(JNIEnv* env, res = CefInitialize(main_args, settings, client_app.get(), nullptr); #endif -#if defined(OS_POSIX) - RestoreSignalHandlers(); -#endif - return res; } diff --git a/native/devtools_message_observer.cpp b/native/devtools_message_observer.cpp new file mode 100644 index 00000000..84a47fbf --- /dev/null +++ b/native/devtools_message_observer.cpp @@ -0,0 +1,44 @@ +// Copyright (c) 2024 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "devtools_message_observer.h" + +#include "jni_util.h" + +DevToolsMessageObserver::DevToolsMessageObserver(JNIEnv* env, jobject observer) + : handle_(env, observer) {} + +void DevToolsMessageObserver::OnDevToolsMethodResult( + CefRefPtr browser, + int message_id, + bool success, + const void* result, + size_t result_size) { + ScopedJNIEnv env; + if (!env) + return; + + ScopedJNIBrowser jbrowser(env, browser); + std::string strResult(static_cast(result), result_size); + JNI_CALL_VOID_METHOD( + env, handle_, "onDevToolsMethodResult", + "(Lorg/cef/browser/CefBrowser;IZLjava/lang/String;)V", jbrowser.get(), + message_id, success ? JNI_TRUE : JNI_FALSE, NewJNIString(env, strResult)); +} + +void DevToolsMessageObserver::OnDevToolsEvent(CefRefPtr browser, + const CefString& method, + const void* params, + size_t params_size) { + ScopedJNIEnv env; + if (!env) + return; + ScopedJNIBrowser jbrowser(env, browser); + + std::string strParams(static_cast(params), params_size); + JNI_CALL_VOID_METHOD( + env, handle_, "onDevToolsEvent", + "(Lorg/cef/browser/CefBrowser;Ljava/lang/String;Ljava/lang/String;)V", + jbrowser.get(), NewJNIString(env, method), NewJNIString(env, strParams)); +} diff --git a/native/devtools_message_observer.h b/native/devtools_message_observer.h new file mode 100644 index 00000000..19e34bb9 --- /dev/null +++ b/native/devtools_message_observer.h @@ -0,0 +1,37 @@ +// Copyright (c) 2024 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#ifndef JCEF_NATIVE_DEVTOOLS_MESSAGE_OBSERVER_H_ +#define JCEF_NATIVE_DEVTOOLS_MESSAGE_OBSERVER_H_ +#pragma once + +#include +#include "include/cef_devtools_message_observer.h" + +#include "jni_scoped_helpers.h" + +// DevToolsMessageObserver implementation. +class DevToolsMessageObserver : public CefDevToolsMessageObserver { + public: + DevToolsMessageObserver(JNIEnv* env, jobject observer); + + // CefDevToolsMessageObserver methods + virtual void OnDevToolsMethodResult(CefRefPtr browser, + int message_id, + bool success, + const void* result, + size_t result_size) override; + virtual void OnDevToolsEvent(CefRefPtr browser, + const CefString& method, + const void* params, + size_t params_size) override; + + protected: + ScopedJNIObjectGlobal handle_; + + // Include the default reference counting implementation. + IMPLEMENT_REFCOUNTING(DevToolsMessageObserver); +}; + +#endif // JCEF_NATIVE_DEVTOOLS_MESSAGE_OBSERVER_H_ diff --git a/native/dialog_handler.cpp b/native/dialog_handler.cpp index 30acb467..883f675f 100644 --- a/native/dialog_handler.cpp +++ b/native/dialog_handler.cpp @@ -27,12 +27,15 @@ class ScopedJNIFileDialogCallback DialogHandler::DialogHandler(JNIEnv* env, jobject handler) : handle_(env, handler) {} -bool DialogHandler::OnFileDialog(CefRefPtr browser, - FileDialogMode mode, - const CefString& title, - const CefString& default_file_path, - const std::vector& accept_filters, - CefRefPtr callback) { +bool DialogHandler::OnFileDialog( + CefRefPtr browser, + FileDialogMode mode, + const CefString& title, + const CefString& default_file_path, + const std::vector& accept_filters, + const std::vector& accept_extensions, + const std::vector& accept_descriptions, + CefRefPtr callback) { ScopedJNIEnv env; if (!env) return false; @@ -42,6 +45,10 @@ bool DialogHandler::OnFileDialog(CefRefPtr browser, ScopedJNIString jdefaultFilePath(env, default_file_path); ScopedJNIObjectLocal jacceptFilters(env, NewJNIStringVector(env, accept_filters)); + ScopedJNIObjectLocal jacceptExtensions( + env, NewJNIStringVector(env, accept_extensions)); + ScopedJNIObjectLocal jacceptDescriptions( + env, NewJNIStringVector(env, accept_descriptions)); ScopedJNIFileDialogCallback jcallback(env, callback); ScopedJNIObjectResult jmode(env); @@ -61,9 +68,11 @@ bool DialogHandler::OnFileDialog(CefRefPtr browser, env, handle_, "onFileDialog", "(Lorg/cef/browser/CefBrowser;Lorg/cef/handler/" "CefDialogHandler$FileDialogMode;Ljava/lang/String;Ljava/lang/" - "String;Ljava/util/Vector;Lorg/cef/callback/CefFileDialogCallback;)Z", + "String;Ljava/util/Vector;Ljava/util/Vector;Ljava/util/Vector;Lorg/cef/" + "callback/CefFileDialogCallback;)Z", Boolean, jreturn, jbrowser.get(), jmode.get(), jtitle.get(), - jdefaultFilePath.get(), jacceptFilters.get(), jcallback.get()); + jdefaultFilePath.get(), jacceptFilters.get(), jacceptExtensions.get(), + jacceptDescriptions.get(), jcallback.get()); if (jreturn == JNI_FALSE) { // If the Java method returns "false" the callback won't be used and diff --git a/native/dialog_handler.h b/native/dialog_handler.h index d4ec0cd3..0a5411ee 100644 --- a/native/dialog_handler.h +++ b/native/dialog_handler.h @@ -22,6 +22,8 @@ class DialogHandler : public CefDialogHandler { const CefString& title, const CefString& default_file_path, const std::vector& accept_filters, + const std::vector& accept_extensions, + const std::vector& accept_descriptions, CefRefPtr callback) override; protected: diff --git a/native/display_handler.cpp b/native/display_handler.cpp index 60874291..cb0537fa 100644 --- a/native/display_handler.cpp +++ b/native/display_handler.cpp @@ -41,6 +41,18 @@ void DisplayHandler::OnTitleChange(CefRefPtr browser, jbrowser.get(), jtitle.get()); } +void DisplayHandler::OnFullscreenModeChange(CefRefPtr browser, + bool fullscreen) { + ScopedJNIEnv env; + if (!env) + return; + + ScopedJNIBrowser jbrowser(env, browser); + JNI_CALL_VOID_METHOD(env, handle_, "onFullscreenModeChange", + "(Lorg/cef/browser/CefBrowser;Z)V", jbrowser.get(), + (jboolean)fullscreen); +} + bool DisplayHandler::OnTooltip(CefRefPtr browser, CefString& text) { ScopedJNIEnv env; if (!env) diff --git a/native/display_handler.h b/native/display_handler.h index 3b015b62..30615fdb 100644 --- a/native/display_handler.h +++ b/native/display_handler.h @@ -23,6 +23,8 @@ class DisplayHandler : public CefDisplayHandler { const CefString& url) override; void OnTitleChange(CefRefPtr browser, const CefString& title) override; + void OnFullscreenModeChange(CefRefPtr browser, + bool fullscreen) override; bool OnTooltip(CefRefPtr browser, CefString& text) override; void OnStatusMessage(CefRefPtr browser, const CefString& value) override; diff --git a/native/download_handler.cpp b/native/download_handler.cpp index f594d435..e0b37759 100644 --- a/native/download_handler.cpp +++ b/native/download_handler.cpp @@ -49,14 +49,14 @@ class ScopedJNIDownloadItemCallback DownloadHandler::DownloadHandler(JNIEnv* env, jobject handler) : handle_(env, handler) {} -void DownloadHandler::OnBeforeDownload( +bool DownloadHandler::OnBeforeDownload( CefRefPtr browser, CefRefPtr download_item, const CefString& suggested_name, CefRefPtr callback) { ScopedJNIEnv env; if (!env) - return; + return false; ScopedJNIBrowser jbrowser(env, browser); ScopedJNIDownloadItem jdownloadItem(env, download_item); @@ -64,12 +64,16 @@ void DownloadHandler::OnBeforeDownload( ScopedJNIString jsuggestedName(env, suggested_name); ScopedJNIBeforeDownloadCallback jcallback(env, callback); - JNI_CALL_VOID_METHOD( - env, handle_, "onBeforeDownload", + jboolean jresult = 0; + + JNI_CALL_BOOLEAN_METHOD( + jresult, env, handle_, "onBeforeDownload", "(Lorg/cef/browser/CefBrowser;Lorg/cef/callback/CefDownloadItem;" - "Ljava/lang/String;Lorg/cef/callback/CefBeforeDownloadCallback;)V", + "Ljava/lang/String;Lorg/cef/callback/CefBeforeDownloadCallback;)Z", jbrowser.get(), jdownloadItem.get(), jsuggestedName.get(), jcallback.get()); + + return jresult; } void DownloadHandler::OnDownloadUpdated( diff --git a/native/download_handler.h b/native/download_handler.h index d41ca492..adbaacbb 100644 --- a/native/download_handler.h +++ b/native/download_handler.h @@ -17,7 +17,7 @@ class DownloadHandler : public CefDownloadHandler { DownloadHandler(JNIEnv* env, jobject handler); // CefDownloadHandler methods - virtual void OnBeforeDownload( + virtual bool OnBeforeDownload( CefRefPtr browser, CefRefPtr download_item, const CefString& suggested_name, diff --git a/native/int_callback.cpp b/native/int_callback.cpp new file mode 100644 index 00000000..a45471a4 --- /dev/null +++ b/native/int_callback.cpp @@ -0,0 +1,20 @@ +// Copyright (c) 2024 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "int_callback.h" + +#include "jni_scoped_helpers.h" +#include "jni_util.h" +#include "util.h" + +IntCallback::IntCallback(JNIEnv* env, jobject jcallback) + : handle_(env, jcallback) {} + +void IntCallback::onComplete(int value) { + ScopedJNIEnv env; + if (!env) + return; + + JNI_CALL_VOID_METHOD(env, handle_, "onComplete", "(I)V", (jint)value); +} diff --git a/native/int_callback.h b/native/int_callback.h new file mode 100644 index 00000000..6437479c --- /dev/null +++ b/native/int_callback.h @@ -0,0 +1,28 @@ +// Copyright (c) 2024 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#ifndef JCEF_NATIVE_INT_CALLBACK_H_ +#define JCEF_NATIVE_INT_CALLBACK_H_ +#pragma once + +#include + +#include "jni_scoped_helpers.h" + +// Callback for returning int primatives. The methods of +// this class will be called on the browser process UI thread. +class IntCallback : public virtual CefBaseRefCounted { + public: + IntCallback(JNIEnv* env, jobject jcallback); + + virtual void onComplete(int value); + + protected: + ScopedJNIObjectGlobal handle_; + + // Include the default reference counting implementation. + IMPLEMENT_REFCOUNTING(IntCallback); +}; + +#endif // JCEF_NATIVE_INT_CALLBACK_H_ diff --git a/native/jni_util.cpp b/native/jni_util.cpp index 957be41d..4bee5978 100644 --- a/native/jni_util.cpp +++ b/native/jni_util.cpp @@ -632,18 +632,10 @@ jobject NewJNIErrorCode(JNIEnv* env, cef_errorcode_t errorCode) { ERR_CONTENT_DECODING_INIT_FAILED, jerrorCode); JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", ERR_HTTP2_RST_STREAM_NO_ERROR_RECEIVED, jerrorCode); - JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", - ERR_HTTP2_PUSHED_STREAM_NOT_AVAILABLE, jerrorCode); - JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", - ERR_HTTP2_CLAIMED_PUSHED_STREAM_RESET_BY_SERVER, jerrorCode); JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", ERR_TOO_MANY_RETRIES, jerrorCode); JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", ERR_HTTP2_STREAM_CLOSED, jerrorCode); - JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", - ERR_HTTP2_CLIENT_REFUSED_STREAM, jerrorCode); - JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", - ERR_HTTP2_PUSHED_RESPONSE_DOES_NOT_MATCH, jerrorCode); JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", ERR_HTTP_RESPONSE_CODE_FAILURE, jerrorCode); JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", @@ -693,20 +685,6 @@ jobject NewJNIErrorCode(JNIEnv* env, cef_errorcode_t errorCode) { JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", ERR_TRUST_TOKEN_OPERATION_SUCCESS_WITHOUT_SENDING_REQUEST, jerrorCode); - JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", ERR_FTP_FAILED, - jerrorCode); - JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", - ERR_FTP_SERVICE_UNAVAILABLE, jerrorCode); - JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", - ERR_FTP_TRANSFER_ABORTED, jerrorCode); - JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", - ERR_FTP_FILE_BUSY, jerrorCode); - JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", - ERR_FTP_SYNTAX_ERROR, jerrorCode); - JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", - ERR_FTP_COMMAND_NOT_SUPPORTED, jerrorCode); - JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", - ERR_FTP_BAD_COMMAND_SEQUENCE, jerrorCode); JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", ERR_PKCS12_IMPORT_BAD_PASSWORD, jerrorCode); JNI_CASE(env, "org/cef/handler/CefLoadHandler$ErrorCode", diff --git a/native/life_span_handler.cpp b/native/life_span_handler.cpp index ea41a700..aaa8c256 100644 --- a/native/life_span_handler.cpp +++ b/native/life_span_handler.cpp @@ -14,6 +14,7 @@ LifeSpanHandler::LifeSpanHandler(JNIEnv* env, jobject handler) // TODO(JCEF): Expose all parameters. bool LifeSpanHandler::OnBeforePopup(CefRefPtr browser, CefRefPtr frame, + int popup_id, const CefString& target_url, const CefString& target_frame_name, WindowOpenDisposition target_disposition, diff --git a/native/life_span_handler.h b/native/life_span_handler.h index bbe00022..97ef6e56 100644 --- a/native/life_span_handler.h +++ b/native/life_span_handler.h @@ -22,6 +22,7 @@ class LifeSpanHandler : public CefLifeSpanHandler { // CefLifeSpanHandler methods: virtual bool OnBeforePopup(CefRefPtr browser, CefRefPtr frame, + int popup_id, const CefString& target_url, const CefString& target_frame_name, WindowOpenDisposition target_disposition, diff --git a/native/request_handler.cpp b/native/request_handler.cpp index 9d6b89e3..24434451 100644 --- a/native/request_handler.cpp +++ b/native/request_handler.cpp @@ -120,8 +120,8 @@ bool RequestHandler::GetAuthCredentials(CefRefPtr browser, ScopedJNIBrowser jbrowser(env, browser); ScopedJNIString joriginUrl(env, origin_url); ScopedJNIString jhost(env, host); - ScopedJNIString jrealm(env, host); - ScopedJNIString jscheme(env, host); + ScopedJNIString jrealm(env, realm); + ScopedJNIString jscheme(env, scheme); ScopedJNIAuthCallback jcallback(env, callback); jboolean jresult = JNI_FALSE; @@ -175,7 +175,9 @@ bool RequestHandler::OnCertificateError(CefRefPtr browser, } void RequestHandler::OnRenderProcessTerminated(CefRefPtr browser, - TerminationStatus status) { + TerminationStatus status, + int error_code, + const CefString& error_string) { // Forward request to ClientHandler to make the message_router_ happy. CefRefPtr client = (ClientHandler*)browser->GetHost()->GetClient().get(); @@ -197,11 +199,20 @@ void RequestHandler::OnRenderProcessTerminated(CefRefPtr browser, TS_PROCESS_CRASHED, jstatus); JNI_CASE(env, "org/cef/handler/CefRequestHandler$TerminationStatus", TS_PROCESS_OOM, jstatus); + JNI_CASE(env, "org/cef/handler/CefRequestHandler$TerminationStatus", + TS_LAUNCH_FAILED, jstatus); + JNI_CASE(env, "org/cef/handler/CefRequestHandler$TerminationStatus", + TS_INTEGRITY_FAILURE, jstatus); + JNI_CASE(env, "org/cef/handler/CefRequestHandler$TerminationStatus", + TS_NUM_VALUES, jstatus); } - JNI_CALL_VOID_METHOD( - env, handle_, "onRenderProcessTerminated", - "(Lorg/cef/browser/CefBrowser;" - "Lorg/cef/handler/CefRequestHandler$TerminationStatus;)V", - jbrowser.get(), jstatus.get()); + ScopedJNIString jerrorString(env, error_string); + + JNI_CALL_VOID_METHOD(env, handle_, "onRenderProcessTerminated", + "(Lorg/cef/browser/CefBrowser;" + "Lorg/cef/handler/CefRequestHandler$TerminationStatus;" + "ILjava/lang/String;)V", + jbrowser.get(), jstatus.get(), error_code, + jerrorString.get()); } diff --git a/native/request_handler.h b/native/request_handler.h index 60b47b0b..9ee8356e 100644 --- a/native/request_handler.h +++ b/native/request_handler.h @@ -50,7 +50,9 @@ class RequestHandler : public CefRequestHandler { CefRefPtr ssl_info, CefRefPtr callback) override; void OnRenderProcessTerminated(CefRefPtr browser, - TerminationStatus status) override; + TerminationStatus status, + int error_code, + const CefString& error_string) override; protected: ScopedJNIObjectGlobal handle_; diff --git a/native/signal_restore_posix.cpp b/native/signal_restore_posix.cpp deleted file mode 100644 index 03d22496..00000000 --- a/native/signal_restore_posix.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights -// reserved. Use of this source code is governed by a BSD-style license that -// can be found in the LICENSE file. - -#include "signal_restore_posix.h" - -#include -#include - -// arraysize borrowed from base/macros.h -template -char (&ArraySizeHelper(T (&array)[N]))[N]; -#define arraysize(array) (sizeof(ArraySizeHelper(array))) - -namespace { - -const int signals_to_restore[] = {SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, - SIGFPE, SIGSEGV, SIGALRM, SIGTERM, SIGCHLD, - SIGBUS, SIGTRAP, SIGPIPE}; - -struct sigaction signal_handlers[arraysize(signals_to_restore)]; - -} // namespace - -void BackupSignalHandlers() { - struct sigaction sigact; - for (unsigned i = 0; i < arraysize(signals_to_restore); ++i) { - memset(&sigact, 0, sizeof(sigact)); - sigaction(signals_to_restore[i], nullptr, &sigact); - signal_handlers[i] = sigact; - } -} - -void RestoreSignalHandlers() { - for (unsigned i = 0; i < arraysize(signals_to_restore); ++i) { - sigaction(signals_to_restore[i], &signal_handlers[i], nullptr); - } -} diff --git a/native/signal_restore_posix.h b/native/signal_restore_posix.h deleted file mode 100644 index 830b361a..00000000 --- a/native/signal_restore_posix.h +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights -// reserved. Use of this source code is governed by a BSD-style license that -// can be found in the LICENSE file. - -#ifndef SIGNAL_RESTORE_POSIX_H -#define SIGNAL_RESTORE_POSIX_H - -void BackupSignalHandlers(); -void RestoreSignalHandlers(); - -#endif // SIGNAL_RESTORE_POSIX_H diff --git a/tools/make_all_jni_headers.bat b/tools/make_all_jni_headers.bat index 3f101d3a..ecb1dee0 100644 --- a/tools/make_all_jni_headers.bat +++ b/tools/make_all_jni_headers.bat @@ -37,6 +37,7 @@ call make_jni_header.bat %1 org.cef.callback.CefQueryCallback_N call make_jni_header.bat %1 org.cef.callback.CefSchemeRegistrar_N call make_jni_header.bat %1 org.cef.handler.CefClientHandler call make_jni_header.bat %1 org.cef.misc.CefPrintSettings_N +call make_jni_header.bat %1 org.cef.browser.CefRegistration_N call make_jni_header.bat %1 org.cef.network.CefCookieManager_N call make_jni_header.bat %1 org.cef.network.CefPostData_N call make_jni_header.bat %1 org.cef.network.CefPostDataElement_N