Skip to content

Commit 423f5b8

Browse files
Filipmagreenblatt
authored andcommitted
Add CefBrowserSettings.windowless_frame_rate (see chromiumembedded#459)
Also adds methods to dynamically set/get the frame rate and fixes some pre-existing compile issues.
1 parent ade64c3 commit 423f5b8

15 files changed

+279
-84
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) 2024 The Chromium Embedded Framework Authors. All rights
2+
// reserved. Use of this source code is governed by a BSD-style license that
3+
// can be found in the LICENSE file.
4+
5+
package org.cef;
6+
7+
/**
8+
* Browser initialization settings. Specify NULL or 0 to get the recommended
9+
* default values. The consequences of using custom values may not be well
10+
* tested. Many of these and other settings can also configured using command-
11+
* line switches.
12+
*/
13+
public class CefBrowserSettings {
14+
/**
15+
* The maximum rate in frames per second (fps) that CefRenderHandler::OnPaint
16+
* will be called for a windowless browser. The actual fps may be lower if
17+
* the browser cannot generate frames at the requested rate. The minimum
18+
* value is 1 and the maximum value is 60 (default 30). This value can also
19+
* be changed dynamically via {@code CefBrowser#setWindowlessFrameRate}
20+
*/
21+
public int windowless_frame_rate = 0;
22+
23+
public CefBrowserSettings() {}
24+
25+
@Override
26+
public CefBrowserSettings clone() {
27+
CefBrowserSettings tmp = new CefBrowserSettings();
28+
tmp.windowless_frame_rate = windowless_frame_rate;
29+
return tmp;
30+
}
31+
}

java/org/cef/CefClient.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@
44

55
package org.cef;
66

7-
import org.cef.browser.CefBrowser;
8-
import org.cef.browser.CefBrowserFactory;
9-
import org.cef.browser.CefFrame;
10-
import org.cef.browser.CefMessageRouter;
11-
import org.cef.browser.CefRequestContext;
7+
import org.cef.browser.*;
128
import org.cef.callback.CefAuthCallback;
139
import org.cef.callback.CefBeforeDownloadCallback;
1410
import org.cef.callback.CefCallback;
@@ -60,6 +56,7 @@
6056
import java.util.Collection;
6157
import java.util.HashMap;
6258
import java.util.Vector;
59+
import java.util.function.Consumer;
6360

6461
import javax.swing.SwingUtilities;
6562

@@ -141,7 +138,16 @@ public CefBrowser createBrowser(String url, boolean isOffscreenRendered, boolean
141138
CefRequestContext context) {
142139
if (isDisposed_)
143140
throw new IllegalStateException("Can't create browser. CefClient is disposed");
144-
return CefBrowserFactory.create(this, url, isOffscreenRendered, isTransparent, context);
141+
return CefBrowserFactory.create(
142+
this, url, isOffscreenRendered, isTransparent, context, null);
143+
}
144+
145+
public CefBrowser createBrowser(String url, boolean isOffscreenRendered, boolean isTransparent,
146+
CefRequestContext context, CefBrowserSettings settings) {
147+
if (isDisposed_)
148+
throw new IllegalStateException("Can't create browser. CefClient is disposed");
149+
return CefBrowserFactory.create(
150+
this, url, isOffscreenRendered, isTransparent, context, settings);
145151
}
146152

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

