diff --git a/java/org/cef/CefBrowserSettings.java b/java/org/cef/CefBrowserSettings.java index 8733a418..36e09598 100644 --- a/java/org/cef/CefBrowserSettings.java +++ b/java/org/cef/CefBrowserSettings.java @@ -20,12 +20,29 @@ public class CefBrowserSettings { */ public int windowless_frame_rate = 0; + /** + * Set to true to enable shared texture rendering. When enabled, the browser + * will render to a shared texture that can be accessed by the host application + * for hardware-accelerated compositing. This is supported on Windows via D3D11, + * macOS via Metal/OpenGL, and Linux via native buffers. + */ + public boolean shared_texture_enabled = false; + + /** + * Set to true to enable external begin frame scheduling. When enabled, the + * client must call CefBrowserHost::SendExternalBeginFrame to trigger frame + * rendering at the specified frame rate. + */ + public boolean external_begin_frame_enabled = false; + public CefBrowserSettings() {} @Override public CefBrowserSettings clone() { CefBrowserSettings tmp = new CefBrowserSettings(); tmp.windowless_frame_rate = windowless_frame_rate; + tmp.shared_texture_enabled = shared_texture_enabled; + tmp.external_begin_frame_enabled = external_begin_frame_enabled; return tmp; } } diff --git a/java/org/cef/CefClient.java b/java/org/cef/CefClient.java index 50693328..4e70ecb8 100644 --- a/java/org/cef/CefClient.java +++ b/java/org/cef/CefClient.java @@ -87,7 +87,7 @@ public CefBrowser createBrowser(String url, boolean isTransparent, } public CefBrowser createBrowser(String url, boolean isTransparent, - CefRequestContext context, CefBrowserSettings settings) { + CefRequestContext context, CefBrowserSettings settings) { if (isDisposed_) throw new IllegalStateException("Can't create browser. CefClient is disposed"); return CefBrowserFactory.create( @@ -122,7 +122,7 @@ protected CefDialogHandler getDialogHandler() { protected CefDisplayHandler getDisplayHandler() { return this; } - + @Override protected CefAudioHandler getAudioHandler() { return this; @@ -230,7 +230,7 @@ public void removeDialogHandler() { @Override public boolean onFileDialog(CefBrowser browser, FileDialogMode mode, String title, String defaultFilePath, Vector acceptFilters, Vector acceptExtensions, - Vector acceptDescriptions, CefFileDialogCallback callback) { + Vector acceptDescriptions, CefFileDialogCallback callback) { if (dialogHandler_ != null && browser != null) { return dialogHandler_.onFileDialog(browser, mode, title, defaultFilePath, acceptFilters, acceptExtensions, acceptDescriptions, callback); @@ -322,7 +322,7 @@ public void removeDownloadHandler() { @Override public boolean onBeforeDownload(CefBrowser browser, CefDownloadItem downloadItem, - String suggestedName, CefBeforeDownloadCallback callback) { + String suggestedName, CefBeforeDownloadCallback callback) { if (downloadHandler_ != null && browser != null) return downloadHandler_.onBeforeDownload( browser, downloadItem, suggestedName, callback); @@ -693,6 +693,15 @@ public void onPaint(CefBrowser browser, boolean popup, Rectangle[] dirtyRects, realHandler.onPaint(browser, popup, dirtyRects, buffer, width, height); } + @Override + public void onAcceleratedPaint(CefBrowser browser, boolean popup, Rectangle[] dirtyRects, CefAcceleratedPaintInfo info) { + if (browser == null) return; + + CefRenderHandler realHandler = browser.getRenderHandler(); + if (realHandler != null) + realHandler.onAcceleratedPaint(browser, popup, dirtyRects, info); + } + @Override public void addOnPaintListener(Consumer listener) {} @@ -702,6 +711,15 @@ public void setOnPaintListener(Consumer listener) {} @Override public void removeOnPaintListener(Consumer listener) {} + @Override + public void addOnAcceleratedPaintListener(Consumer listener) {} + + @Override + public void setOnAcceleratedPaintListener(Consumer listener) {} + + @Override + public void removeOnAcceleratedPaintListener(Consumer listener) {} + @Override public boolean startDragging(CefBrowser browser, CefDragData dragData, int mask, int x, int y) { if (browser == null) return false; @@ -808,39 +826,39 @@ public void onMouseEvent( public boolean getScreenInfo(CefBrowser arg0, CefScreenInfo arg1) { return false; } - + // CefAudioHandler - + public CefClient addAudioHandler(CefAudioHandler handler) { if (audioHandler_ == null) audioHandler_ = handler; return this; } - + public void removeAudioHandler() { audioHandler_ = null; } - + @Override public boolean getAudioParameters(CefBrowser browser, CefAudioParameters params) { if (audioHandler_ != null) return audioHandler_.getAudioParameters(browser, params); return false; } - + @Override public void onAudioStreamStarted(CefBrowser browser, CefAudioParameters params, int channels) { if (audioHandler_ != null) audioHandler_.onAudioStreamStarted(browser, params, channels); } - + @Override public void onAudioStreamPacket(CefBrowser browser, DataPointer data, int frames, long pts) { if (audioHandler_ != null) audioHandler_.onAudioStreamPacket(browser, data, frames, pts); } - + @Override public void onAudioStreamStopped(CefBrowser browser) { if (audioHandler_ != null) audioHandler_.onAudioStreamStopped(browser); } - + @Override public void onAudioStreamError(CefBrowser browser, String text) { if (audioHandler_ != null) audioHandler_.onAudioStreamError(browser, text); diff --git a/java/org/cef/browser/CefAcceleratedPaintEvent.java b/java/org/cef/browser/CefAcceleratedPaintEvent.java new file mode 100644 index 00000000..4b840b10 --- /dev/null +++ b/java/org/cef/browser/CefAcceleratedPaintEvent.java @@ -0,0 +1,48 @@ +// 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.handler.CefAcceleratedPaintInfo; + +import java.awt.*; + +public class CefAcceleratedPaintEvent { + private final CefBrowser browser; + private final boolean popup; + private final Rectangle[] dirtyRects; + private final CefAcceleratedPaintInfo acceleratedPaintInfo; + + public CefAcceleratedPaintEvent(CefBrowser browser, boolean popup, Rectangle[] dirtyRects, + CefAcceleratedPaintInfo acceleratedPaintInfo) { + this.browser = browser; + this.popup = popup; + this.dirtyRects = dirtyRects; + this.acceleratedPaintInfo = acceleratedPaintInfo; + } + + public CefBrowser getBrowser() { + return browser; + } + + public boolean getPopup() { + return popup; + } + + public Rectangle[] getDirtyRects() { + return dirtyRects; + } + + public CefAcceleratedPaintInfo getAcceleratedPaintInfo() { + return acceleratedPaintInfo; + } + + public int getWidth() { + return acceleratedPaintInfo.width; + } + + public int getHeight() { + return acceleratedPaintInfo.height; + } +} diff --git a/java/org/cef/browser/CefBrowser.java b/java/org/cef/browser/CefBrowser.java index 5818e681..e60c09bf 100644 --- a/java/org/cef/browser/CefBrowser.java +++ b/java/org/cef/browser/CefBrowser.java @@ -398,6 +398,15 @@ public void runFileDialog(FileDialogMode mode, String title, String defaultFileP */ public void setWindowlessFrameRate(int frameRate); + /** + * Send an external begin frame to trigger frame rendering when external begin frame + * scheduling is enabled. This method should be called at the desired frame rate when + * CefBrowserSettings.external_begin_frame_enabled is set to true. + * + * @throws UnsupportedOperationException if not supported + */ + public void sendExternalBeginFrame(); + /** * 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 diff --git a/java/org/cef/browser/CefBrowserOsr.java b/java/org/cef/browser/CefBrowserOsr.java index 08d40ef7..d297360d 100644 --- a/java/org/cef/browser/CefBrowserOsr.java +++ b/java/org/cef/browser/CefBrowserOsr.java @@ -9,7 +9,9 @@ import org.cef.callback.CefDragData; import org.cef.handler.CefRenderHandler; import org.cef.handler.CefScreenInfo; +import org.cef.handler.CefAcceleratedPaintInfo; +import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; import java.nio.ByteBuffer; @@ -23,169 +25,199 @@ * 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_; - - private CopyOnWriteArrayList> onPaintListeners = new CopyOnWriteArrayList<>(); - - protected 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) { - } + 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<>(); + + private CopyOnWriteArrayList> onAcceleratedPaintListeners = + new CopyOnWriteArrayList<>(); + + protected 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 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; - } + @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 addOnAcceleratedPaintListener(Consumer listener) { + onAcceleratedPaintListeners.add(listener); + } + + @Override + public void setOnAcceleratedPaintListener(Consumer listener) { + onAcceleratedPaintListeners.clear(); + onAcceleratedPaintListeners.add(listener); + } + + @Override + public void removeOnAcceleratedPaintListener(Consumer listener) { + onAcceleratedPaintListeners.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 void onAcceleratedPaint(CefBrowser browser, boolean popup, Rectangle[] dirtyRects, CefAcceleratedPaintInfo info) { + if (!onAcceleratedPaintListeners.isEmpty()) { + CefAcceleratedPaintEvent paintEvent = + new CefAcceleratedPaintEvent(browser, popup, dirtyRects, info); + for (Consumer l : onAcceleratedPaintListeners) { + 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 fde036e9..32735a48 100644 --- a/java/org/cef/browser/CefBrowser_N.java +++ b/java/org/cef/browser/CefBrowser_N.java @@ -772,6 +772,14 @@ public void setWindowlessFrameRate(int frameRate) { } } + public void sendExternalBeginFrame() { + try { + N_SendExternalBeginFrame(); + } catch (UnsatisfiedLinkError ule) { + ule.printStackTrace(); + } + } + public CompletableFuture getWindowlessFrameRate() { final CompletableFuture future = new CompletableFuture<>(); try { @@ -854,5 +862,6 @@ private final native void N_DragTargetDragEnter( 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_SendExternalBeginFrame(); private final native void N_GetWindowlessFrameRate(IntCallback frameRateCallback); } diff --git a/java/org/cef/handler/CefAcceleratedPaintInfo.java b/java/org/cef/handler/CefAcceleratedPaintInfo.java new file mode 100644 index 00000000..bd8aeedc --- /dev/null +++ b/java/org/cef/handler/CefAcceleratedPaintInfo.java @@ -0,0 +1,43 @@ +// 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.handler; + +/** + * Structure representing shared texture info for accelerated painting. + */ +public class CefAcceleratedPaintInfo { + /** + * Shared texture handle. The meaning depends on the platform: + * - Windows: HANDLE to a texture that can be opened with D3D11 OpenSharedResource + * - macOS: IOSurface pointer that can be opened with Metal or OpenGL + * - Linux: Contains several planes, each with an fd to the underlying system native buffer + */ + public long shared_texture_handle = 0; + + /** + * Format of the shared texture. + */ + public int format = 0; + + /** + * Size information for the shared texture. + */ + public int width = 0; + public int height = 0; + + public CefAcceleratedPaintInfo() {} + + public CefAcceleratedPaintInfo(long shared_texture_handle, int format, int width, int height) { + this.shared_texture_handle = shared_texture_handle; + this.format = format; + this.width = width; + this.height = height; + } + + @Override + public CefAcceleratedPaintInfo clone() { + return new CefAcceleratedPaintInfo(shared_texture_handle, format, width, height); + } +} diff --git a/java/org/cef/handler/CefRenderHandler.java b/java/org/cef/handler/CefRenderHandler.java index 258df884..47754504 100644 --- a/java/org/cef/handler/CefRenderHandler.java +++ b/java/org/cef/handler/CefRenderHandler.java @@ -4,6 +4,7 @@ package org.cef.handler; +import org.cef.browser.CefAcceleratedPaintEvent; import org.cef.browser.CefBrowser; import org.cef.browser.CefPaintEvent; import org.cef.callback.CefDragData; @@ -67,6 +68,35 @@ public interface CefRenderHandler { public void onPaint(CefBrowser browser, boolean popup, Rectangle[] dirtyRects, ByteBuffer buffer, int width, int height); + /** + * Called when an element has been rendered to the shared texture handle. + * This method is only called when CefWindowInfo::shared_texture_enabled is set to true. + * @param browser The browser generating the event. + * @param popup True if painting a popup window. + * @param dirtyRects Array of dirty regions. + * @param info Contains the shared handle and texture information. + */ + public void onAcceleratedPaint(CefBrowser browser, boolean popup, Rectangle[] dirtyRects, + CefAcceleratedPaintInfo info); + + /** + * Add provided listener for accelerated paint events. + * @param listener Code that gets executed after a frame was rendered with accelerated painting. + */ + public void addOnAcceleratedPaintListener(Consumer listener); + + /** + * Remove existing accelerated paint listeners and replace with provided listener. + * @param listener Code that gets executed after a frame was rendered with accelerated painting. + */ + public void setOnAcceleratedPaintListener(Consumer listener); + + /** + * Remove provided accelerated paint listener. + * @param listener Code that gets executed after a frame was rendered with accelerated painting. + */ + public void removeOnAcceleratedPaintListener(Consumer listener); + /** * Add provided listener. * @param listener Code that gets executed after a frame was rendered. diff --git a/java/org/cef/handler/CefRenderHandlerAdapter.java b/java/org/cef/handler/CefRenderHandlerAdapter.java index ea782830..9ff45419 100644 --- a/java/org/cef/handler/CefRenderHandlerAdapter.java +++ b/java/org/cef/handler/CefRenderHandlerAdapter.java @@ -42,6 +42,10 @@ public void onPopupSize(CefBrowser browser, Rectangle size) {} public void onPaint(CefBrowser browser, boolean popup, Rectangle[] dirtyRects, ByteBuffer buffer, int width, int height) {} + @Override + public void onAcceleratedPaint(CefBrowser browser, boolean popup, Rectangle[] dirtyRects, + CefAcceleratedPaintInfo info) {} + @Override public boolean onCursorChange(CefBrowser browser, int cursorType) { return false; diff --git a/native/CefBrowser_N.cpp b/native/CefBrowser_N.cpp index f4ed2c6e..f14045c8 100644 --- a/native/CefBrowser_N.cpp +++ b/native/CefBrowser_N.cpp @@ -575,7 +575,7 @@ KeyboardCode KeyboardCodeFromXKeysym(unsigned int keysym) { return VKEY_OEM_7; case XK_ISO_Level5_Shift: return VKEY_OEM_8; - case XK_Shift_L: + case XK_Shift_L: case XK_Shift_R: return VKEY_SHIFT; case XK_Control_L: @@ -1042,6 +1042,10 @@ void create(std::shared_ptr objs, objs->jbrowserSettings != nullptr) { // Dev-tools settings are null GetJNIFieldInt(env, cefBrowserSettings, objs->jbrowserSettings, "windowless_frame_rate", &settings.windowless_frame_rate); + GetJNIFieldBoolean(env, cefBrowserSettings, objs->jbrowserSettings, + "shared_texture_enabled", &windowInfo.shared_texture_enabled); + GetJNIFieldBoolean(env, cefBrowserSettings, objs->jbrowserSettings, + "external_begin_frame_enabled", &windowInfo.external_begin_frame_enabled); } CefRefPtr browserObj; @@ -2167,6 +2171,14 @@ Java_org_cef_browser_CefBrowser_1N_N_1SetWindowlessFrameRate(JNIEnv* env, host->SetWindowlessFrameRate(frameRate); } +JNIEXPORT void JNICALL +Java_org_cef_browser_CefBrowser_1N_N_1SendExternalBeginFrame(JNIEnv* env, + jobject jbrowser) { + CefRefPtr browser = JNI_GET_BROWSER_OR_RETURN(env, jbrowser); + CefRefPtr host = browser->GetHost(); + host->SendExternalBeginFrame(); +} + void getWindowlessFrameRate(CefRefPtr host, CefRefPtr callback) { callback->onComplete((jint)host->GetWindowlessFrameRate()); diff --git a/native/CefBrowser_N.h b/native/CefBrowser_N.h index 4aa37469..990f7a19 100644 --- a/native/CefBrowser_N.h +++ b/native/CefBrowser_N.h @@ -555,6 +555,15 @@ Java_org_cef_browser_CefBrowser_1N_N_1GetWindowlessFrameRate(JNIEnv*, jobject, jobject); +/* + * Class: org_cef_browser_CefBrowser_N + * Method: N_SendExternalBeginFrame + * Signature: ()V + */ +JNIEXPORT void JNICALL +Java_org_cef_browser_CefBrowser_1N_N_1SendExternalBeginFrame(JNIEnv*, + jobject); + #ifdef __cplusplus } #endif diff --git a/native/jni_util.cpp b/native/jni_util.cpp index 4bee5978..0134be54 100644 --- a/native/jni_util.cpp +++ b/native/jni_util.cpp @@ -894,6 +894,20 @@ bool SetJNIFieldBoolean(JNIEnv* env, return false; } +bool SetJNIFieldLong(JNIEnv* env, + jclass cls, + jobject obj, + const char* field_name, + jlong value) { + jfieldID field = env->GetFieldID(cls, field_name, "J"); + if (field) { + env->SetLongField(obj, field, value); + return true; + } + env->ExceptionClear(); + return false; +} + bool GetJNIFieldStaticInt(JNIEnv* env, jclass cls, const char* field_name, diff --git a/native/jni_util.h b/native/jni_util.h index 4b78b3f3..306b2001 100644 --- a/native/jni_util.h +++ b/native/jni_util.h @@ -148,6 +148,11 @@ bool SetJNIFieldBoolean(JNIEnv* env, jobject obj, const char* field_name, int value); +bool SetJNIFieldLong(JNIEnv* env, + jclass cls, + jobject obj, + const char* field_name, + jlong value); // Retrieve the static int value stored in the |field_name| field of |cls|. bool GetJNIFieldStaticInt(JNIEnv* env, diff --git a/native/render_handler.cpp b/native/render_handler.cpp index dee74281..cedb72ef 100644 --- a/native/render_handler.cpp +++ b/native/render_handler.cpp @@ -270,6 +270,48 @@ void RenderHandler::OnPaint(CefRefPtr browser, jdirectBuffer.get(), width, height); } +void RenderHandler::OnAcceleratedPaint(CefRefPtr browser, + PaintElementType type, + const RectList& dirtyRects, + const CefAcceleratedPaintInfo& info) { + ScopedJNIEnv env; + if (!env) + return; + + ScopedJNIBrowser jbrowser(env, browser); + jboolean jtype = type == PET_VIEW ? JNI_FALSE : JNI_TRUE; + ScopedJNIObjectLocal jrectArray(env, NewJNIRectArray(env, dirtyRects)); + + // Create CefAcceleratedPaintInfo Java object + ScopedJNIClass cls(env, "org/cef/handler/CefAcceleratedPaintInfo"); + if (!cls) + return; + ScopedJNIObjectLocal jpaintInfo(env, NewJNIObject(env, cls)); + if (!jpaintInfo) + return; + + // Get view rect to determine width and height + CefRect viewRect; + GetViewRect(browser, viewRect); + // Set the fields of the paint info object +#if defined(OS_WIN) + SetJNIFieldLong(env, cls, jpaintInfo, "shared_texture_handle", + reinterpret_cast(info.shared_texture_handle)); +#else + // On non-Windows platforms, shared_texture_handle is not available + SetJNIFieldLong(env, cls, jpaintInfo, "shared_texture_handle", 0); +#endif + SetJNIFieldInt(env, cls, jpaintInfo, "format", info.format); + SetJNIFieldInt(env, cls, jpaintInfo, "width", viewRect.width); + SetJNIFieldInt(env, cls, jpaintInfo, "height", viewRect.height); + + JNI_CALL_VOID_METHOD(env, handle_, "onAcceleratedPaint", + "(Lorg/cef/browser/CefBrowser;Z[Ljava/awt/" + "Rectangle;Lorg/cef/handler/CefAcceleratedPaintInfo;)V", + jbrowser.get(), jtype, jrectArray.get(), + jpaintInfo.get()); +} + bool RenderHandler::StartDragging(CefRefPtr browser, CefRefPtr drag_data, DragOperationsMask allowed_ops, diff --git a/native/render_handler.h b/native/render_handler.h index 27379d6e..55352392 100644 --- a/native/render_handler.h +++ b/native/render_handler.h @@ -40,6 +40,10 @@ class RenderHandler : public CefRenderHandler { const void* buffer, int width, int height) override; + virtual void OnAcceleratedPaint(CefRefPtr browser, + PaintElementType type, + const RectList& dirtyRects, + const CefAcceleratedPaintInfo& info) override; virtual bool StartDragging(CefRefPtr browser, CefRefPtr drag_data, DragOperationsMask allowed_ops,