Skip to content

Commit

Permalink
Add CefBrowserSettings.windowless_frame_rate (see chromiumembedded#459)
Browse files Browse the repository at this point in the history
Also adds methods to dynamically set/get the frame rate and fixes
some pre-existing compile issues.
  • Loading branch information
1fxe authored and magreenblatt committed Jan 11, 2024
1 parent ade64c3 commit 423f5b8
Show file tree
Hide file tree
Showing 15 changed files with 279 additions and 84 deletions.
31 changes: 31 additions & 0 deletions java/org/cef/CefBrowserSettings.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
27 changes: 21 additions & 6 deletions java/org/cef/CefClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -60,6 +56,7 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.Vector;
import java.util.function.Consumer;

import javax.swing.SwingUtilities;

Expand Down Expand Up @@ -141,7 +138,16 @@ public CefBrowser createBrowser(String url, boolean isOffscreenRendered, boolean
CefRequestContext context) {
if (isDisposed_)
throw new IllegalStateException("Can't create browser. CefClient is disposed");
return CefBrowserFactory.create(this, url, isOffscreenRendered, isTransparent, context);
return CefBrowserFactory.create(
this, url, isOffscreenRendered, isTransparent, context, null);
}

public CefBrowser createBrowser(String url, boolean isOffscreenRendered, boolean isTransparent,
CefRequestContext context, CefBrowserSettings settings) {
if (isDisposed_)
throw new IllegalStateException("Can't create browser. CefClient is disposed");
return CefBrowserFactory.create(
this, url, isOffscreenRendered, isTransparent, context, settings);
}

@Override
Expand Down Expand Up @@ -753,6 +759,15 @@ public void onPaint(CefBrowser browser, boolean popup, Rectangle[] dirtyRects,
realHandler.onPaint(browser, popup, dirtyRects, buffer, width, height);
}

@Override
public void addOnPaintListener(Consumer<CefPaintEvent> listener) {}

@Override
public void setOnPaintListener(Consumer<CefPaintEvent> listener) {}

@Override
public void removeOnPaintListener(Consumer<CefPaintEvent> listener) {}

@Override
public boolean startDragging(CefBrowser browser, CefDragData dragData, int mask, int x, int y) {
if (browser == null) return false;
Expand Down
22 changes: 22 additions & 0 deletions java/org/cef/browser/CefBrowser.java
Original file line number Diff line number Diff line change
Expand Up @@ -390,4 +390,26 @@ public void runFileDialog(FileDialogMode mode, String title, String defaultFileP
* @throws UnsupportedOperationException if not supported
*/
public CompletableFuture<BufferedImage> 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<Integer> getWindowlessFrameRate();
}
8 changes: 5 additions & 3 deletions java/org/cef/browser/CefBrowserFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@

package org.cef.browser;

import org.cef.CefBrowserSettings;
import org.cef.CefClient;

/**
* Creates a new instance of CefBrowser according the passed values
*/
public class CefBrowserFactory {
public static CefBrowser create(CefClient client, String url, boolean isOffscreenRendered,
boolean isTransparent, CefRequestContext context) {
if (isOffscreenRendered) return new CefBrowserOsr(client, url, isTransparent, context);
return new CefBrowserWr(client, url, context);
boolean isTransparent, CefRequestContext context, CefBrowserSettings settings) {
if (isOffscreenRendered)
return new CefBrowserOsr(client, url, isTransparent, context, settings);
return new CefBrowserWr(client, url, context, settings);
}
}
13 changes: 8 additions & 5 deletions java/org/cef/browser/CefBrowserOsr.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.jogamp.opengl.awt.GLCanvas;
import com.jogamp.opengl.util.GLBuffers;

import org.cef.CefBrowserSettings;
import org.cef.CefClient;
import org.cef.OS;
import org.cef.callback.CefDragData;
Expand Down Expand Up @@ -89,13 +90,15 @@ class CefBrowserOsr extends CefBrowser_N implements CefRenderHandler {
private CopyOnWriteArrayList<Consumer<CefPaintEvent>> onPaintListeners =
new CopyOnWriteArrayList<>();

CefBrowserOsr(CefClient client, String url, boolean transparent, CefRequestContext context) {
this(client, url, transparent, context, null, null);
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) {
super(client, url, context, parent, inspectAt);
CefRequestContext context, CefBrowserOsr parent, Point inspectAt,
CefBrowserSettings settings) {
super(client, url, context, parent, inspectAt, settings);
isTransparent_ = transparent;
renderer_ = new CefRenderer(transparent);
createGLCanvas();
Expand All @@ -122,7 +125,7 @@ public CefRenderHandler getRenderHandler() {
protected CefBrowser_N createDevToolsBrowser(CefClient client, String url,
CefRequestContext context, CefBrowser_N parent, Point inspectAt) {
return new CefBrowserOsr(
client, url, isTransparent_, context, (CefBrowserOsr) this, inspectAt);
client, url, isTransparent_, context, (CefBrowserOsr) this, inspectAt, null);
}

private synchronized long getWindowHandle() {
Expand Down
24 changes: 19 additions & 5 deletions java/org/cef/browser/CefBrowserWr.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package org.cef.browser;

import org.cef.CefBrowserSettings;
import org.cef.CefClient;
import org.cef.OS;
import org.cef.handler.CefWindowHandler;
Expand Down Expand Up @@ -166,14 +167,15 @@ public int getClickCount(int event, int button) {
}
};

CefBrowserWr(CefClient client, String url, CefRequestContext context) {
this(client, url, context, null, null);
CefBrowserWr(
CefClient client, String url, CefRequestContext context, CefBrowserSettings settings) {
this(client, url, context, null, null, settings);
}

@SuppressWarnings("serial")
private CefBrowserWr(CefClient client, String url, CefRequestContext context,
CefBrowserWr parent, Point inspectAt) {
super(client, url, context, parent, inspectAt);
CefBrowserWr parent, Point inspectAt, CefBrowserSettings settings) {
super(client, url, context, parent, inspectAt, settings);
delayedUpdate_.setRepeats(false);

// Disabling lightweight of popup menu is required because
Expand Down Expand Up @@ -318,7 +320,7 @@ public CefWindowHandler getWindowHandler() {
@Override
protected CefBrowser_N createDevToolsBrowser(CefClient client, String url,
CefRequestContext context, CefBrowser_N parent, Point inspectAt) {
return new CefBrowserWr(client, url, context, (CefBrowserWr) this, inspectAt);
return new CefBrowserWr(client, url, context, (CefBrowserWr) this, inspectAt, null);
}

private synchronized long getWindowHandle() {
Expand Down Expand Up @@ -421,4 +423,16 @@ private boolean createBrowserIfRequired(boolean hasParent) {
public CompletableFuture<BufferedImage> createScreenshot(boolean nativeResolution) {
throw new UnsupportedOperationException("Unsupported for windowed rendering");
}

@Override
public void setWindowlessFrameRate(int frameRate) {
throw new UnsupportedOperationException(
"You can only set windowless framerate on OSR browser");
}

@Override
public CompletableFuture<Integer> getWindowlessFrameRate() {
throw new UnsupportedOperationException(
"You can only get windowless framerate on OSR browser");
}
}
43 changes: 35 additions & 8 deletions java/org/cef/browser/CefBrowser_N.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package org.cef.browser;

import org.cef.CefBrowserSettings;
import org.cef.CefClient;
import org.cef.browser.CefDevToolsClient.DevToolsException;
import org.cef.callback.CefDragData;
Expand Down Expand Up @@ -49,14 +50,19 @@ abstract class CefBrowser_N extends CefNativeAdapter implements CefBrowser {
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() {
Expand Down Expand Up @@ -162,7 +168,7 @@ public synchronized CefDevToolsClient getDevToolsClient() {

CompletableFuture<Integer> executeDevToolsMethod(String method, String parametersAsJson) {
CompletableFuture<Integer> future = new CompletableFuture<>();
N_ExecuteDevToolsMethod(method, parametersAsJson, new DevToolsMethodCallback() {
N_ExecuteDevToolsMethod(method, parametersAsJson, new IntCallback() {
@Override
public void onComplete(int generatedMessageId) {
if (generatedMessageId <= 0) {
Expand Down Expand Up @@ -190,8 +196,8 @@ protected void createBrowser(CefClientHandler clientHandler, long windowHandle,
boolean osr, boolean transparent, Component canvas, CefRequestContext context) {
if (getNativeRef("CefBrowser") == 0 && !isPending_) {
try {
N_CreateBrowser(
clientHandler, windowHandle, url, osr, transparent, canvas, context);
N_CreateBrowser(clientHandler, windowHandle, url, osr, transparent, canvas, context,
settings_);
} catch (UnsatisfiedLinkError err) {
err.printStackTrace();
}
Expand Down Expand Up @@ -789,17 +795,36 @@ protected final void notifyMoveOrResizeStarted() {
}
}

private interface DevToolsMethodCallback {
void onComplete(int generatedMessageId);
public void setWindowlessFrameRate(int frameRate) {
try {
N_SetWindowlessFrameRate(frameRate);
} catch (UnsatisfiedLinkError ule) {
ule.printStackTrace();
}
}

public CompletableFuture<Integer> getWindowlessFrameRate() {
final CompletableFuture<Integer> 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, Component canvas,
CefRequestContext context);
CefRequestContext context, CefBrowserSettings settings);
private final native boolean N_CreateDevTools(CefBrowser parent, CefClientHandler clientHandler,
long windowHandle, boolean osr, boolean transparent, Component canvas, Point inspectAt);
private final native void N_ExecuteDevToolsMethod(
String method, String parametersAsJson, DevToolsMethodCallback callback);
String method, String parametersAsJson, IntCallback callback);
private final native CefRegistration N_AddDevToolsMessageObserver(
CefDevToolsMessageObserver observer);
private final native long N_GetWindowHandle(long surfaceHandle);
Expand Down Expand Up @@ -860,4 +885,6 @@ private final native void N_DragTargetDragEnter(
private final native void N_UpdateUI(Rectangle contentRect, Rectangle browserRect);
private final native void N_SetParent(long windowHandle, Component canvas);
private final native void N_NotifyMoveOrResizeStarted();
private final native void N_SetWindowlessFrameRate(int frameRate);
private final native void N_GetWindowlessFrameRate(IntCallback frameRateCallback);
}
28 changes: 23 additions & 5 deletions java/tests/detailed/MainFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

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;
Expand Down Expand Up @@ -58,6 +59,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")) {
Expand All @@ -66,17 +68,30 @@ 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;
}
}

System.out.println("Offscreen rendering " + (osrEnabledArg ? "enabled" : "disabled"));

// 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_;
Expand All @@ -88,7 +103,7 @@ public static void main(String[] args) {
private boolean transparent_painting_enabled_;

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;

Expand Down Expand Up @@ -200,9 +215,12 @@ 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, transparentPaintingEnabled, null);
CefBrowser browser = client_.createBrowser("http://www.google.com", osrEnabled,
transparentPaintingEnabled, null, browserSettings);
setBrowser(browser);

// Set up the UI for this example implementation.
Expand Down
Loading

0 comments on commit 423f5b8

Please sign in to comment.