762+
@Override
763+
public void addOnPaintListener(Consumer<CefPaintEvent> listener) {}
764+
765+
@Override
766+
public void setOnPaintListener(Consumer<CefPaintEvent> listener) {}
767+
768+
@Override
769+
public void removeOnPaintListener(Consumer<CefPaintEvent> listener) {}
770+
756771
@Override
757772
public boolean startDragging(CefBrowser browser, CefDragData dragData, int mask, int x, int y) {
758773
if (browser == null) return false;

java/org/cef/browser/CefBrowser.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,4 +390,26 @@ public void runFileDialog(FileDialogMode mode, String title, String defaultFileP
390390
* @throws UnsupportedOperationException if not supported
391391
*/
392392
public CompletableFuture<BufferedImage> createScreenshot(boolean nativeResolution);
393+
394+
/**
395+
* Set the maximum rate in frames per second (fps) that {@code CefRenderHandler::onPaint}
396+
* will be called for a windowless browser. The actual fps may be
397+
* lower if the browser cannot generate frames at the requested rate. The
398+
* minimum value is 1, and the maximum value is 60 (default 30).
399+
*
400+
* @param frameRate the maximum frame rate
401+
* @throws UnsupportedOperationException if not supported
402+
*/
403+
public void setWindowlessFrameRate(int frameRate);
404+
405+
/**
406+
* Returns the maximum rate in frames per second (fps) that {@code CefRenderHandler::onPaint}
407+
* will be called for a windowless browser. The actual fps may be lower if the browser cannot
408+
* generate frames at the requested rate. The minimum value is 1, and the maximum value is 60
409+
* (default 30).
410+
*
411+
* @return the framerate, 0 if an error occurs
412+
* @throws UnsupportedOperationException if not supported
413+
*/
414+
public CompletableFuture<Integer> getWindowlessFrameRate();
393415
}

java/org/cef/browser/CefBrowserFactory.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@
44

55
package org.cef.browser;
66

7+
import org.cef.CefBrowserSettings;
78
import org.cef.CefClient;
89

910
/**
1011
* Creates a new instance of CefBrowser according the passed values
1112
*/
1213
public class CefBrowserFactory {
1314
public static CefBrowser create(CefClient client, String url, boolean isOffscreenRendered,
14-
boolean isTransparent, CefRequestContext context) {
15-
if (isOffscreenRendered) return new CefBrowserOsr(client, url, isTransparent, context);
16-
return new CefBrowserWr(client, url, context);
15+
boolean isTransparent, CefRequestContext context, CefBrowserSettings settings) {
16+
if (isOffscreenRendered)
17+
return new CefBrowserOsr(client, url, isTransparent, context, settings);
18+
return new CefBrowserWr(client, url, context, settings);
1719
}
1820
}

java/org/cef/browser/CefBrowserOsr.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.jogamp.opengl.awt.GLCanvas;
1616
import com.jogamp.opengl.util.GLBuffers;
1717

18+
import org.cef.CefBrowserSettings;
1819
import org.cef.CefClient;
1920
import org.cef.OS;
2021
import org.cef.callback.CefDragData;
@@ -89,13 +90,15 @@ class CefBrowserOsr extends CefBrowser_N implements CefRenderHandler {
8990
private CopyOnWriteArrayList<Consumer<CefPaintEvent>> onPaintListeners =
9091
new CopyOnWriteArrayList<>();
9192

92-
CefBrowserOsr(CefClient client, String url, boolean transparent, CefRequestContext context) {
93-
this(client, url, transparent, context, null, null);
93+
CefBrowserOsr(CefClient client, String url, boolean transparent, CefRequestContext context,
94+
CefBrowserSettings settings) {
95+
this(client, url, transparent, context, null, null, settings);
9496
}
9597

9698
private CefBrowserOsr(CefClient client, String url, boolean transparent,
97-
CefRequestContext context, CefBrowserOsr parent, Point inspectAt) {
98-
super(client, url, context, parent, inspectAt);
99+
CefRequestContext context, CefBrowserOsr parent, Point inspectAt,
100+
CefBrowserSettings settings) {
101+
super(client, url, context, parent, inspectAt, settings);
99102
isTransparent_ = transparent;
100103
renderer_ = new CefRenderer(transparent);
101104
createGLCanvas();
@@ -122,7 +125,7 @@ public CefRenderHandler getRenderHandler() {
122125
protected CefBrowser_N createDevToolsBrowser(CefClient client, String url,
123126
CefRequestContext context, CefBrowser_N parent, Point inspectAt) {
124127
return new CefBrowserOsr(
125-
client, url, isTransparent_, context, (CefBrowserOsr) this, inspectAt);
128+
client, url, isTransparent_, context, (CefBrowserOsr) this, inspectAt, null);
126129
}
127130

128131
private synchronized long getWindowHandle() {

java/org/cef/browser/CefBrowserWr.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
package org.cef.browser;
66

7+
import org.cef.CefBrowserSettings;
78
import org.cef.CefClient;
89
import org.cef.OS;
910
import org.cef.handler.CefWindowHandler;
@@ -166,14 +167,15 @@ public int getClickCount(int event, int button) {
166167
}
167168
};
168169

169-
CefBrowserWr(CefClient client, String url, CefRequestContext context) {
170-
this(client, url, context, null, null);
170+
CefBrowserWr(
171+
CefClient client, String url, CefRequestContext context, CefBrowserSettings settings) {
172+
this(client, url, context, null, null, settings);
171173
}
172174

173175
@SuppressWarnings("serial")
174176
private CefBrowserWr(CefClient client, String url, CefRequestContext context,
175-
CefBrowserWr parent, Point inspectAt) {
176-
super(client, url, context, parent, inspectAt);
177+
CefBrowserWr parent, Point inspectAt, CefBrowserSettings settings) {
178+
super(client, url, context, parent, inspectAt, settings);
177179
delayedUpdate_.setRepeats(false);
178180

179181
// Disabling lightweight of popup menu is required because
@@ -318,7 +320,7 @@ public CefWindowHandler getWindowHandler() {
318320
@Override
319321
protected CefBrowser_N createDevToolsBrowser(CefClient client, String url,
320322
CefRequestContext context, CefBrowser_N parent, Point inspectAt) {
321-
return new CefBrowserWr(client, url, context, (CefBrowserWr) this, inspectAt);
323+
return new CefBrowserWr(client, url, context, (CefBrowserWr) this, inspectAt, null);
322324
}
323325

324326
private synchronized long getWindowHandle() {
@@ -421,4 +423,16 @@ private boolean createBrowserIfRequired(boolean hasParent) {
421423
public CompletableFuture<BufferedImage> createScreenshot(boolean nativeResolution) {
422424
throw new UnsupportedOperationException("Unsupported for windowed rendering");
423425
}
426+
427+
@Override
428+
public void setWindowlessFrameRate(int frameRate) {
429+
throw new UnsupportedOperationException(
430+
"You can only set windowless framerate on OSR browser");
431+
}
432+
433+
@Override
434+
public CompletableFuture<Integer> getWindowlessFrameRate() {
435+
throw new UnsupportedOperationException(
436+
"You can only get windowless framerate on OSR browser");
437+
}
424438
}

java/org/cef/browser/CefBrowser_N.java

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
package org.cef.browser;
66

7+
import org.cef.CefBrowserSettings;
78
import org.cef.CefClient;
89
import org.cef.browser.CefDevToolsClient.DevToolsException;
910
import org.cef.callback.CefDragData;
@@ -49,14 +50,19 @@ abstract class CefBrowser_N extends CefNativeAdapter implements CefBrowser {
4950
private boolean closeAllowed_ = false;
5051
private volatile boolean isClosed_ = false;
5152
private volatile boolean isClosing_ = false;
53+
private final CefBrowserSettings settings_;
5254

5355
protected CefBrowser_N(CefClient client, String url, CefRequestContext context,
54-
CefBrowser_N parent, Point inspectAt) {
56+
CefBrowser_N parent, Point inspectAt, CefBrowserSettings settings) {
5557
client_ = client;
5658
url_ = url;
5759
request_context_ = context;
5860
parent_ = parent;
5961
inspectAt_ = inspectAt;
62+
if (settings != null)
63+
settings_ = settings.clone();
64+
else
65+
settings_ = new CefBrowserSettings();
6066
}
6167

6268
protected String getUrl() {
@@ -162,7 +168,7 @@ public synchronized CefDevToolsClient getDevToolsClient() {
162168

163169
CompletableFuture<Integer> executeDevToolsMethod(String method, String parametersAsJson) {
164170
CompletableFuture<Integer> future = new CompletableFuture<>();
165-
N_ExecuteDevToolsMethod(method, parametersAsJson, new DevToolsMethodCallback() {
171+
N_ExecuteDevToolsMethod(method, parametersAsJson, new IntCallback() {
166172
@Override
167173
public void onComplete(int generatedMessageId) {
168174
if (generatedMessageId <= 0) {
@@ -190,8 +196,8 @@ protected void createBrowser(CefClientHandler clientHandler, long windowHandle,
190196
boolean osr, boolean transparent, Component canvas, CefRequestContext context) {
191197
if (getNativeRef("CefBrowser") == 0 && !isPending_) {
192198
try {
193-
N_CreateBrowser(
194-
clientHandler, windowHandle, url, osr, transparent, canvas, context);
199+
N_CreateBrowser(clientHandler, windowHandle, url, osr, transparent, canvas, context,
200+
settings_);
195201
} catch (UnsatisfiedLinkError err) {
196202
err.printStackTrace();
197203
}
@@ -789,17 +795,36 @@ protected final void notifyMoveOrResizeStarted() {
789795
}
790796
}
791797

792-
private interface DevToolsMethodCallback {
793-
void onComplete(int generatedMessageId);
798+
public void setWindowlessFrameRate(int frameRate) {
799+
try {
800+
N_SetWindowlessFrameRate(frameRate);
801+
} catch (UnsatisfiedLinkError ule) {
802+
ule.printStackTrace();
803+
}
804+
}
805+
806+
public CompletableFuture<Integer> getWindowlessFrameRate() {
807+
final CompletableFuture<Integer> future = new CompletableFuture<>();
808+
try {
809+
N_GetWindowlessFrameRate(future::complete);
810+
} catch (UnsatisfiedLinkError ule) {
811+
ule.printStackTrace();
812+
future.complete(0);
813+
}
814+
return future;
815+
}
816+
817+
private interface IntCallback {
818+
void onComplete(int value);
794819
}
795820

796821
private final native boolean N_CreateBrowser(CefClientHandler clientHandler, long windowHandle,
797822
String url, boolean osr, boolean transparent, Component canvas,
798-
CefRequestContext context);
823+
CefRequestContext context, CefBrowserSettings settings);
799824
private final native boolean N_CreateDevTools(CefBrowser parent, CefClientHandler clientHandler,
800825
long windowHandle, boolean osr, boolean transparent, Component canvas, Point inspectAt);
801826
private final native void N_ExecuteDevToolsMethod(
802-
String method, String parametersAsJson, DevToolsMethodCallback callback);
827+
String method, String parametersAsJson, IntCallback callback);
803828
private final native CefRegistration N_AddDevToolsMessageObserver(
804829
CefDevToolsMessageObserver observer);
805830
private final native long N_GetWindowHandle(long surfaceHandle);
@@ -860,4 +885,6 @@ private final native void N_DragTargetDragEnter(
860885
private final native void N_UpdateUI(Rectangle contentRect, Rectangle browserRect);
861886
private final native void N_SetParent(long windowHandle, Component canvas);
862887
private final native void N_NotifyMoveOrResizeStarted();
888+
private final native void N_SetWindowlessFrameRate(int frameRate);
889+
private final native void N_GetWindowlessFrameRate(IntCallback frameRateCallback);
863890
}

java/tests/detailed/MainFrame.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import org.cef.CefApp;
88
import org.cef.CefApp.CefVersion;
9+
import org.cef.CefBrowserSettings;
910
import org.cef.CefClient;
1011
import org.cef.CefSettings;
1112
import org.cef.CefSettings.ColorType;
@@ -58,6 +59,7 @@ public static void main(String[] args) {
5859
boolean osrEnabledArg = false;
5960
boolean transparentPaintingEnabledArg = false;
6061
boolean createImmediately = false;
62+
int windowless_frame_rate = 0;
6163
for (String arg : args) {
6264
arg = arg.toLowerCase();
6365
if (arg.equals("--off-screen-rendering-enabled")) {
@@ -66,17 +68,30 @@ public static void main(String[] args) {
6668
transparentPaintingEnabledArg = true;
6769
} else if (arg.equals("--create-immediately")) {
6870
createImmediately = true;
71+
} else if (arg.equals("--windowless-frame-rate-60")) {
72+
windowless_frame_rate = 60;
6973
}
7074
}
7175

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

7478
// MainFrame keeps all the knowledge to display the embedded browser
7579
// frame.
76-
final MainFrame frame = new MainFrame(
77-
osrEnabledArg, transparentPaintingEnabledArg, createImmediately, args);
80+
final MainFrame frame = new MainFrame(osrEnabledArg, transparentPaintingEnabledArg,
81+
createImmediately, windowless_frame_rate, args);
7882
frame.setSize(800, 600);
7983
frame.setVisible(true);
84+
85+
if (osrEnabledArg && windowless_frame_rate != 0) {
86+
frame.getBrowser().getWindowlessFrameRate().thenAccept(
87+
framerate -> System.out.println("Framerate is:" + framerate));
88+
89+
frame.getBrowser().setWindowlessFrameRate(2);
90+
frame.getBrowser().getWindowlessFrameRate().thenAccept(
91+
framerate -> System.out.println("Framerate is:" + framerate));
92+
93+
frame.getBrowser().setWindowlessFrameRate(windowless_frame_rate);
94+
}
8095
}
8196

8297
private final CefClient client_;
@@ -88,7 +103,7 @@ public static void main(String[] args) {
88103
private boolean transparent_painting_enabled_;
89104

90105
public MainFrame(boolean osrEnabled, boolean transparentPaintingEnabled,
91-
boolean createImmediately, String[] args) {
106+
boolean createImmediately, int windowless_frame_rate, String[] args) {
92107
this.osr_enabled_ = osrEnabled;
93108
this.transparent_painting_enabled_ = transparentPaintingEnabled;
94109

@@ -200,9 +215,12 @@ public void onLoadError(CefBrowser browser, CefFrame frame, ErrorCode errorCode,
200215
}
201216
});
202217

218+
CefBrowserSettings browserSettings = new CefBrowserSettings();
219+
browserSettings.windowless_frame_rate = windowless_frame_rate;
220+
203221
// Create the browser.
204-
CefBrowser browser = client_.createBrowser(
205-
"http://www.google.com", osrEnabled, transparentPaintingEnabled, null);
222+
CefBrowser browser = client_.createBrowser("http://www.google.com", osrEnabled,
223+
transparentPaintingEnabled, null, browserSettings);
206224
setBrowser(browser);
207225

208226
// Set up the UI for this example implementation.

0 commit comments

Comments
 (0)