diff options
59 files changed, 1242 insertions, 392 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 5286fb3..62466be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,8 +11,8 @@ # CMake-generated project formats that have been tested with JCEF include: # # Linux: Ninja, Unix Makefiles -# Mac OS X: Ninja, Xcode 5+ -# Windows: Ninja, Visual Studio 2010+ +# MacOS: Ninja, Xcode 8+ (x86_64) or Xcode 12.2+ (ARM64) +# Windows: Ninja, Visual Studio 2015+ # # Ninja is a cross-platform open-source tool for running fast builds using # pre-installed platform toolchains (GNU, clang, Xcode or MSVC). It can be @@ -27,20 +27,20 @@ # # - Linux requirements: # Currently supported distributions include Debian Wheezy, Ubuntu Precise, and -# related. Ubuntu 14.04 64-bit is recommended. Newer versions will likely also +# related. Ubuntu 18.04 64-bit is recommended. Newer versions will likely also # work but may not have been tested. # Required packages include: # build-essential -# libgtk2.0-dev # -# - Mac OS X requirements: -# Xcode 5 or newer building on Mac OS X 10.9 (Mavericks) or newer. Xcode 7.2 -# and OS X 10.11 are recommended. The Xcode command-line tools must also be -# installed. Only 64-bit builds are supported on OS X. +# - MacOS requirements: +# Xcode 8 or newer building on MacOS 10.11 (El Capitan) or newer for x86_64. +# Xcode 12.2 or newer building on MacOS 10.15.4 (Catalina) or newer for ARM64. +# Only 64-bit builds are supported. The Xcode command-line tools must also be +# installed. # # - Windows requirements: -# Visual Studio 2010 or newer building on Windows 7 or newer. Visual Studio -# 2015 Update 2 and Windows 10 64-bit are recommended. +# Visual Studio 2015 Update 2 or newer building on Windows 7 or newer. Visual +# Studio 2019 and Windows 10 64-bit are recommended. # # BUILD EXAMPLES # @@ -64,38 +64,43 @@ # > cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Debug .. # > ninja # -# To perform a Mac OS X build using a 64-bit CEF binary distribution: +# To perform a MacOS build using a 64-bit CEF binary distribution: # Using the Xcode IDE: # > cmake -G "Xcode" -DPROJECT_ARCH="x86_64" .. # Open jcef.xcodeproj in Xcode and select Product > Build. # -# Using Unix Makefiles: -# > cmake -G "Unix Makefiles" -DPROJECT_ARCH="x86_64" -DCMAKE_BUILD_TYPE=Debug .. -# > make -j4 -# # Using Ninja: # > cmake -G "Ninja" -DPROJECT_ARCH="x86_64" -DCMAKE_BUILD_TYPE=Debug .. # > ninja # +# To perform a MacOS build using an ARM64 CEF binary distribution: +# Using the Xcode IDE: +# > cmake -G "Xcode" -DPROJECT_ARCH="arm64" .. +# Open jcef.xcodeproj in Xcode and select Product > Build. +# +# Using Ninja: +# > cmake -G "Ninja" -DPROJECT_ARCH="arm64" -DCMAKE_BUILD_TYPE=Debug .. +# > ninja +# # To perform a Windows build using a 32-bit CEF binary distribution: -# Using the Visual Studio 2015 IDE: -# > cmake -G "Visual Studio 14" .. +# Using the Visual Studio 2019 IDE: +# > cmake -G "Visual Studio 16" -A Win32 .. # Open jcef.sln in Visual Studio and select Build > Build Solution. # -# Using Ninja with Visual Studio 2015 command-line tools: +# Using Ninja with Visual Studio 2019 command-line tools: # (this path may be different depending on your Visual Studio installation) -# > "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\vcvars32.bat" +# > "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvars32.bat" # > cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Debug .. # > ninja # # To perform a Windows build using a 64-bit CEF binary distribution: -# Using the Visual Studio 2015 IDE: -# > cmake -G "Visual Studio 14 Win64" .. +# Using the Visual Studio 2019 IDE: +# > cmake -G "Visual Studio 16" -A x64 .. # Open jcef.sln in Visual Studio and select Build > Build Solution. # -# Using Ninja with Visual Studio 2015 command-line tools: +# Using Ninja with Visual Studio 2019 command-line tools: # (this path may be different depending on your Visual Studio installation) -# > "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat" +# > "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvars64.bat" # > cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Debug .. # > ninja @@ -121,12 +126,16 @@ set_property(GLOBAL PROPERTY OS_FOLDERS ON) # Specify the CEF distribution version. if(NOT DEFINED CEF_VERSION) - set(CEF_VERSION "84.3.8+gc8a556f+chromium-84.0.4147.105") + set(CEF_VERSION "87.1.12+g03f9336+chromium-87.0.4280.88") endif() # Determine the platform. if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") - set(CEF_PLATFORM "macosx64") + if("${PROJECT_ARCH}" STREQUAL "arm64") + set(CEF_PLATFORM "macosarm64") + else() + set(CEF_PLATFORM "macosx64") + endif() elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") if(CMAKE_SIZEOF_VOID_P MATCHES 8) set(CEF_PLATFORM "linux64") @@ -4,6 +4,7 @@ The Java Chromium Embedded Framework (JCEF) is a simple framework for embedding * Building JCEF - https://bitbucket.org/chromiumembedded/java-cef/wiki/BranchesAndBuilding
* Support Forum - http://magpcss.org/ceforum/viewforum.php?f=17
+* Downloads - https://github.com/jcefbuild/jcefbuild
* Donations - http://www.magpcss.org/ceforum/donate.php
# Introduction
diff --git a/cmake/DownloadCEF.cmake b/cmake/DownloadCEF.cmake index f702268..a64592b 100644 --- a/cmake/DownloadCEF.cmake +++ b/cmake/DownloadCEF.cmake @@ -5,7 +5,7 @@ # Download the CEF binary distribution for |platform| and |version| to # |download_dir|. The |CEF_ROOT| variable will be set in global scope pointing # to the extracted location. -# Visit http://opensource.spotify.com/cefbuilds/index.html for the list of +# Visit https://cef-builds.spotifycdn.com/index.html for the list of # supported platforms and versions. function(DownloadCEF platform version download_dir) @@ -21,7 +21,7 @@ function(DownloadCEF platform version download_dir) set(CEF_DOWNLOAD_FILENAME "${CEF_DISTRIBUTION}.tar.bz2") set(CEF_DOWNLOAD_PATH "${CEF_DOWNLOAD_DIR}/${CEF_DOWNLOAD_FILENAME}") if(NOT EXISTS "${CEF_DOWNLOAD_PATH}") - set(CEF_DOWNLOAD_URL "http://opensource.spotify.com/cefbuilds/${CEF_DOWNLOAD_FILENAME}") + set(CEF_DOWNLOAD_URL "https://cef-builds.spotifycdn.com/${CEF_DOWNLOAD_FILENAME}") string(REPLACE "+" "%2B" CEF_DOWNLOAD_URL_ESCAPED ${CEF_DOWNLOAD_URL}) # Download the SHA1 hash for the binary distribution. diff --git a/java/org/cef/CefClient.java b/java/org/cef/CefClient.java index 7aff09f..508390b 100644 --- a/java/org/cef/CefClient.java +++ b/java/org/cef/CefClient.java @@ -37,6 +37,7 @@ import org.cef.handler.CefRenderHandler; import org.cef.handler.CefRequestHandler; import org.cef.handler.CefResourceHandler; import org.cef.handler.CefResourceRequestHandler; +import org.cef.handler.CefScreenInfo; import org.cef.handler.CefWindowHandler; import org.cef.misc.BoolRef; import org.cef.misc.StringRef; @@ -341,6 +342,24 @@ public class CefClient extends CefClientHandler return false; } + @Override + public boolean onCursorChange(CefBrowser browser, int cursorType) { + if (browser == null) { + return false; + } + + if (displayHandler_ != null && displayHandler_.onCursorChange(browser, cursorType)) { + return true; + } + + CefRenderHandler realHandler = browser.getRenderHandler(); + if (realHandler != null) { + return realHandler.onCursorChange(browser, cursorType); + } + + return false; + } + // CefDownloadHandler public CefClient addDownloadHandler(CefDownloadHandler handler) { @@ -718,14 +737,6 @@ public class CefClient extends CefClientHandler } @Override - public void onCursorChange(CefBrowser browser, int cursorType) { - if (browser == null) return; - - CefRenderHandler realHandler = browser.getRenderHandler(); - if (realHandler != null) realHandler.onCursorChange(browser, cursorType); - } - - @Override public boolean startDragging(CefBrowser browser, CefDragData dragData, int mask, int x, int y) { if (browser == null) return false; @@ -763,6 +774,15 @@ public class CefClient extends CefClientHandler } @Override + public boolean onOpenURLFromTab( + CefBrowser browser, CefFrame frame, String target_url, boolean user_gesture) { + if (isDisposed_) return true; + if (requestHandler_ != null && browser != null) + return requestHandler_.onOpenURLFromTab(browser, frame, target_url, user_gesture); + return false; + } + + @Override public CefResourceRequestHandler getResourceRequestHandler(CefBrowser browser, CefFrame frame, CefRequest request, boolean isNavigation, boolean isDownload, String requestInitiator, BoolRef disableDefaultHandling) { @@ -828,4 +848,9 @@ public class CefClient extends CefClientHandler if (realHandler != null) realHandler.onMouseEvent(browser, event, screenX, screenY, modifier, button); } + + @Override + public boolean getScreenInfo(CefBrowser arg0, CefScreenInfo arg1) { + return false; + } } diff --git a/java/org/cef/browser/CefBrowser.java b/java/org/cef/browser/CefBrowser.java index 83e5eae..35e4b32 100644 --- a/java/org/cef/browser/CefBrowser.java +++ b/java/org/cef/browser/CefBrowser.java @@ -19,7 +19,9 @@ import java.awt.Point; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; +import java.awt.image.BufferedImage; import java.util.Vector; +import java.util.concurrent.CompletableFuture; /** * Interface representing a browser. @@ -380,4 +382,27 @@ public interface CefBrowser { * @since api-1.2 */ void sendMouseWheelEvent(MouseWheelEvent e); + + /** + * Captures a screenshot-like image of the currently displayed content and returns it. + * <p> + * If executed on the AWT Event Thread, this returns an immediately resolved {@link + * java.util.concurrent.CompletableFuture}. If executed from another thread, the {@link + * java.util.concurrent.CompletableFuture} returned is resolved as soon as the screenshot + * has been taken (which must happen on the event thread). + * <p> + * The generated screenshot can either be returned as-is, containing all natively-rendered + * pixels, or it can be scaled to match the logical width and height of the window. + * This distinction is only relevant in case of differing logical and physical resolutions + * (for example with HiDPI/Retina displays, which have a scaling factor of for example 2 + * between the logical width of a window (ex. 400px) and the actual number of pixels in + * each row (ex. 800px with a scaling factor of 2)). + * + * @param nativeResolution whether to return an image at full native resolution (true) + * or a scaled-down version whose width and height are equal to the logical size + * of the screenshotted browser window + * @return the screenshot image + * @throws UnsupportedOperationException if not supported + */ + public CompletableFuture<BufferedImage> createScreenshot(boolean nativeResolution); } diff --git a/java/org/cef/browser/CefBrowserOsr.java b/java/org/cef/browser/CefBrowserOsr.java index 18a9d1e..c7acf60 100644 --- a/java/org/cef/browser/CefBrowserOsr.java +++ b/java/org/cef/browser/CefBrowserOsr.java @@ -6,21 +6,27 @@ package org.cef.browser; import com.jetbrains.cef.JCefAppConfig; import com.jogamp.nativewindow.NativeSurface; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLContext; import com.jogamp.opengl.GLEventListener; import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.awt.GLCanvas; +import com.jogamp.opengl.util.GLBuffers; import org.cef.CefClient; import org.cef.OS; import org.cef.callback.CefDragData; import org.cef.handler.CefRenderHandler; +import org.cef.handler.CefScreenInfo; import java.awt.Component; import java.awt.Cursor; import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; import java.awt.Point; import java.awt.Rectangle; import java.awt.dnd.DropTarget; @@ -33,7 +39,22 @@ import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; +import java.awt.geom.AffineTransform; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.lang.ClassNotFoundException; +import java.lang.IllegalAccessException; +import java.lang.IllegalArgumentException; +import java.lang.NoSuchMethodException; +import java.lang.SecurityException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.nio.ByteBuffer; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import javax.swing.MenuSelectionManager; import javax.swing.SwingUtilities; @@ -47,8 +68,12 @@ class CefBrowserOsr extends CefBrowser_N implements CefRenderHandler { private CefRenderer renderer_; private GLCanvas canvas_; private long window_handle_ = 0; + private boolean justCreated_ = false; private 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_; CefBrowserOsr(CefClient client, String url, boolean transparent, CefRequestContext context) { @@ -65,6 +90,7 @@ class CefBrowserOsr extends CefBrowser_N implements CefRenderHandler { @Override public void createImmediately() { + justCreated_ = true; // Create the browser immediately. createBrowserIfRequired(false); } @@ -104,11 +130,76 @@ class CefBrowserOsr extends CefBrowser_N implements CefRenderHandler { GLProfile glprofile = GLProfile.getMaxFixedFunc(true); GLCapabilities glcapabilities = new GLCapabilities(glprofile); canvas_ = new GLCanvas(glcapabilities) { + private Method scaleFactorAccessor = null; + private boolean removed_ = true; + @Override public void paint(Graphics g) { createBrowserIfRequired(true); + if (g instanceof Graphics2D) { + GraphicsConfiguration config = ((Graphics2D) g).getDeviceConfiguration(); + depth = config.getColorModel().getPixelSize(); + depth_per_component = config.getColorModel().getComponentSize()[0]; + + if (OS.isMacintosh() + && System.getProperty("java.runtime.version").startsWith("1.8")) { + // This fixes a weird thing on MacOS: the scale factor being read from + // getTransform().getScaleX() is incorrect for Java 8 VMs; it is always + // 1, even though Retina display scaling of window sizes etc. is + // definitely ongoing somewhere in the lower levels of AWT. This isn't + // too big of a problem for us, because the transparent scaling handles + // the situation, except for one thing: the screenshot-grabbing + // code below, which reads from the OpenGL context, must know the real + // scale factor, because the image to be read is larger by that factor + // and thus a bigger buffer is required. This is why there's some + // admittedly-ugly reflection magic going on below that's able to get + // the real scale factor. + // All of this is not relevant for either Windows or MacOS JDKs > 8, + // for which the official "getScaleX()" approach works fine. + try { + if (scaleFactorAccessor == null) { + scaleFactorAccessor = getClass() + .getClassLoader() + .loadClass("sun.awt.CGraphicsDevice") + .getDeclaredMethod("getScaleFactor"); + } + Object factor = scaleFactorAccessor.invoke(config.getDevice()); + if (factor instanceof Integer) { + scaleFactor_ = ((Integer) factor).doubleValue(); + } else { + scaleFactor_ = 1.0; + } + } catch (InvocationTargetException | IllegalAccessException + | IllegalArgumentException | NoSuchMethodException + | SecurityException | ClassNotFoundException exc) { + scaleFactor_ = 1.0; + } + } else { + scaleFactor_ = ((Graphics2D) g).getTransform().getScaleX(); + } + } super.paint(g); } + + @Override + public void addNotify() { + super.addNotify(); + if (removed_) { + notifyAfterParentChanged(); + removed_ = false; + } + } + + @Override + public void removeNotify() { + if (!removed_) { + if (!isClosed()) { + notifyAfterParentChanged(); + } + removed_ = true; + } + super.removeNotify(); + } }; // The GLContext will be re-initialized when changing displays, resulting in calls to @@ -119,7 +210,7 @@ class CefBrowserOsr extends CefBrowser_N implements CefRenderHandler { GLAutoDrawable glautodrawable, int x, int y, int width, int height) { browser_rect_.setBounds(canvas_.getBounds()/*x, y, width, height*/); // [tav] todo: revise it screenPoint_ = canvas_.getLocationOnScreen(); - wasResized(width, height); + wasResized(newWidth, newHeight); } @Override @@ -275,12 +366,15 @@ class CefBrowserOsr extends CefBrowser_N implements CefRenderHandler { } @Override - public void onCursorChange(CefBrowser browser, final int cursorType) { + public boolean onCursorChange(CefBrowser browser, final int cursorType) { SwingUtilities.invokeLater(new Runnable() { public void run() { canvas_.setCursor(new Cursor(cursorType)); } }); + + // OSR always handles the cursor change. + return true; } @Override @@ -308,9 +402,182 @@ class CefBrowserOsr extends CefBrowser_N implements CefRenderHandler { createBrowser(getClient(), windowHandle, getUrl(), true, isTransparent_, null, getRequestContext()); } - } else { - // OSR windows cannot be reparented after creation. + } 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<BufferedImage> createScreenshot(boolean nativeResolution) { + int width = (int) (canvas_.getWidth() * scaleFactor_); + int height = (int) (canvas_.getHeight() * scaleFactor_); + + // In order to grab a screenshot of the browser window, we need to get the OpenGL internals + // from the GLCanvas that displays the browser. + GL2 gl = canvas_.getGL().getGL2(); + int textureId = renderer_.getTextureID(); + + // This mirrors the two ways in which CefRenderer may render images internally - either via + // an incrementally updated texture that is the same size as the window and simply rendered + // onto a textured quad by graphics hardware, in which case we capture the data directly + // from this texture, or by directly writing pixels into the OpenGL framebuffer, in which + // case we directly read those pixels back. The latter is the way chosen if there is no + // hardware rasterizer capability detected. We can simply distinguish both approaches by + // looking whether the textureId of the renderer is a valid (non-zero) one. + boolean useReadPixels = (textureId == 0); + + // This Callable encapsulates the pixel-reading code. After running it, the screenshot + // BufferedImage contains the grabbed image. + final Callable<BufferedImage> pixelGrabberCallable = new Callable<BufferedImage>() { + @Override + public BufferedImage call() { + BufferedImage screenshot = + new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + ByteBuffer buffer = GLBuffers.newDirectByteBuffer(width * height * 4); + + gl.getContext().makeCurrent(); + try { + if (useReadPixels) { + // If pixels are copied directly to the framebuffer, we also directly read + // them back. + gl.glReadPixels( + 0, 0, width, height, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, buffer); + } else { + // In this case, read the texture pixel data from the previously-retrieved + // texture ID + gl.glEnable(GL.GL_TEXTURE_2D); + gl.glBindTexture(GL.GL_TEXTURE_2D, textureId); + gl.glGetTexImage( + GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, buffer); + gl.glDisable(GL.GL_TEXTURE_2D); + } + } finally { + gl.getContext().release(); + } + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + // The OpenGL functions only support RGBA, while Java BufferedImage uses + // ARGB. We must convert. + int r = (buffer.get() & 0xff); + int g = (buffer.get() & 0xff); + int b = (buffer.get() & 0xff); + int a = (buffer.get() & 0xff); + int argb = (a << 24) | (r << 16) | (g << 8) | (b << 0); + // If pixels were read from the framebuffer, we have to flip the resulting + // image on the Y axis, as the OpenGL framebuffer's y axis starts at the + // bottom of the image pointing "upwards", while BufferedImage has the + // origin in the upper left corner. This flipping is done when drawing into + // the BufferedImage. + screenshot.setRGB(x, useReadPixels ? (height - y - 1) : y, argb); + } + } + + if (!nativeResolution && scaleFactor_ != 1.0) { + // HiDPI images should be resized down to "normal" levels + BufferedImage resized = + new BufferedImage((int) (screenshot.getWidth() / scaleFactor_), + (int) (screenshot.getHeight() / scaleFactor_), + BufferedImage.TYPE_INT_ARGB); + AffineTransform tempTransform = new AffineTransform(); + tempTransform.scale(1.0 / scaleFactor_, 1.0 / scaleFactor_); + AffineTransformOp tempScaleOperation = + new AffineTransformOp(tempTransform, AffineTransformOp.TYPE_BILINEAR); + resized = tempScaleOperation.filter(screenshot, resized); + return resized; + } else { + return screenshot; + } + } + }; + + if (SwingUtilities.isEventDispatchThread()) { + // If called on the AWT event thread, just access the GL API + try { + BufferedImage screenshot = pixelGrabberCallable.call(); + return CompletableFuture.completedFuture(screenshot); + } catch (Exception e) { + CompletableFuture<BufferedImage> future = new CompletableFuture<BufferedImage>(); + future.completeExceptionally(e); + return future; + } + } else { + // If called from another thread, register a GLEventListener and trigger an async + // redraw, during which we use the GL API to grab the pixel data. An unresolved Future + // is returned, on which the caller can wait for a result (but not with the Event + // Thread, as we need that for pixel grabbing, which is why there's a safeguard in place + // to catch that situation if it accidentally happens). + CompletableFuture<BufferedImage> future = new CompletableFuture<BufferedImage>() { + private void safeguardGet() { + if (SwingUtilities.isEventDispatchThread()) { + throw new RuntimeException( + "Waiting on this Future using the AWT Event Thread is illegal, " + + "because it can potentially deadlock the thread."); + } + } + + @Override + public BufferedImage get() throws InterruptedException, ExecutionException { + safeguardGet(); + return super.get(); + } + + @Override + public BufferedImage get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + safeguardGet(); + return super.get(timeout, unit); + } + }; + canvas_.addGLEventListener(new GLEventListener() { + @Override + public void reshape( + GLAutoDrawable aDrawable, int aArg1, int aArg2, int aArg3, int aArg4) { + // ignore + } + + @Override + public void init(GLAutoDrawable aDrawable) { + // ignore + } + + @Override + public void dispose(GLAutoDrawable aDrawable) { + // ignore + } + + @Override + public void display(GLAutoDrawable aDrawable) { + canvas_.removeGLEventListener(this); + try { + future.complete(pixelGrabberCallable.call()); + } catch (Exception e) { + future.completeExceptionally(e); + } + } + }); + + // This repaint triggers an indirect call to the listeners' display method above, which + // ultimately completes the future that we return immediately. + canvas_.repaint(); + + return future; } } } diff --git a/java/org/cef/browser/CefBrowserWr.java b/java/org/cef/browser/CefBrowserWr.java index 0d63a83..4ef663b 100644 --- a/java/org/cef/browser/CefBrowserWr.java +++ b/java/org/cef/browser/CefBrowserWr.java @@ -20,7 +20,9 @@ import java.awt.event.HierarchyEvent; import java.awt.event.HierarchyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; +import java.awt.image.BufferedImage; import java.util.Date; +import java.util.concurrent.CompletableFuture; import javax.swing.JPanel; import javax.swing.JPopupMenu; @@ -428,4 +430,9 @@ class CefBrowserWr extends CefBrowser_N { return false; } + + @Override + public CompletableFuture<BufferedImage> createScreenshot(boolean nativeResolution) { + throw new UnsupportedOperationException("Unsupported for windowed rendering"); + } } diff --git a/java/org/cef/browser/CefBrowser_N.java b/java/org/cef/browser/CefBrowser_N.java index d017bde..4571c40 100644 --- a/java/org/cef/browser/CefBrowser_N.java +++ b/java/org/cef/browser/CefBrowser_N.java @@ -153,7 +153,7 @@ abstract class CefBrowser_N extends CefNativeAdapter implements CefBrowser { boolean osr, boolean transparent, Component canvas, CefRequestContext context) { if (getNativeRef("CefBrowser") == 0 && !isPending_) { try { - /*isPending_ = */N_CreateBrowser( + N_CreateBrowser( clientHandler, windowHandle, url, osr, transparent, canvas, context); } catch (UnsatisfiedLinkError err) { err.printStackTrace(); diff --git a/java/org/cef/browser/CefRenderer.java b/java/org/cef/browser/CefRenderer.java index f5d8e7c..2a29546 100644 --- a/java/org/cef/browser/CefRenderer.java +++ b/java/org/cef/browser/CefRenderer.java @@ -30,6 +30,10 @@ class CefRenderer { return transparent_; } + protected int getTextureID() { + return texture_id_[0]; + } + @SuppressWarnings("static-access") protected void initialize(GL2 gl2) { if (initialized_context_ == gl2) return; diff --git a/java/org/cef/handler/CefDisplayHandler.java b/java/org/cef/handler/CefDisplayHandler.java index 0a14229..0affefc 100644 --- a/java/org/cef/handler/CefDisplayHandler.java +++ b/java/org/cef/handler/CefDisplayHandler.java @@ -4,9 +4,9 @@ package org.cef.handler; +import org.cef.CefSettings; import org.cef.browser.CefBrowser; import org.cef.browser.CefFrame; -import org.cef.CefSettings; /** * Implement this interface to handle events related to browser display state. @@ -14,7 +14,7 @@ import org.cef.CefSettings; */ public interface CefDisplayHandler { /** - * Handle address changes. + * Browser address changed. * @param browser The browser generating the event. * @param frame The frame generating the event. * @param url The new address. @@ -22,32 +22,29 @@ public interface CefDisplayHandler { public void onAddressChange(CefBrowser browser, CefFrame frame, String url); /** - * Handle title changes. + * Browser title changed. * @param browser The browser generating the event. * @param title The new title. */ public void onTitleChange(CefBrowser browser, String title); /** - * Called when the browser is about to display a tooltip. - * + * About to display a tooltip. * @param browser The browser generating the event. * @param text Contains the text that will be displayed in the tooltip. - * @return To handle the display of the tooltip yourself return true. + * @return true to handle the tooltip display yourself. */ public boolean onTooltip(CefBrowser browser, String text); /** - * Called when the browser receives a status message. - * + * Received a status message. * @param browser The browser generating the event. * @param value Contains the text that will be displayed in the status message. */ public void onStatusMessage(CefBrowser browser, String value); /** - * Called to display a console message. - * + * Display a console message. * @param browser The browser generating the event. * @param level * @param message @@ -57,4 +54,12 @@ public interface CefDisplayHandler { */ public boolean onConsoleMessage(CefBrowser browser, CefSettings.LogSeverity level, String message, String source, int line); + + /** + * Handle cursor changes. + * @param browser The browser generating the event. + * @param cursorType The new cursor type. + * @return true if the cursor change was handled. + */ + public boolean onCursorChange(CefBrowser browser, int cursorType); } diff --git a/java/org/cef/handler/CefDisplayHandlerAdapter.java b/java/org/cef/handler/CefDisplayHandlerAdapter.java index 88de539..80ab96b 100644 --- a/java/org/cef/handler/CefDisplayHandlerAdapter.java +++ b/java/org/cef/handler/CefDisplayHandlerAdapter.java @@ -4,9 +4,9 @@ package org.cef.handler; +import org.cef.CefSettings; import org.cef.browser.CefBrowser; import org.cef.browser.CefFrame; -import org.cef.CefSettings; /** * An abstract adapter class for receiving display events. @@ -39,4 +39,9 @@ public abstract class CefDisplayHandlerAdapter implements CefDisplayHandler { String message, String source, int line) { return false; } + + @Override + public boolean onCursorChange(CefBrowser browser, int cursorType) { + return false; + } } diff --git a/java/org/cef/handler/CefRenderHandler.java b/java/org/cef/handler/CefRenderHandler.java index f43822b..5637eb0 100644 --- a/java/org/cef/handler/CefRenderHandler.java +++ b/java/org/cef/handler/CefRenderHandler.java @@ -4,13 +4,13 @@ package org.cef.handler; +import org.cef.browser.CefBrowser; +import org.cef.callback.CefDragData; + import java.awt.Point; import java.awt.Rectangle; import java.nio.ByteBuffer; -import org.cef.browser.CefBrowser; -import org.cef.callback.CefDragData; - /** * Implement this interface to handle events when window rendering is disabled. * The methods of this class will be called on the UI thread. @@ -22,6 +22,15 @@ public interface CefRenderHandler { * @return The view rectangle. */ public Rectangle getViewRect(CefBrowser browser); + + /** + * Retrieve the screen info. + * @param browser The browser generating the event. + * @param screenInfo The screenInfo + * @return True if this callback was handled. False to fallback to defaults. + */ + public boolean getScreenInfo(CefBrowser browser, CefScreenInfo screenInfo); + /** * Retrieve the screen point for the specified view point. * @param browser The browser generating the event. @@ -64,9 +73,10 @@ public interface CefRenderHandler { /** * Handle cursor changes. * @param browser The browser generating the event. - * @param cursor The new cursor. + * @param cursorType The new cursor type. + * @return true if the cursor change was handled. */ - public void onCursorChange(CefBrowser browser, int cursor); + public boolean onCursorChange(CefBrowser browser, int cursorType); /** * Called when the user starts dragging content in the web view. Contextual diff --git a/java/org/cef/handler/CefRenderHandlerAdapter.java b/java/org/cef/handler/CefRenderHandlerAdapter.java index 88c9c32..ca1dba9 100644 --- a/java/org/cef/handler/CefRenderHandlerAdapter.java +++ b/java/org/cef/handler/CefRenderHandlerAdapter.java @@ -4,13 +4,13 @@ package org.cef.handler; +import org.cef.browser.CefBrowser; +import org.cef.callback.CefDragData; + import java.awt.Point; import java.awt.Rectangle; import java.nio.ByteBuffer; -import org.cef.browser.CefBrowser; -import org.cef.callback.CefDragData; - /** * An abstract adapter class for receiving render events. * The methods in this class are empty. @@ -18,13 +18,13 @@ import org.cef.callback.CefDragData; */ public abstract class CefRenderHandlerAdapter implements CefRenderHandler { @Override - public void onCursorChange(CefBrowser browser, int cursorIdentifer) { - return; + public Rectangle getViewRect(CefBrowser browser) { + return new Rectangle(0, 0, 0, 0); } @Override - public Rectangle getViewRect(CefBrowser browser) { - return new Rectangle(0, 0, 0, 0); + public boolean getScreenInfo(CefBrowser browser, CefScreenInfo screenInfo) { + return false; } @Override @@ -48,6 +48,11 @@ public abstract class CefRenderHandlerAdapter implements CefRenderHandler { ByteBuffer buffer, int width, int height) {} @Override + public boolean onCursorChange(CefBrowser browser, int cursorType) { + return false; + } + + @Override public boolean startDragging(CefBrowser browser, CefDragData dragData, int mask, int x, int y) { return false; } diff --git a/java/org/cef/handler/CefRequestHandler.java b/java/org/cef/handler/CefRequestHandler.java index a7917c6..3378981 100644 --- a/java/org/cef/handler/CefRequestHandler.java +++ b/java/org/cef/handler/CefRequestHandler.java @@ -48,6 +48,23 @@ public interface CefRequestHandler { boolean user_gesture, boolean is_redirect); /** + * Called on the UI thread before OnBeforeBrowse in certain limited cases + * where navigating a new or different browser might be desirable. This + * includes user-initiated navigation that might open in a special way (e.g. + * links clicked via middle-click or ctrl + left-click) and certain types of + * cross-origin navigation initiated from the renderer process (e.g. + * navigating the top-level frame to/from a file URL). + * + * @param browser The corresponding browser. + * @param frame The frame generating the event. Instance only valid within the scope of this + * method + * @param user_gesture True if the request was initiated by a user gesture. + * @return True to cancel navigation or false to continue + */ + boolean onOpenURLFromTab(CefBrowser browser, CefFrame frame, String target_url, + boolean user_gesture); + + /** * Called on the IO thread before a resource request is initiated. The |browser| and |frame| * values represent the source of the request. If this callback returns null the same method * will be called on the associated CefRequestContextHandler, if any. diff --git a/java/org/cef/handler/CefRequestHandlerAdapter.java b/java/org/cef/handler/CefRequestHandlerAdapter.java index baa8e6e..a5231d0 100644 --- a/java/org/cef/handler/CefRequestHandlerAdapter.java +++ b/java/org/cef/handler/CefRequestHandlerAdapter.java @@ -26,6 +26,12 @@ public abstract class CefRequestHandlerAdapter implements CefRequestHandler { } @Override + public boolean onOpenURLFromTab(CefBrowser browser, CefFrame frame, String target_url, + boolean user_gesture) { + return false; + } + + @Override public CefResourceRequestHandler getResourceRequestHandler(CefBrowser browser, CefFrame frame, CefRequest request, boolean isNavigation, boolean isDownload, String requestInitiator, BoolRef disableDefaultHandling) { diff --git a/java/org/cef/handler/CefScreenInfo.java b/java/org/cef/handler/CefScreenInfo.java new file mode 100644 index 0000000..8a8cd4a --- /dev/null +++ b/java/org/cef/handler/CefScreenInfo.java @@ -0,0 +1,36 @@ +// 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. + +package org.cef.handler; + +import java.awt.Rectangle; + +/** + * + * @author shannah + */ +public class CefScreenInfo { + public double device_scale_factor; + public int depth; + public int depth_per_component; + public boolean is_monochrome; + public int x, y, width, height; + public int available_x, available_y, available_width, available_height; + + public void Set(double device_scale_factor, int depth, int depth_per_component, + boolean is_monochrome, Rectangle rect, Rectangle availableRect) { + this.device_scale_factor = device_scale_factor; + this.depth = depth; + this.depth_per_component = depth_per_component; + this.is_monochrome = is_monochrome; + this.x = rect.x; + this.y = rect.y; + this.width = rect.width; + this.height = rect.height; + this.available_x = availableRect.x; + this.available_y = availableRect.y; + this.available_width = availableRect.width; + this.available_height = availableRect.height; + } +} diff --git a/java_tests/tests/detailed/MainFrame.java b/java_tests/tests/detailed/MainFrame.java index d01c7a1..06e1237 100644 --- a/java_tests/tests/detailed/MainFrame.java +++ b/java_tests/tests/detailed/MainFrame.java @@ -83,9 +83,14 @@ public class MainFrame extends BrowserFrame { private ControlPanel control_pane_; private StatusPanel status_panel_; private boolean browserFocus_ = true; + private boolean osr_enabled_; + private boolean transparent_painting_enabled_; public MainFrame(boolean osrEnabled, boolean transparentPaintingEnabled, boolean createImmediately, String[] args) { + this.osr_enabled_ = osrEnabled; + this.transparent_painting_enabled_ = transparentPaintingEnabled; + CefApp myApp; if (CefApp.getState() != CefApp.CefAppState.INITIALIZED) { JCefAppConfig config = JCefAppConfig.getInstance(); @@ -248,7 +253,7 @@ public class MainFrame extends BrowserFrame { menuBar.addBookmark("Binding Test", "client://tests/binding_test.html"); menuBar.addBookmark("Binding Test 2", "client://tests/binding_test2.html"); - menuBar.addBookmark("Download Test", "http://opensource.spotify.com/cefbuilds/index.html"); + menuBar.addBookmark("Download Test", "https://cef-builds.spotifycdn.com/index.html"); menuBar.addBookmark("Login Test (username:pumpkin, password:pie)", "http://www.colostate.edu/~ric/protect/your.html"); menuBar.addBookmark("Certificate-error Test", "https://www.k2go.de"); @@ -285,4 +290,12 @@ public class MainFrame extends BrowserFrame { contentPanel.add(status_panel_, BorderLayout.SOUTH); return contentPanel; } + + public boolean isOsrEnabled() { + return osr_enabled_; + } + + public boolean isTransparentPaintingEnabled() { + return transparent_painting_enabled_; + } } diff --git a/java_tests/tests/detailed/handler/RequestHandler.java b/java_tests/tests/detailed/handler/RequestHandler.java index 7ebd3c7..45ee1e6 100644 --- a/java_tests/tests/detailed/handler/RequestHandler.java +++ b/java_tests/tests/detailed/handler/RequestHandler.java @@ -66,6 +66,12 @@ public class RequestHandler extends CefResourceRequestHandlerAdapter implements } @Override + public boolean onOpenURLFromTab(CefBrowser browser, CefFrame frame, String target_url, + boolean user_gesture) { + return false; + } + + @Override public CefResourceRequestHandler getResourceRequestHandler(CefBrowser browser, CefFrame frame, CefRequest request, boolean isNavigation, boolean isDownload, String requestInitiator, BoolRef disableDefaultHandling) { diff --git a/java_tests/tests/detailed/ui/MenuBar.java b/java_tests/tests/detailed/ui/MenuBar.java index b9d39d9..f92741a 100644 --- a/java_tests/tests/detailed/ui/MenuBar.java +++ b/java_tests/tests/detailed/ui/MenuBar.java @@ -19,6 +19,8 @@ import org.cef.network.CefRequest; import java.awt.BorderLayout; import java.awt.Component; 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; @@ -26,15 +28,21 @@ 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; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.util.Vector; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; +import javax.swing.JLabel; import javax.swing.JLayeredPane; import javax.swing.JMenu; import javax.swing.JMenuBar; @@ -71,7 +79,7 @@ public class MenuBar extends JMenuBar { } } - private final BrowserFrame owner_; + private final MainFrame owner_; private final CefBrowser browser_; private String last_selected_file_ = ""; private final JMenu bookmarkMenu_; @@ -80,7 +88,7 @@ public class MenuBar extends JMenuBar { private final CefCookieManager cookieManager_; private boolean reparentPending_ = false; - public MenuBar(BrowserFrame owner, CefBrowser browser, ControlPanel control_pane, + public MenuBar(MainFrame owner, CefBrowser browser, ControlPanel control_pane, DownloadDialog downloadDialog, CefCookieManager cookieManager) { owner_ = owner; browser_ = browser; @@ -457,6 +465,64 @@ public class MenuBar extends JMenuBar { }); testMenu.add(newwindow); + JMenuItem screenshotSync = new JMenuItem("Screenshot (on AWT thread, native res)"); + screenshotSync.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + long start = System.nanoTime(); + CompletableFuture<BufferedImage> shot = browser.createScreenshot(true); + System.out.println("Took screenshot from the AWT event thread in " + + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start) + " msecs"); + try { + displayScreenshot(shot.get()); + } catch (InterruptedException | ExecutionException exc) { + // cannot happen, future is already resolved in this case + } + } + }); + screenshotSync.setEnabled(owner.isOsrEnabled()); + testMenu.add(screenshotSync); + + JMenuItem screenshotSyncScaled = new JMenuItem("Screenshot (on AWT thread, scaled)"); + screenshotSyncScaled.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + long start = System.nanoTime(); + CompletableFuture<BufferedImage> shot = browser.createScreenshot(false); + System.out.println("Took screenshot from the AWT event thread in " + + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start) + " msecs"); + try { + displayScreenshot(shot.get()); + } catch (InterruptedException | ExecutionException exc) { + // cannot happen, future is already resolved in this case + } + } + }); + screenshotSyncScaled.setEnabled(owner.isOsrEnabled()); + testMenu.add(screenshotSyncScaled); + + JMenuItem screenshotAsync = new JMenuItem("Screenshot (from other thread, scaled)"); + screenshotAsync.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + long start = System.nanoTime(); + CompletableFuture<BufferedImage> shot = browser.createScreenshot(false); + shot.thenAccept((image) -> { + System.out.println("Took screenshot asynchronously in " + + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start) + + " msecs"); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + displayScreenshot(image); + } + }); + }); + } + }); + screenshotAsync.setEnabled(owner.isOsrEnabled()); + testMenu.add(screenshotAsync); + add(fileMenu); add(bookmarkMenu_); add(testMenu); @@ -489,6 +555,18 @@ public class MenuBar extends JMenuBar { validate(); } + private void displayScreenshot(BufferedImage aScreenshot) { + JFrame frame = new JFrame("Screenshot"); + ImageIcon image = new ImageIcon(); + image.setImage(aScreenshot); + frame.setLayout(new FlowLayout()); + JLabel label = new JLabel(image); + label.setPreferredSize(new Dimension(aScreenshot.getWidth(), aScreenshot.getHeight())); + frame.add(label); + frame.setVisible(true); + frame.pack(); + } + public void addBookmarkSeparator() { bookmarkMenu_.addSeparator(); } diff --git a/java_tests/tests/junittests/TestFrame.java b/java_tests/tests/junittests/TestFrame.java index c643280..6fc30f8 100644 --- a/java_tests/tests/junittests/TestFrame.java +++ b/java_tests/tests/junittests/TestFrame.java @@ -223,6 +223,12 @@ class TestFrame extends JFrame implements CefLifeSpanHandler, CefLoadHandler, Ce } @Override + public boolean onOpenURLFromTab(CefBrowser browser, CefFrame frame, String target_url, + boolean user_gesture) { + return false; + } + + @Override public CefResourceRequestHandler getResourceRequestHandler(CefBrowser browser, CefFrame frame, CefRequest request, boolean isNavigation, boolean isDownload, String requestInitiator, BoolRef disableDefaultHandling) { diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index b7eb604..a35a2d4 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -155,7 +155,7 @@ set(JCEF_SRCS_LINUX util_linux.cpp util_posix.cpp ) -set(JCEF_SRCS_MACOSX +set(JCEF_SRCS_MAC critical_wait_posix.cpp signal_restore_posix.cpp signal_restore_posix.h @@ -184,7 +184,7 @@ set(JCEF_HELPER_SRCS set(JCEF_HELPER_SRCS_LINUX util_posix.cpp ) -set(JCEF_HELPER_SRCS_MACOSX +set(JCEF_HELPER_SRCS_MAC util_posix.cpp ) set(JCEF_HELPER_SRCS_WINDOWS @@ -201,7 +201,7 @@ source_group(jcef FILES ${JCEF_HELPER_SRCS}) # Target binary names. set(JCEF_TARGET "jcef") -if(OS_MACOSX) +if(OS_MAC) set(JCEF_APP_NAME "jcef_app") set(JCEF_HELPER_TARGET "jcef_Helper") set(JCEF_HELPER_OUTPUT_NAME "jcef Helper") @@ -285,7 +285,7 @@ endif() # Mac OS X configuration. # -if(OS_MACOSX) +if(OS_MAC) # Avoid CMP0042 policy errors. set(CMAKE_MACOSX_RPATH 1) diff --git a/native/CefBrowser_N.cpp b/native/CefBrowser_N.cpp index 598fe5b..6cc289b 100644 --- a/native/CefBrowser_N.cpp +++ b/native/CefBrowser_N.cpp @@ -9,6 +9,7 @@ #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 "jni_util.h" @@ -890,7 +891,7 @@ int GetMacKeyCodeFromChar(int key_char) { #endif // defined(OS_MACOSX) struct JNIObjectsForCreate { - public: + public: ScopedJNIObjectGlobal jbrowser; ScopedJNIObjectGlobal jparentBrowser; ScopedJNIObjectGlobal jclientHandler; @@ -899,28 +900,29 @@ struct JNIObjectsForCreate { ScopedJNIObjectGlobal jcontext; ScopedJNIObjectGlobal jinspectAt; - JNIObjectsForCreate( - JNIEnv* env, - jobject _jbrowser, - jobject _jparentBrowser, - jobject _jclientHandler, - jstring _url, - jobject _canvas, - jobject _jcontext, - jobject _jinspectAt) : - - jbrowser(env, _jbrowser), - jparentBrowser(env, _jparentBrowser), - jclientHandler(env, _jclientHandler), - url(env, _url), - canvas(env, _canvas), - jcontext(env, _jcontext), - jinspectAt(env, _jinspectAt) - {} + JNIObjectsForCreate(JNIEnv* env, + jobject _jbrowser, + jobject _jparentBrowser, + jobject _jclientHandler, + jstring _url, + jobject _canvas, + jobject _jcontext, + jobject _jinspectAt) + : + + jbrowser(env, _jbrowser), + jparentBrowser(env, _jparentBrowser), + jclientHandler(env, _jclientHandler), + url(env, _url), + canvas(env, _canvas), + jcontext(env, _jcontext), + jinspectAt(env, _jinspectAt) {} }; -void create(std::shared_ptr<JNIObjectsForCreate> objs, jlong windowHandle, jboolean osr, jboolean transparent) -{ +void create(std::shared_ptr<JNIObjectsForCreate> objs, + jlong windowHandle, + jboolean osr, + jboolean transparent) { ScopedJNIEnv env; CefRefPtr<ClientHandler> clientHandler = GetCefFromJNIObject<ClientHandler>( env, objs->jclientHandler, "CefClientHandler"); @@ -1007,8 +1009,16 @@ void create(std::shared_ptr<JNIObjectsForCreate> objs, jlong windowHandle, jbool return; } - bool result = CefBrowserHost::CreateBrowser(windowInfo, clientHandler.get(), - strUrl, settings, NULL, context); + CefRefPtr<CefDictionaryValue> extra_info; + auto router_configs = BrowserProcessHandler::GetMessageRouterConfigs(); + if (router_configs) { + // Send the message router config to CefHelperApp::OnBrowserCreated. + extra_info = CefDictionaryValue::Create(); + extra_info->SetList("router_configs", router_configs); + } + + bool result = CefBrowserHost::CreateBrowser( + windowInfo, clientHandler.get(), strUrl, settings, extra_info, context); if (!result) { lifeSpanHandler->unregisterJBrowser(globalRef); env->DeleteGlobalRef(globalRef); @@ -1141,15 +1151,16 @@ Java_org_cef_browser_CefBrowser_1N_N_1CreateBrowser(JNIEnv* env, jboolean osr, jboolean transparent, jobject canvas, - jobject jcontext) -{ - std::shared_ptr<JNIObjectsForCreate> objs(new JNIObjectsForCreate(env, jbrowser, nullptr, jclientHandler, url, canvas, jcontext, nullptr)); + jobject jcontext) { + std::shared_ptr<JNIObjectsForCreate> objs(new JNIObjectsForCreate( + env, jbrowser, nullptr, jclientHandler, url, canvas, jcontext, nullptr)); if (CefCurrentlyOn(TID_UI)) { create(objs, windowHandle, osr, transparent); } else { - CefPostTask(TID_UI, base::Bind(&create, objs, windowHandle, osr, transparent)); + CefPostTask(TID_UI, + base::Bind(&create, objs, windowHandle, osr, transparent)); } - return JNI_FALSE; // set asynchronously + return JNI_FALSE; // set asynchronously } JNIEXPORT jboolean JNICALL @@ -1161,15 +1172,17 @@ Java_org_cef_browser_CefBrowser_1N_N_1CreateDevTools(JNIEnv* env, jboolean osr, jboolean transparent, jobject canvas, - jobject inspect) -{ - std::shared_ptr<JNIObjectsForCreate> objs(new JNIObjectsForCreate(env, jbrowser, jparent, jclientHandler, nullptr, canvas, nullptr, inspect)); + jobject inspect) { + std::shared_ptr<JNIObjectsForCreate> objs( + new JNIObjectsForCreate(env, jbrowser, jparent, jclientHandler, nullptr, + canvas, nullptr, inspect)); if (CefCurrentlyOn(TID_UI)) { create(objs, windowHandle, osr, transparent); } else { - CefPostTask(TID_UI, base::Bind(&create, objs, windowHandle, osr, transparent)); + CefPostTask(TID_UI, + base::Bind(&create, objs, windowHandle, osr, transparent)); } - return JNI_FALSE; // set asynchronously + return JNI_FALSE; // set asynchronously } JNIEXPORT jlong JNICALL diff --git a/native/CefFrame_N.cpp b/native/CefFrame_N.cpp index cede5f2..f9ca4c1 100644 --- a/native/CefFrame_N.cpp +++ b/native/CefFrame_N.cpp @@ -118,41 +118,69 @@ Java_org_cef_browser_CefFrame_1N_N_1ExecuteJavaScript(JNIEnv* env, JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1Undo(JNIEnv* env, jobject obj, jlong self) { - GetSelf(self)->Undo(); + CefRefPtr<CefFrame> frame = GetSelf(self); + if (!frame) + return; + + frame->Undo(); } JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1Redo(JNIEnv* env, jobject obj, jlong self) { - GetSelf(self)->Redo(); + CefRefPtr<CefFrame> frame = GetSelf(self); + if (!frame) + return; + + frame->Redo(); } JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1Cut(JNIEnv* env, jobject obj, jlong self) { - GetSelf(self)->Cut(); + CefRefPtr<CefFrame> frame = GetSelf(self); + if (!frame) + return; + + frame->Cut(); } JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1Copy(JNIEnv* env, jobject obj, jlong self) { - GetSelf(self)->Copy(); + CefRefPtr<CefFrame> frame = GetSelf(self); + if (!frame) + return; + + frame->Copy(); } JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1Paste(JNIEnv* env, jobject obj, jlong self) { - GetSelf(self)->Paste(); + CefRefPtr<CefFrame> frame = GetSelf(self); + if (!frame) + return; + + frame->Paste(); } JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1Delete(JNIEnv* env, jobject obj, jlong self) { - GetSelf(self)->Delete(); + CefRefPtr<CefFrame> frame = GetSelf(self); + if (!frame) + return; + + frame->Delete(); } JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1SelectAll(JNIEnv* env, jobject obj, jlong self) { - GetSelf(self)->SelectAll(); + CefRefPtr<CefFrame> frame = GetSelf(self); + if (!frame) + return; + + frame->SelectAll(); } diff --git a/native/CefFrame_N.h b/native/CefFrame_N.h index cdf0e4c..b28bfdc 100644 --- a/native/CefFrame_N.h +++ b/native/CefFrame_N.h @@ -153,6 +153,51 @@ JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1SelectAll(JNIEnv*, jobject, jlong); +/* + * Class: org_cef_browser_CefFrame_N + * Method: N_Undo + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1Undo(JNIEnv*, + jobject, + jlong); + +/* + * Class: org_cef_browser_CefFrame_N + * Method: N_Redo + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1Redo(JNIEnv*, + jobject, + jlong); + +/* + * Class: org_cef_browser_CefFrame_N + * Method: N_Cut + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1Cut(JNIEnv*, + jobject, + jlong); + +/* + * Class: org_cef_browser_CefFrame_N + * Method: N_Copy + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1Copy(JNIEnv*, + jobject, + jlong); + +/* + * Class: org_cef_browser_CefFrame_N + * Method: N_Paste + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_cef_browser_CefFrame_1N_N_1Paste(JNIEnv*, + jobject, + jlong); + #ifdef __cplusplus } #endif diff --git a/native/browser_process_handler.cpp b/native/browser_process_handler.cpp index c310c08..cc0d48a 100644 --- a/native/browser_process_handler.cpp +++ b/native/browser_process_handler.cpp @@ -38,22 +38,6 @@ void BrowserProcessHandler::OnContextInitialized() { JNI_CALL_VOID_METHOD(env, handle_, "onContextInitialized", "()V"); } -void BrowserProcessHandler::OnRenderProcessThreadCreated( - CefRefPtr<CefListValue> extra_info) { - int idx = 0; - static std::set<CefMessageRouterConfig, cmpCfg>::iterator iter; - - // Delegate creation of the renderer-side router for query handling. - base::AutoLock lock_scope(router_cfg_lock_); - for (iter = router_cfg_.begin(); iter != router_cfg_.end(); ++iter) { - CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create(); - dict->SetString("js_query_function", iter->js_query_function); - dict->SetString("js_cancel_function", iter->js_cancel_function); - extra_info->SetDictionary(idx, dict); - idx++; - } -} - CefRefPtr<CefPrintHandler> BrowserProcessHandler::GetPrintHandler() { CefRefPtr<CefPrintHandler> result; ScopedJNIEnv env; @@ -85,12 +69,36 @@ void BrowserProcessHandler::OnScheduleMessagePumpWork(int64 delay_ms) { delay_ms); } +// static +CefRefPtr<CefListValue> BrowserProcessHandler::GetMessageRouterConfigs() { + int idx = 0; + static std::set<CefMessageRouterConfig, cmpCfg>::iterator iter; + + base::AutoLock lock_scope(router_cfg_lock_); + if (router_cfg_.empty()) + return nullptr; + + // Configuration pased to CefHelperApp::OnBrowserCreated. + auto router_configs = CefListValue::Create(); + for (iter = router_cfg_.begin(); iter != router_cfg_.end(); ++iter) { + CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create(); + dict->SetString("js_query_function", iter->js_query_function); + dict->SetString("js_cancel_function", iter->js_cancel_function); + router_configs->SetDictionary(idx, dict); + idx++; + } + + return router_configs; +} + +// static void BrowserProcessHandler::AddMessageRouterConfig( const CefMessageRouterConfig& cfg) { base::AutoLock lock_scope(router_cfg_lock_); router_cfg_.insert(cfg); } +// static void BrowserProcessHandler::RemoveMessageRouterConfig( const CefMessageRouterConfig& cfg) { base::AutoLock lock_scope(router_cfg_lock_); diff --git a/native/browser_process_handler.h b/native/browser_process_handler.h index 608caad..532f38d 100644 --- a/native/browser_process_handler.h +++ b/native/browser_process_handler.h @@ -33,11 +33,10 @@ class BrowserProcessHandler : public CefBrowserProcessHandler { virtual ~BrowserProcessHandler(); void OnContextInitialized() OVERRIDE; - void OnRenderProcessThreadCreated( - CefRefPtr<CefListValue> extra_info) OVERRIDE; CefRefPtr<CefPrintHandler> GetPrintHandler() OVERRIDE; void OnScheduleMessagePumpWork(int64 delay_ms) OVERRIDE; + static CefRefPtr<CefListValue> GetMessageRouterConfigs(); static void AddMessageRouterConfig(const CefMessageRouterConfig& cfg); static void RemoveMessageRouterConfig(const CefMessageRouterConfig& cfg); diff --git a/native/display_handler.cpp b/native/display_handler.cpp index 1da0415..10d7c68 100644 --- a/native/display_handler.cpp +++ b/native/display_handler.cpp @@ -6,6 +6,66 @@ #include "jni_util.h" +namespace { + +int GetCursorId(cef_cursor_type_t type) { + ScopedJNIEnv env; + if (!env) + return 0; + + ScopedJNIClass cls(env, "java/awt/Cursor"); + if (!cls) + return 0; + + JNI_STATIC_DEFINE_INT_RV(env, cls, CROSSHAIR_CURSOR, 0); + JNI_STATIC_DEFINE_INT_RV(env, cls, DEFAULT_CURSOR, 0); + JNI_STATIC_DEFINE_INT_RV(env, cls, E_RESIZE_CURSOR, 0); + JNI_STATIC_DEFINE_INT_RV(env, cls, HAND_CURSOR, 0); + JNI_STATIC_DEFINE_INT_RV(env, cls, MOVE_CURSOR, 0); + JNI_STATIC_DEFINE_INT_RV(env, cls, N_RESIZE_CURSOR, 0); + JNI_STATIC_DEFINE_INT_RV(env, cls, NE_RESIZE_CURSOR, 0); + JNI_STATIC_DEFINE_INT_RV(env, cls, NW_RESIZE_CURSOR, 0); + JNI_STATIC_DEFINE_INT_RV(env, cls, S_RESIZE_CURSOR, 0); + JNI_STATIC_DEFINE_INT_RV(env, cls, SE_RESIZE_CURSOR, 0); + JNI_STATIC_DEFINE_INT_RV(env, cls, SW_RESIZE_CURSOR, 0); + JNI_STATIC_DEFINE_INT_RV(env, cls, TEXT_CURSOR, 0); + JNI_STATIC_DEFINE_INT_RV(env, cls, W_RESIZE_CURSOR, 0); + JNI_STATIC_DEFINE_INT_RV(env, cls, WAIT_CURSOR, 0); + + switch (type) { + case CT_CROSS: + return JNI_STATIC(CROSSHAIR_CURSOR); + case CT_HAND: + return JNI_STATIC(HAND_CURSOR); + case CT_IBEAM: + return JNI_STATIC(TEXT_CURSOR); + case CT_WAIT: + return JNI_STATIC(WAIT_CURSOR); + case CT_EASTRESIZE: + return JNI_STATIC(E_RESIZE_CURSOR); + case CT_NORTHRESIZE: + return JNI_STATIC(N_RESIZE_CURSOR); + case CT_NORTHEASTRESIZE: + return JNI_STATIC(NE_RESIZE_CURSOR); + case CT_NORTHWESTRESIZE: + return JNI_STATIC(NW_RESIZE_CURSOR); + case CT_SOUTHRESIZE: + return JNI_STATIC(S_RESIZE_CURSOR); + case CT_SOUTHEASTRESIZE: + return JNI_STATIC(SE_RESIZE_CURSOR); + case CT_SOUTHWESTRESIZE: + return JNI_STATIC(SW_RESIZE_CURSOR); + case CT_WESTRESIZE: + return JNI_STATIC(W_RESIZE_CURSOR); + case CT_MOVE: + return JNI_STATIC(MOVE_CURSOR); + default: + return JNI_STATIC(DEFAULT_CURSOR); + } +} + +} // namespace + DisplayHandler::DisplayHandler(JNIEnv* env, jobject handler) : handle_(env, handler) {} @@ -109,3 +169,23 @@ bool DisplayHandler::OnConsoleMessage(CefRefPtr<CefBrowser> browser, return (jreturn != JNI_FALSE); } + +// TODO(JCEF): Expose all parameters. +bool DisplayHandler::OnCursorChange(CefRefPtr<CefBrowser> browser, + CefCursorHandle cursor, + cef_cursor_type_t type, + const CefCursorInfo& custom_cursor_info) { + ScopedJNIEnv env; + if (!env) + return false; + + ScopedJNIBrowser jbrowser(env, browser); + const int cursorId = GetCursorId(type); + jboolean jreturn = JNI_FALSE; + + JNI_CALL_METHOD(env, handle_, "onCursorChange", + "(Lorg/cef/browser/CefBrowser;I)Z", Boolean, jreturn, + jbrowser.get(), cursorId); + + return (jreturn != JNI_FALSE); +} diff --git a/native/display_handler.h b/native/display_handler.h index 96d71b4..e470479 100644 --- a/native/display_handler.h +++ b/native/display_handler.h @@ -31,6 +31,10 @@ class DisplayHandler : public CefDisplayHandler { const CefString& message, const CefString& source, int line) OVERRIDE; + bool OnCursorChange(CefRefPtr<CefBrowser> browser, + CefCursorHandle cursor, + cef_cursor_type_t type, + const CefCursorInfo& custom_cursor_info) OVERRIDE; protected: ScopedJNIObjectGlobal handle_; diff --git a/native/jcef_helper.cpp b/native/jcef_helper.cpp index 3c8adef..5d32fd1 100644 --- a/native/jcef_helper.cpp +++ b/native/jcef_helper.cpp @@ -39,7 +39,7 @@ class CefHelperApp : public CefApp, public CefRenderProcessHandler { public: CefHelperApp() {} - virtual void OnRegisterCustomSchemes( + void OnRegisterCustomSchemes( CefRawPtr<CefSchemeRegistrar> registrar) OVERRIDE { std::fstream fStream; std::string fName = util::GetTempFileName("scheme", true); @@ -64,24 +64,29 @@ class CefHelperApp : public CefApp, public CefRenderProcessHandler { return this; } - virtual void OnRenderThreadCreated( - CefRefPtr<CefListValue> extra_info) OVERRIDE { - for (size_t idx = 0; idx < extra_info->GetSize(); idx++) { - CefRefPtr<CefDictionaryValue> dict = extra_info->GetDictionary((int)idx); - // Create the renderer-side router for query handling. - CefMessageRouterConfig config; - config.js_query_function = dict->GetString("js_query_function"); - config.js_cancel_function = dict->GetString("js_cancel_function"); - - CefRefPtr<CefMessageRouterRendererSide> router = - CefMessageRouterRendererSide::Create(config); - message_router_.insert(std::make_pair(config, router)); + void OnBrowserCreated(CefRefPtr<CefBrowser> browser, + CefRefPtr<CefDictionaryValue> extra_info) OVERRIDE { + auto router_configs = extra_info->GetList("router_configs"); + if (router_configs) { + // Configuration from BrowserProcessHandler::GetMessageRouterConfigs. + for (size_t idx = 0; idx < router_configs->GetSize(); idx++) { + CefRefPtr<CefDictionaryValue> dict = + router_configs->GetDictionary((int)idx); + // Create the renderer-side router for query handling. + CefMessageRouterConfig config; + config.js_query_function = dict->GetString("js_query_function"); + config.js_cancel_function = dict->GetString("js_cancel_function"); + + CefRefPtr<CefMessageRouterRendererSide> router = + CefMessageRouterRendererSide::Create(config); + message_router_.insert(std::make_pair(config, router)); + } } } - virtual void OnContextCreated(CefRefPtr<CefBrowser> browser, - CefRefPtr<CefFrame> frame, - CefRefPtr<CefV8Context> context) OVERRIDE { + void OnContextCreated(CefRefPtr<CefBrowser> browser, + CefRefPtr<CefFrame> frame, + CefRefPtr<CefV8Context> context) OVERRIDE { std::map<CefMessageRouterConfig, CefRefPtr<CefMessageRouterRendererSide>, cmpCfg>::iterator iter; for (iter = message_router_.begin(); iter != message_router_.end(); @@ -90,9 +95,9 @@ class CefHelperApp : public CefApp, public CefRenderProcessHandler { } } - virtual void OnContextReleased(CefRefPtr<CefBrowser> browser, - CefRefPtr<CefFrame> frame, - CefRefPtr<CefV8Context> context) OVERRIDE { + void OnContextReleased(CefRefPtr<CefBrowser> browser, + CefRefPtr<CefFrame> frame, + CefRefPtr<CefV8Context> context) OVERRIDE { std::map<CefMessageRouterConfig, CefRefPtr<CefMessageRouterRendererSide>, cmpCfg>::iterator iter; for (iter = message_router_.begin(); iter != message_router_.end(); @@ -101,11 +106,10 @@ class CefHelperApp : public CefApp, public CefRenderProcessHandler { } } - virtual bool OnProcessMessageReceived( - CefRefPtr<CefBrowser> browser, - CefRefPtr<CefFrame> frame, - CefProcessId source_process, - CefRefPtr<CefProcessMessage> message) OVERRIDE { + bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, + CefRefPtr<CefFrame> frame, + CefProcessId source_process, + CefRefPtr<CefProcessMessage> message) OVERRIDE { if (message->GetName() == "AddMessageRouter") { CefRefPtr<CefListValue> args = message->GetArgumentList(); CefMessageRouterConfig config; diff --git a/native/jni_scoped_helpers.h b/native/jni_scoped_helpers.h index 705e1c7..e1423ed 100644 --- a/native/jni_scoped_helpers.h +++ b/native/jni_scoped_helpers.h @@ -882,6 +882,21 @@ class ScopedJNIStringRef : public ScopedJNIBase<jobject> { } \ } +#define JNI_CALL_BOOLEAN_METHOD(out, env, obj, method, sig, ...) \ + { \ + if (env && obj) { \ + ScopedJNIClass _cls(env, env->GetObjectClass(obj)); \ + jmethodID _methodId = env->GetMethodID(_cls, method, sig); \ + if (_methodId != NULL) { \ + out = env->CallBooleanMethod(obj, _methodId, ##__VA_ARGS__); \ + } \ + if (env->ExceptionOccurred()) { \ + env->ExceptionDescribe(); \ + env->ExceptionClear(); \ + } \ + } \ + } + // Set the CEF base object for an existing JNI object. A reference will be // added to the base object. If a previous base object existed a reference // will be removed from that object. diff --git a/native/jni_util.cpp b/native/jni_util.cpp index 5259bb2..85a08cc 100644 --- a/native/jni_util.cpp +++ b/native/jni_util.cpp @@ -874,6 +874,34 @@ bool SetJNIFieldInt(JNIEnv* env, return false; } +bool SetJNIFieldDouble(JNIEnv* env, + jclass cls, + jobject obj, + const char* field_name, + double value) { + jfieldID field = env->GetFieldID(cls, field_name, "D"); + if (field) { + env->SetDoubleField(obj, field, value); + return true; + } + env->ExceptionClear(); + return false; +} + +bool SetJNIFieldBoolean(JNIEnv* env, + jclass cls, + jobject obj, + const char* field_name, + int value) { + jfieldID field = env->GetFieldID(cls, field_name, "Z"); + if (field) { + env->SetBooleanField(obj, field, value == 0 ? 0 : 1); + 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 c838907..34017ab 100644 --- a/native/jni_util.h +++ b/native/jni_util.h @@ -125,6 +125,12 @@ bool GetJNIFieldInt(JNIEnv* env, const char* field_name, int* value); +bool GetJNIFieldDouble(JNIEnv* env, + jclass cls, + jobject obj, + const char* field_name, + double* value); + // Retrieve the long value stored in the |field_name| field of |cls|. bool GetJNIFieldLong(JNIEnv* env, jclass cls, @@ -138,6 +144,16 @@ bool SetJNIFieldInt(JNIEnv* env, jobject obj, const char* field_name, int value); +bool SetJNIFieldDouble(JNIEnv* env, + jclass cls, + jobject obj, + const char* field_name, + double value); +bool SetJNIFieldBoolean(JNIEnv* env, + jclass cls, + jobject obj, + const char* field_name, + int 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 a4ea1a1..6655683 100644 --- a/native/render_handler.cpp +++ b/native/render_handler.cpp @@ -29,6 +29,81 @@ jobject NewJNIRect(JNIEnv* env, const CefRect& rect) { return NULL; } +jobject NewJNIScreenInfo(JNIEnv* env, CefScreenInfo& screenInfo) { + ScopedJNIClass cls(env, "org/cef/handler/CefScreenInfo"); + if (!cls) { + return NULL; + } + + ScopedJNIObjectLocal obj(env, NewJNIObject(env, cls)); + if (!obj) { + return NULL; + } + + if (SetJNIFieldDouble(env, cls, obj, "device_scale_factor", + (double)screenInfo.device_scale_factor) && + SetJNIFieldInt(env, cls, obj, "depth", screenInfo.depth) && + SetJNIFieldInt(env, cls, obj, "depth_per_component", + screenInfo.depth_per_component) && + SetJNIFieldBoolean(env, cls, obj, "is_monochrome", + screenInfo.is_monochrome) && + SetJNIFieldInt(env, cls, obj, "x", screenInfo.rect.x) && + SetJNIFieldInt(env, cls, obj, "y", screenInfo.rect.y) && + SetJNIFieldInt(env, cls, obj, "width", screenInfo.rect.width) && + SetJNIFieldInt(env, cls, obj, "height", screenInfo.rect.height) && + SetJNIFieldInt(env, cls, obj, "available_x", + screenInfo.available_rect.x) && + SetJNIFieldInt(env, cls, obj, "available_y", + screenInfo.available_rect.y) && + SetJNIFieldInt(env, cls, obj, "available_width", + screenInfo.available_rect.width) && + SetJNIFieldInt(env, cls, obj, "available_height", + screenInfo.available_rect.height)) { + return obj.Release(); + } + + return NULL; +} + +bool GetJNIScreenInfo(JNIEnv* env, jobject jScreenInfo, CefScreenInfo& dest) { + ScopedJNIClass cls(env, "org/cef/handler/CefScreenInfo"); + if (!cls) { + return false; + } + + ScopedJNIObjectLocal obj(env, jScreenInfo); + if (!obj) { + return false; + } + double tmp; + if (!GetJNIFieldDouble(env, cls, obj, "device_scale_factor", &tmp)) { + return false; + } + dest.device_scale_factor = (float)tmp; + + if (GetJNIFieldInt(env, cls, obj, "depth", &(dest.depth)) && + GetJNIFieldInt(env, cls, obj, "depth_per_component", + &(dest.depth_per_component)) && + GetJNIFieldBoolean(env, cls, obj, "is_monochrome", + &(dest.is_monochrome)) && + GetJNIFieldInt(env, cls, obj, "x", &(dest.rect.x)) && + GetJNIFieldInt(env, cls, obj, "y", &(dest.rect.y)) && + GetJNIFieldInt(env, cls, obj, "width", &(dest.rect.width)) && + GetJNIFieldInt(env, cls, obj, "height", &(dest.rect.height)) && + GetJNIFieldInt(env, cls, obj, "available_x", &(dest.available_rect.x)) && + GetJNIFieldInt(env, cls, obj, "available_y", &(dest.available_rect.y)) && + GetJNIFieldInt(env, cls, obj, "available_width", + &(dest.available_rect.width)) && + GetJNIFieldInt(env, cls, obj, "available_height", + &(dest.available_rect.height)) + + ) { + return true; + } else { + return false; + } +} + // create a new array of java.awt.Rectangle. jobjectArray NewJNIRectArray(JNIEnv* env, const std::vector<CefRect>& vals) { if (vals.empty()) @@ -67,62 +142,6 @@ jobject NewJNIPoint(JNIEnv* env, int x, int y) { return NULL; } -int GetCursorId(cef_cursor_type_t type) { - ScopedJNIEnv env; - if (!env) - return 0; - - ScopedJNIClass cls(env, "java/awt/Cursor"); - if (!cls) - return 0; - - JNI_STATIC_DEFINE_INT_RV(env, cls, CROSSHAIR_CURSOR, 0); - JNI_STATIC_DEFINE_INT_RV(env, cls, DEFAULT_CURSOR, 0); - JNI_STATIC_DEFINE_INT_RV(env, cls, E_RESIZE_CURSOR, 0); - JNI_STATIC_DEFINE_INT_RV(env, cls, HAND_CURSOR, 0); - JNI_STATIC_DEFINE_INT_RV(env, cls, MOVE_CURSOR, 0); - JNI_STATIC_DEFINE_INT_RV(env, cls, N_RESIZE_CURSOR, 0); - JNI_STATIC_DEFINE_INT_RV(env, cls, NE_RESIZE_CURSOR, 0); - JNI_STATIC_DEFINE_INT_RV(env, cls, NW_RESIZE_CURSOR, 0); - JNI_STATIC_DEFINE_INT_RV(env, cls, S_RESIZE_CURSOR, 0); - JNI_STATIC_DEFINE_INT_RV(env, cls, SE_RESIZE_CURSOR, 0); - JNI_STATIC_DEFINE_INT_RV(env, cls, SW_RESIZE_CURSOR, 0); - JNI_STATIC_DEFINE_INT_RV(env, cls, TEXT_CURSOR, 0); - JNI_STATIC_DEFINE_INT_RV(env, cls, W_RESIZE_CURSOR, 0); - JNI_STATIC_DEFINE_INT_RV(env, cls, WAIT_CURSOR, 0); - - switch (type) { - case CT_CROSS: - return JNI_STATIC(CROSSHAIR_CURSOR); - case CT_HAND: - return JNI_STATIC(HAND_CURSOR); - case CT_IBEAM: - return JNI_STATIC(TEXT_CURSOR); - case CT_WAIT: - return JNI_STATIC(WAIT_CURSOR); - case CT_EASTRESIZE: - return JNI_STATIC(E_RESIZE_CURSOR); - case CT_NORTHRESIZE: - return JNI_STATIC(N_RESIZE_CURSOR); - case CT_NORTHEASTRESIZE: - return JNI_STATIC(NE_RESIZE_CURSOR); - case CT_NORTHWESTRESIZE: - return JNI_STATIC(NW_RESIZE_CURSOR); - case CT_SOUTHRESIZE: - return JNI_STATIC(S_RESIZE_CURSOR); - case CT_SOUTHEASTRESIZE: - return JNI_STATIC(SE_RESIZE_CURSOR); - case CT_SOUTHWESTRESIZE: - return JNI_STATIC(SW_RESIZE_CURSOR); - case CT_WESTRESIZE: - return JNI_STATIC(W_RESIZE_CURSOR); - case CT_MOVE: - return JNI_STATIC(MOVE_CURSOR); - default: - return JNI_STATIC(DEFAULT_CURSOR); - } -} - } // namespace RenderHandler::RenderHandler(JNIEnv* env, jobject handler) @@ -150,6 +169,44 @@ void RenderHandler::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) { } } +/// +// Called to allow the client to fill in the CefScreenInfo object with +// appropriate values. Return true if the |screen_info| structure has been +// modified. +// +// If the screen info rectangle is left empty the rectangle from GetViewRect +// will be used. If the rectangle is still empty or invalid popups may not be +// drawn correctly. +/// +/*--cef()--*/ +bool RenderHandler::GetScreenInfo(CefRefPtr<CefBrowser> browser, + CefScreenInfo& screen_info) { + ScopedJNIEnv env; + if (!env) { + return false; + } + + ScopedJNIObjectLocal jScreenInfo(env, NewJNIScreenInfo(env, screen_info)); + if (!jScreenInfo) { + return false; + } + ScopedJNIBrowser jbrowser(env, browser); + jboolean jresult = 0; + + JNI_CALL_BOOLEAN_METHOD( + jresult, env, jbrowser.get(), "getScreenInfo", + "(Lorg/cef/browser/CefBrowser;Lorg/cef/handler/CefScreenInfo;)Z", + jbrowser.get(), jScreenInfo.get()); + + if (jresult) { + if (GetJNIScreenInfo(env, jScreenInfo.get(), screen_info)) { + return true; + } + } + + return false; +} + bool RenderHandler::GetScreenPoint(CefRefPtr<CefBrowser> browser, int viewX, int viewY, @@ -213,22 +270,6 @@ void RenderHandler::OnPaint(CefRefPtr<CefBrowser> browser, jdirectBuffer.get(), width, height); } -// TODO(JCEF): Expose all parameters. -void RenderHandler::OnCursorChange(CefRefPtr<CefBrowser> browser, - CefCursorHandle cursor, - CursorType type, - const CefCursorInfo& custom_cursor_info) { - ScopedJNIEnv env; - if (!env) - return; - - ScopedJNIBrowser jbrowser(env, browser); - const int cursorId = GetCursorId(type); - JNI_CALL_VOID_METHOD(env, handle_, "onCursorChange", - "(Lorg/cef/browser/CefBrowser;I)V", jbrowser.get(), - cursorId); -} - bool RenderHandler::StartDragging(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDragData> drag_data, DragOperationsMask allowed_ops, diff --git a/native/render_handler.h b/native/render_handler.h index c976c0a..433d6b7 100644 --- a/native/render_handler.h +++ b/native/render_handler.h @@ -22,6 +22,10 @@ class RenderHandler : public CefRenderHandler { CefRect& rect) OVERRIDE; virtual void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) OVERRIDE; + + virtual bool GetScreenInfo(CefRefPtr<CefBrowser> browser, + CefScreenInfo& screen_info) OVERRIDE; + virtual bool GetScreenPoint(CefRefPtr<CefBrowser> browser, int viewX, int viewY, @@ -36,10 +40,6 @@ class RenderHandler : public CefRenderHandler { const void* buffer, int width, int height) OVERRIDE; - virtual void OnCursorChange(CefRefPtr<CefBrowser> browser, - CefCursorHandle cursor, - CursorType type, - const CefCursorInfo& custom_cursor_info) OVERRIDE; virtual bool StartDragging(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDragData> drag_data, DragOperationsMask allowed_ops, diff --git a/native/request_handler.cpp b/native/request_handler.cpp index a03d275..a886338 100644 --- a/native/request_handler.cpp +++ b/native/request_handler.cpp @@ -59,6 +59,30 @@ bool RequestHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser, return (jresult != JNI_FALSE); } +bool RequestHandler::OnOpenURLFromTab(CefRefPtr<CefBrowser> browser, + CefRefPtr<CefFrame> frame, + const CefString& target_url, + WindowOpenDisposition target_disposition, + bool user_gesture) { + ScopedJNIEnv env; + if (!env) + return false; + + ScopedJNIBrowser jbrowser(env, browser); + ScopedJNIFrame jframe(env, frame); + jframe.SetTemporary(); + ScopedJNIString jtargetUrl(env, target_url); + jboolean jresult = JNI_FALSE; + + JNI_CALL_METHOD(env, handle_, "onOpenURLFromTab", + "(Lorg/cef/browser/CefBrowser;Lorg/cef/browser/CefFrame;" + "Ljava/lang/String;Z)Z", + Boolean, jresult, jbrowser.get(), jframe.get(), + jtargetUrl.get(), (user_gesture ? JNI_TRUE : JNI_FALSE)); + + return (jresult != JNI_FALSE); +} + CefRefPtr<CefResourceRequestHandler> RequestHandler::GetResourceRequestHandler( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, diff --git a/native/request_handler.h b/native/request_handler.h index 27d47bd..01c04e6 100644 --- a/native/request_handler.h +++ b/native/request_handler.h @@ -23,6 +23,11 @@ class RequestHandler : public CefRequestHandler { CefRefPtr<CefRequest> request, bool user_gesture, bool is_redirect) OVERRIDE; + bool OnOpenURLFromTab(CefRefPtr<CefBrowser> browser, + CefRefPtr<CefFrame> frame, + const CefString& target_url, + WindowOpenDisposition target_disposition, + bool user_gesture) OVERRIDE; CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, diff --git a/native/resources/jcef-Info.plist b/native/resources/jcef-Info.plist index 782d3bd..b832a2b 100644 --- a/native/resources/jcef-Info.plist +++ b/native/resources/jcef-Info.plist @@ -26,7 +26,7 @@ <key>LSFileQuarantineEnabled</key> <true/> <key>LSMinimumSystemVersion</key> - <string>10.5.0</string> + <string>10.10.0</string> <key>LSUIElement</key> <string>1</string> <key>NSSupportsAutomaticGraphicsSwitching</key> diff --git a/native/util.h b/native/util.h index 09b5938..718e12c 100644 --- a/native/util.h +++ b/native/util.h @@ -17,6 +17,10 @@ #include "include/cef_task.h" #include "critical_wait.h" +#if defined(OS_LINUX) +#include "critical_wait.h" +#endif + #endif // USING_JAVA #if defined(OS_WIN) @@ -110,6 +114,13 @@ void SetParent(CefWindowHandle browserHandle, CriticalWait* waitCond, const base::Closure& callback); +#if defined(OS_LINUX) +void SetParentSync(CefWindowHandle browserHandle, + CefWindowHandle parentHandle, + CriticalWait* waitCond, + const base::Closure& callback); +#endif + // Set the window bounds for |browserHandle|. void SetWindowBounds(CefWindowHandle browserHandle, const CefRect& contentRect); diff --git a/native/util_mac.mm b/native/util_mac.mm index d7ba846..bd721db 100644 --- a/native/util_mac.mm +++ b/native/util_mac.mm @@ -328,7 +328,7 @@ bool g_shutdown_called = false; - (void)dealloc { if (cefBrowser) { - util::DestroyCefBrowser(cefBrowser); // we're on the main thread + util::DestroyCefBrowser(cefBrowser); } [[NSNotificationCenter defaultCenter] removeObserver:self]; cefBrowser = NULL; diff --git a/third_party/appbundler/README.jcef b/third_party/appbundler/README.jcef index 0173837..0067ccc 100644 --- a/third_party/appbundler/README.jcef +++ b/third_party/appbundler/README.jcef @@ -1,7 +1,7 @@ Name: Java Application Bundler Short Name: appbundler URL: https://github.com/TheInfiniteKind/appbundler/ -Version: 1.0 (commit 96d579d8) +Version: 1.0 (commit ad6782ea) License: GPL-2.0 Description: @@ -11,5 +11,7 @@ See the project URL for related documentation. Local Modifications: 1. Clone the repo using Git. -2. Run `ant` from the top-level directory. -3. Copy the resulting /appbundler/bin/appbundler-1.0ea.jar file to this directory. +2. Apply the Apple Silicon support patch from + https://github.com/TheInfiniteKind/appbundler/issues/75 +3. Run `ant` from the top-level directory. +4. Copy the resulting /appbundler/bin/appbundler-1.0ea.jar file to this directory. diff --git a/third_party/appbundler/appbundler-1.0.jar b/third_party/appbundler/appbundler-1.0.jar Binary files differindex 7774aba..777e3ce 100644 --- a/third_party/appbundler/appbundler-1.0.jar +++ b/third_party/appbundler/appbundler-1.0.jar diff --git a/third_party/jogamp/README.jcef b/third_party/jogamp/README.jcef index e74e047..2953576 100644 --- a/third_party/jogamp/README.jcef +++ b/third_party/jogamp/README.jcef @@ -1,12 +1,13 @@ Name: Java™ libraries for 3D Graphics, Multimedia and Processing Short Name: jogamp URL: http://jogamp.org/ -Version: 2.3.2 +Version: jogl-2.4-b1506-20200306, gluegen-2.4-b937-20200306 License: Mixed (see LICENSE.txt files) Description: -This library is used to provide OpenGL bindings. Download -jogamp-all-platforms.7z and copy files from the jar/ directory. +This library is used to provide OpenGL bindings. Download the platform 7z +files from https://jogamp.org/deployment/autobuilds/master/ and extract the +required jar files from the jar/ directory. See http://jogamp.org/wiki/index.php/Downloading_and_installing_JOGL for related documentation. diff --git a/third_party/jogamp/jar/gluegen-rt-natives-linux-i586.jar b/third_party/jogamp/jar/gluegen-rt-natives-linux-i586.jar Binary files differindex 914a259..ac9182c 100644 --- a/third_party/jogamp/jar/gluegen-rt-natives-linux-i586.jar +++ b/third_party/jogamp/jar/gluegen-rt-natives-linux-i586.jar diff --git a/third_party/jogamp/jar/gluegen-rt-natives-windows-i586.jar b/third_party/jogamp/jar/gluegen-rt-natives-windows-i586.jar Binary files differindex 1c393b7..a0c6931 100644 --- a/third_party/jogamp/jar/gluegen-rt-natives-windows-i586.jar +++ b/third_party/jogamp/jar/gluegen-rt-natives-windows-i586.jar diff --git a/third_party/jogamp/jar/jogl-all-natives-linux-i586.jar b/third_party/jogamp/jar/jogl-all-natives-linux-i586.jar Binary files differindex 88a27ce..979fa36 100644 --- a/third_party/jogamp/jar/jogl-all-natives-linux-i586.jar +++ b/third_party/jogamp/jar/jogl-all-natives-linux-i586.jar diff --git a/third_party/jogamp/jar/jogl-all-natives-windows-i586.jar b/third_party/jogamp/jar/jogl-all-natives-windows-i586.jar Binary files differindex 4439f1d..63b5ade 100644 --- a/third_party/jogamp/jar/jogl-all-natives-windows-i586.jar +++ b/third_party/jogamp/jar/jogl-all-natives-windows-i586.jar diff --git a/tools/compile.sh b/tools/compile.sh index c9c2f25..d44a7e2 100755 --- a/tools/compile.sh +++ b/tools/compile.sh @@ -3,28 +3,26 @@ # reserved. Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file. -cd .. - if [ -z "$1" ]; then echo "ERROR: Please specify a target platform: linux32 or linux64" elif [ -z "$2" ]; then echo "ERROR: Please specify a target configuration: Release or Debug" else - export OUT_PATH="./out/$1" - export OUT_NATIVE_PATH="./jcef_build/native/$2" - export CLS_PATH="./third_party/jogamp/jar/*:./third_party/junit/*:./java" + DIR="$( cd "$( dirname "$0" )" && cd .. && pwd )" + export OUT_PATH="${DIR}/out/$1" + export OUT_NATIVE_PATH="${DIR}/jcef_build/native/$2" + JAVA_PATH="${DIR}/java" + export CLS_PATH="${DIR}/third_party/jogamp/jar/*:${DIR}/third_party/junit/*:${JAVA_PATH}" if [ ! -d "$OUT_PATH" ]; then mkdir -p "$OUT_PATH" fi - #$JAVA_HOME/bin/javac -Xdiags:verbose -cp $CLS_PATH -d $OUT_PATH java/tests/detailed/*.java java/tests/junittests/*.java java/tests/simple/*.java java/org/cef/*.java java/org/cef/browser/*.java java/org/cef/callback/*.java java/org/cef/handler/*.java java/org/cef/misc/*.java java/org/cef/network/*.java + #$JAVA_HOME/bin/javac -Xdiags:verbose -cp "$CLS_PATH" -d "$OUT_PATH" "${JAVA_PATH}"/tests/detailed/*.java "${JAVA_PATH}"/tests/junittests/*.java "${JAVA_PATH}"/tests/simple/*.java "${JAVA_PATH}"/org/cef/*.java "${JAVA_PATH}"/org/cef/browser/*.java "${JAVA_PATH}"/org/cef/callback/*.java "${JAVA_PATH}"/org/cef/handler/*.java "${JAVA_PATH}"/org/cef/misc/*.java "${JAVA_PATH}"/org/cef/network/*.java ant -v modular-sdk # Copy resource files. - cp -f ./java/tests/detailed/handler/*.html $OUT_PATH/tests/detailed/handler - cp -f ./java/tests/detailed/handler/*.png $OUT_PATH/tests/detailed/handler + cp -f "${JAVA_PATH}"/tests/detailed/handler/*.html "$OUT_PATH/tests/detailed/handler" + cp -f "${JAVA_PATH}"/tests/detailed/handler/*.png "$OUT_PATH/tests/detailed/handler" fi -cd tools - diff --git a/tools/distrib/linux32/compile.sh b/tools/distrib/linux32/compile.sh index c073b1b..6bee820 100755 --- a/tools/distrib/linux32/compile.sh +++ b/tools/distrib/linux32/compile.sh @@ -3,10 +3,12 @@ # reserved. Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file. +# Determine the absolute path to the current directory. +DIR="$( cd "$( dirname "$0" )" && pwd )" +BIN_DIR="${DIR}/bin" + # Compile the test program. -javac -cp "./bin:./bin/*" ./bin/tests/detailed/*.java ./bin/tests/detailed/dialog/*.java ./bin/tests/detailed/handler/*.java ./bin/tests/detailed/ui/*.java ./bin/tests/simple/*.java +javac -cp "${BIN_DIR}:${BIN_DIR}/*" "${BIN_DIR}"/tests/detailed/*.java "${BIN_DIR}"/tests/detailed/dialog/*.java "${BIN_DIR}"/tests/detailed/handler/*.java "${BIN_DIR}"/tests/detailed/ui/*.java "${BIN_DIR}"/tests/simple/*.java # Create the test JAR file. -cd bin -jar -cf jcef-tests.jar tests/detailed/*.class tests/detailed/dialog/*.class tests/detailed/handler/*.class tests/detailed/ui/*.class tests/simple/*.java -cd ..
\ No newline at end of file +jar -cf "${BIN_DIR}"/jcef-tests.jar -C "${BIN_DIR}" tests diff --git a/tools/distrib/linux32/run.sh b/tools/distrib/linux32/run.sh index 67cfe42..93f7482 100755 --- a/tools/distrib/linux32/run.sh +++ b/tools/distrib/linux32/run.sh @@ -3,16 +3,23 @@ # reserved. Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file. -# Determine the absolute path to the library directory. -export LIB_PATH=$(readlink -f "./bin/lib/linux32") +# Determine the absolute path to the current directory. +DIR="$( cd "$( dirname "$0" )" && pwd )" +LIB_PATH="$DIR/bin/lib/linux32" + +if [ -z "$1" ]; then + EXAMPLE="detailed" +else + EXAMPLE="$1" +fi # Necessary for jcef_helper to find libcef.so. if [ -n "$LD_LIBRARY_PATH" ]; then - LD_LIBRARY_PATH=$LIB_PATH:${LD_LIBRARY_PATH} + LD_LIBRARY_PATH="$LIB_PATH:${LD_LIBRARY_PATH}" else - LD_LIBRARY_PATH=$LIB_PATH + LD_LIBRARY_PATH="$LIB_PATH" fi export LD_LIBRARY_PATH # Preload libcef.so to avoid crashes. -LD_PRELOAD=$LIB_PATH/libcef.so java -cp "./bin:./bin/*" -Djava.library.path=$LIB_PATH tests.detailed.MainFrame "$@" +LD_PRELOAD=libcef.so java -cp "${DIR}/bin:${DIR}/bin/*" -Djava.library.path="$LIB_PATH" tests.${EXAMPLE}.MainFrame "$@" diff --git a/tools/distrib/linux64/compile.sh b/tools/distrib/linux64/compile.sh index c073b1b..6bee820 100755 --- a/tools/distrib/linux64/compile.sh +++ b/tools/distrib/linux64/compile.sh @@ -3,10 +3,12 @@ # reserved. Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file. +# Determine the absolute path to the current directory. +DIR="$( cd "$( dirname "$0" )" && pwd )" +BIN_DIR="${DIR}/bin" + # Compile the test program. -javac -cp "./bin:./bin/*" ./bin/tests/detailed/*.java ./bin/tests/detailed/dialog/*.java ./bin/tests/detailed/handler/*.java ./bin/tests/detailed/ui/*.java ./bin/tests/simple/*.java +javac -cp "${BIN_DIR}:${BIN_DIR}/*" "${BIN_DIR}"/tests/detailed/*.java "${BIN_DIR}"/tests/detailed/dialog/*.java "${BIN_DIR}"/tests/detailed/handler/*.java "${BIN_DIR}"/tests/detailed/ui/*.java "${BIN_DIR}"/tests/simple/*.java # Create the test JAR file. -cd bin -jar -cf jcef-tests.jar tests/detailed/*.class tests/detailed/dialog/*.class tests/detailed/handler/*.class tests/detailed/ui/*.class tests/simple/*.java -cd ..
\ No newline at end of file +jar -cf "${BIN_DIR}"/jcef-tests.jar -C "${BIN_DIR}" tests diff --git a/tools/distrib/linux64/run.sh b/tools/distrib/linux64/run.sh index 2eabf9c..cbb4fd4 100755 --- a/tools/distrib/linux64/run.sh +++ b/tools/distrib/linux64/run.sh @@ -3,16 +3,23 @@ # reserved. Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file. -# Determine the absolute path to the library directory. -export LIB_PATH=$(readlink -f "./bin/lib/linux64") +# Determine the absolute path to the current directory. +DIR="$( cd "$( dirname "$0" )" && pwd )" +LIB_PATH="$DIR/bin/lib/linux64" + +if [ -z "$1" ]; then + EXAMPLE="detailed" +else + EXAMPLE="$1" +fi # Necessary for jcef_helper to find libcef.so. if [ -n "$LD_LIBRARY_PATH" ]; then - LD_LIBRARY_PATH=$LIB_PATH:${LD_LIBRARY_PATH} + LD_LIBRARY_PATH="$LIB_PATH:${LD_LIBRARY_PATH}" else - LD_LIBRARY_PATH=$LIB_PATH + LD_LIBRARY_PATH="$LIB_PATH" fi export LD_LIBRARY_PATH # Preload libcef.so to avoid crashes. -LD_PRELOAD=$LIB_PATH/libcef.so java -cp "./bin:./bin/*" -Djava.library.path=$LIB_PATH tests.detailed.MainFrame "$@" +LD_PRELOAD=libcef.so java -cp "${DIR}/bin:${DIR}/bin/*" -Djava.library.path="$LIB_PATH" tests.${EXAMPLE}.MainFrame "$@" diff --git a/tools/make_all_jni_headers.sh b/tools/make_all_jni_headers.sh index 4b2c87e..5d28cc1 100755 --- a/tools/make_all_jni_headers.sh +++ b/tools/make_all_jni_headers.sh @@ -6,36 +6,37 @@ if [ -z "$1" ]; then echo "ERROR: Please specify a target platform: linux32, linux64 or macosx64" else - ./make_jni_header.sh $1 org.cef.CefApp - ./make_jni_header.sh $1 org.cef.browser.CefBrowser_N - ./make_jni_header.sh $1 org.cef.browser.CefFrame_N - ./make_jni_header.sh $1 org.cef.browser.CefMessageRouter_N - ./make_jni_header.sh $1 org.cef.browser.CefRequestContext_N - ./make_jni_header.sh $1 org.cef.callback.CefAuthCallback_N - ./make_jni_header.sh $1 org.cef.callback.CefBeforeDownloadCallback_N - ./make_jni_header.sh $1 org.cef.callback.CefCommandLine_N - ./make_jni_header.sh $1 org.cef.callback.CefCallback_N - ./make_jni_header.sh $1 org.cef.callback.CefContextMenuParams_N - ./make_jni_header.sh $1 org.cef.callback.CefDownloadItem_N - ./make_jni_header.sh $1 org.cef.callback.CefDownloadItemCallback_N - ./make_jni_header.sh $1 org.cef.callback.CefDragData_N - ./make_jni_header.sh $1 org.cef.callback.CefFileDialogCallback_N - ./make_jni_header.sh $1 org.cef.callback.CefJSDialogCallback_N - ./make_jni_header.sh $1 org.cef.callback.CefMenuModel_N - ./make_jni_header.sh $1 org.cef.callback.CefPrintDialogCallback_N - ./make_jni_header.sh $1 org.cef.callback.CefPrintJobCallback_N - ./make_jni_header.sh $1 org.cef.callback.CefQueryCallback_N - ./make_jni_header.sh $1 org.cef.callback.CefRequestCallback_N - ./make_jni_header.sh $1 org.cef.callback.CefSchemeRegistrar_N - ./make_jni_header.sh $1 org.cef.handler.CefClientHandler - ./make_jni_header.sh $1 org.cef.misc.CefPrintSettings_N - ./make_jni_header.sh $1 org.cef.network.CefCookieManager_N - ./make_jni_header.sh $1 org.cef.network.CefPostData_N - ./make_jni_header.sh $1 org.cef.network.CefPostDataElement_N - ./make_jni_header.sh $1 org.cef.network.CefRequest_N - ./make_jni_header.sh $1 org.cef.network.CefResponse_N - ./make_jni_header.sh $1 org.cef.network.CefURLRequest_N - ./make_jni_header.sh $1 org.cef.network.CefWebPluginInfo_N - ./make_jni_header.sh $1 org.cef.network.CefWebPluginManager_N + DIR="$( cd "$( dirname "$0" )" && pwd )" + "${DIR}"/make_jni_header.sh $1 org.cef.CefApp + "${DIR}"/make_jni_header.sh $1 org.cef.browser.CefBrowser_N + "${DIR}"/make_jni_header.sh $1 org.cef.browser.CefFrame_N + "${DIR}"/make_jni_header.sh $1 org.cef.browser.CefMessageRouter_N + "${DIR}"/make_jni_header.sh $1 org.cef.browser.CefRequestContext_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefAuthCallback_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefBeforeDownloadCallback_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefCommandLine_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefCallback_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefContextMenuParams_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefDownloadItem_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefDownloadItemCallback_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefDragData_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefFileDialogCallback_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefJSDialogCallback_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefMenuModel_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefPrintDialogCallback_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefPrintJobCallback_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefQueryCallback_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefRequestCallback_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefSchemeRegistrar_N + "${DIR}"/make_jni_header.sh $1 org.cef.handler.CefClientHandler + "${DIR}"/make_jni_header.sh $1 org.cef.misc.CefPrintSettings_N + "${DIR}"/make_jni_header.sh $1 org.cef.network.CefCookieManager_N + "${DIR}"/make_jni_header.sh $1 org.cef.network.CefPostData_N + "${DIR}"/make_jni_header.sh $1 org.cef.network.CefPostDataElement_N + "${DIR}"/make_jni_header.sh $1 org.cef.network.CefRequest_N + "${DIR}"/make_jni_header.sh $1 org.cef.network.CefResponse_N + "${DIR}"/make_jni_header.sh $1 org.cef.network.CefURLRequest_N + "${DIR}"/make_jni_header.sh $1 org.cef.network.CefWebPluginInfo_N + "${DIR}"/make_jni_header.sh $1 org.cef.network.CefWebPluginManager_N fi diff --git a/tools/make_distrib.sh b/tools/make_distrib.sh index e532076..1b66aba 100755 --- a/tools/make_distrib.sh +++ b/tools/make_distrib.sh @@ -6,59 +6,56 @@ if [ -z "$1" ]; then echo "ERROR: Please specify a build target: linux32, linux64 or macosx64" else - cd .. - - export DISTRIB_PLATFORM="$1" - export DISTRIB_PATH="./binary_distrib/$1" - export DISTRIB_BIN_PATH="$DISTRIB_PATH/bin" - export DISTRIB_DOCS_PATH="$DISTRIB_PATH/docs" - export OUT_PATH="./out" - export OUT_DOCS_PATH="./out/docs" - export SOURCE_PATH="./java" - export JOGAMP_PATH="./third_party/jogamp" - export TOOLS_DISTRIB_PATH="./tools/distrib/$1" - export EXCLUDE_FILE="./tools/distrib/EXCLUDE_FILES.txt" + DIR="$( cd "$( dirname "$0" )" && cd .. && pwd )" + DISTRIB_PLATFORM="$1" + DISTRIB_PATH="${DIR}/binary_distrib/$1" + DISTRIB_BIN_PATH="$DISTRIB_PATH/bin" + DISTRIB_DOCS_PATH="$DISTRIB_PATH/docs" + OUT_PATH="${DIR}/out" + OUT_DOCS_PATH="${DIR}/out/docs" + SOURCE_PATH="${DIR}/java" + JOGAMP_PATH="${DIR}/third_party/jogamp" + TOOLS_DISTRIB_PATH="${DIR}/tools/distrib/$1" + EXCLUDE_FILE="${DIR}/tools/distrib/EXCLUDE_FILES.txt" if [ ! -d "$DISTRIB_BIN_PATH" ]; then mkdir -p "$DISTRIB_BIN_PATH" fi # Create the JCEF documentation. -# cd tools -# ./make_docs.sh -# cd .. + #"${DIR}"/tools/make_docs.sh # Copy documentation to the docs directory. - cp -rf $OUT_DOCS_PATH $DISTRIB_DOCS_PATH + cp -rf "$OUT_DOCS_PATH" "$DISTRIB_DOCS_PATH" # Create README.txt - python tools/make_readme.py --output-dir $DISTRIB_PATH/ --platform $DISTRIB_PLATFORM + python "${DIR}"/tools/make_readme.py --output-dir "$DISTRIB_PATH/" --platform $DISTRIB_PLATFORM # Copy miscellaneous files to the root directory. - cp -f ./LICENSE.txt $DISTRIB_PATH - cp -f $JOGAMP_PATH/*.LICENSE.txt $DISTRIB_PATH - rsync -a --exclude-from $EXCLUDE_FILE $TOOLS_DISTRIB_PATH/ $DISTRIB_PATH/ + cp -f "${DIR}"/LICENSE.txt "$DISTRIB_PATH" + cp -f "$JOGAMP_PATH"/*.LICENSE.txt "$DISTRIB_PATH" + rsync -a --exclude-from "$EXCLUDE_FILE" "$TOOLS_DISTRIB_PATH/" "$DISTRIB_PATH/" if [ $1 == "macosx64" ]; then - export OUT_BINARY_PATH="./jcef_build/native/Release" + OUT_BINARY_PATH="${DIR}/jcef_build/native/Release" if [ ! -d "$OUT_BINARY_PATH" ]; then echo "ERROR: Native Release build output path does not exist" exit 1 fi # Copy test program source file to the tests directory. - cp -rf $SOURCE_PATH/tests $DISTRIB_PATH + cp -rf "$SOURCE_PATH"/tests "$DISTRIB_PATH" # Everything else is contained in the app bundle. - cp -rf $OUT_BINARY_PATH/jcef_app.app $DISTRIB_BIN_PATH + cp -rf "$OUT_BINARY_PATH"/jcef_app.app ""$DISTRIB_BIN_PATH else - export DISTRIB_LIB_PATH="$DISTRIB_PATH/bin/lib/$1" - export JOGAMP_JAR_PATH="$JOGAMP_PATH/jar" - export OUT_BINARY_PATH="$OUT_PATH/Release" + DISTRIB_LIB_PATH="$DISTRIB_PATH/bin/lib/$1" + JOGAMP_JAR_PATH="$JOGAMP_PATH/jar" + OUT_BINARY_PATH="$OUT_PATH/Release" # Alternately look in the CMake output path. if [ ! -d "$OUT_BINARY_PATH" ]; then - export OUT_BINARY_PATH="./jcef_build/native/Release" + OUT_BINARY_PATH="${DIR}/jcef_build/native/Release" fi if [ ! -d "$OUT_BINARY_PATH" ]; then echo "ERROR: Native Release build output path does not exist" @@ -66,47 +63,42 @@ else fi # Create the JCEF JAR file. - cd tools - ./make_jar.sh $1 - cd .. + "${DIR}"/tools/make_jar.sh $1 # Copy JAR files to the bin directory. - cp -f $JOGAMP_JAR_PATH/gluegen-rt.jar $DISTRIB_BIN_PATH - cp -f $JOGAMP_JAR_PATH/jogl-all.jar $DISTRIB_BIN_PATH + cp -f "$JOGAMP_JAR_PATH"/gluegen-rt.jar "$DISTRIB_BIN_PATH" + cp -f "$JOGAMP_JAR_PATH"/jogl-all.jar "$DISTRIB_BIN_PATH" if [ $1 == "linux32" ]; then - export JOGAMP_JAR_SUFFIX="i586" + JOGAMP_JAR_SUFFIX="i586" else - export JOGAMP_JAR_SUFFIX="amd64" + JOGAMP_JAR_SUFFIX="amd64" fi - cp -f $JOGAMP_JAR_PATH/gluegen-rt-natives-linux-$JOGAMP_JAR_SUFFIX.jar $DISTRIB_BIN_PATH - cp -f $JOGAMP_JAR_PATH/jogl-all-natives-linux-$JOGAMP_JAR_SUFFIX.jar $DISTRIB_BIN_PATH - cp -f $OUT_PATH/$1/jcef.jar $DISTRIB_BIN_PATH + cp -f "$JOGAMP_JAR_PATH"/gluegen-rt-natives-linux-$JOGAMP_JAR_SUFFIX.jar "$DISTRIB_BIN_PATH" + cp -f "$JOGAMP_JAR_PATH"/jogl-all-natives-linux-$JOGAMP_JAR_SUFFIX.jar "$DISTRIB_BIN_PATH" + cp -f "$OUT_PATH"/$1/jcef.jar "$DISTRIB_BIN_PATH" # Copy test program source and JAR file to the bin directory. - cp -rf $SOURCE_PATH/tests $DISTRIB_BIN_PATH - cp -f $OUT_PATH/$1/jcef-tests.jar $DISTRIB_BIN_PATH + cp -rf "$SOURCE_PATH"/tests "$DISTRIB_BIN_PATH" + cp -f "$OUT_PATH"/$1/jcef-tests.jar "$DISTRIB_BIN_PATH" # Copy CEF Release files to the lib directory. if [ ! -d "$DISTRIB_LIB_PATH" ]; then mkdir -p "$DISTRIB_LIB_PATH" fi - cp -f $OUT_BINARY_PATH/chrome-sandbox $DISTRIB_LIB_PATH - cp -f $OUT_BINARY_PATH/libjcef.so $DISTRIB_LIB_PATH - cp -f $OUT_BINARY_PATH/jcef_helper $DISTRIB_LIB_PATH - cp -f $OUT_BINARY_PATH/icudtl.dat $DISTRIB_LIB_PATH - cp -f $OUT_BINARY_PATH/libcef.so $DISTRIB_LIB_PATH - cp -f $OUT_BINARY_PATH/libEGL.so $DISTRIB_LIB_PATH - cp -f $OUT_BINARY_PATH/libGLESv2.so $DISTRIB_LIB_PATH - cp -f $OUT_BINARY_PATH/natives_blob.bin $DISTRIB_LIB_PATH - cp -f $OUT_BINARY_PATH/snapshot_blob.bin $DISTRIB_LIB_PATH - cp -f $OUT_BINARY_PATH/v8_context_snapshot.bin $DISTRIB_LIB_PATH - cp -f $OUT_BINARY_PATH/*.pak $DISTRIB_LIB_PATH - cp -rf $OUT_BINARY_PATH/locales/ $DISTRIB_LIB_PATH - cp -rf $OUT_BINARY_PATH/swiftshader/ $DISTRIB_LIB_PATH + cp -f "$OUT_BINARY_PATH"/chrome-sandbox "$DISTRIB_LIB_PATH" + cp -f "$OUT_BINARY_PATH"/libjcef.so "$DISTRIB_LIB_PATH" + cp -f "$OUT_BINARY_PATH"/jcef_helper "$DISTRIB_LIB_PATH" + cp -f "$OUT_BINARY_PATH"/icudtl.dat "$DISTRIB_LIB_PATH" + cp -f "$OUT_BINARY_PATH"/libcef.so "$DISTRIB_LIB_PATH" + cp -f "$OUT_BINARY_PATH"/libEGL.so "$DISTRIB_LIB_PATH" + cp -f "$OUT_BINARY_PATH"/libGLESv2.so "$DISTRIB_LIB_PATH" + cp -f "$OUT_BINARY_PATH"/snapshot_blob.bin "$DISTRIB_LIB_PATH" + cp -f "$OUT_BINARY_PATH"/v8_context_snapshot.bin "$DISTRIB_LIB_PATH" + cp -f "$OUT_BINARY_PATH"/*.pak "$DISTRIB_LIB_PATH" + cp -rf "$OUT_BINARY_PATH"/locales/ "$DISTRIB_LIB_PATH" + cp -rf "$OUT_BINARY_PATH"/swiftshader/ "$DISTRIB_LIB_PATH" fi - - cd tools fi diff --git a/tools/make_docs.sh b/tools/make_docs.sh index acd6bf7..030aaf0 100755 --- a/tools/make_docs.sh +++ b/tools/make_docs.sh @@ -3,10 +3,9 @@ # reserved. Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file. -cd ../java +DIR="$( cd "$( dirname "$0" )" && cd .. && pwd )" +OUT_PATH="${DIR}/out/docs" -export OUT_PATH="../out/docs" - -$JAVA_HOME/bin/javadoc -Xdoclint:none -windowtitle "CEF3 Java API Docs" -footer "<center><a href="https://bitbucket.org/chromiumembedded/java-cef" target="_top">Chromium Embedded Framework (CEF)</a> Copyright © 2013 Marshall A. Greenblatt</center>" -nodeprecated -d $OUT_PATH -link http://docs.oracle.com/javase/7/docs/api/ -subpackages org.cef +$JAVA_HOME/bin/javadoc -Xdoclint:none -windowtitle "CEF3 Java API Docs" -footer "<center><a href="https://bitbucket.org/chromiumembedded/java-cef" target="_top">Chromium Embedded Framework (CEF)</a> Copyright © 2013 Marshall A. Greenblatt</center>" -nodeprecated -d "$OUT_PATH" -sourcepath "${DIR}/java" -link http://docs.oracle.com/javase/7/docs/api/ -subpackages org.cef cd ../tools diff --git a/tools/make_jar.sh b/tools/make_jar.sh index bcba2fb..1bc2618 100755 --- a/tools/make_jar.sh +++ b/tools/make_jar.sh @@ -6,8 +6,8 @@ if [ -z "$1" ]; then echo "ERROR: Please specify a build target: linux32 or linux64" else - cd ../out/$1 - jar -cf jcef.jar org/cef/*.class org/cef/browser/*.class org/cef/callback/*.class org/cef/handler/*.class org/cef/misc/*.class org/cef/network/*.class - jar -cf jcef-tests.jar tests/detailed/*.class tests/detailed/dialog/*.class tests/detailed/handler/* tests/detailed/ui/*.class - cd ../../tools + DIR="$( cd "$( dirname "$0" )" && cd .. && pwd )" + OUT_DIR="${DIR}/out/$1" + jar -cf "${OUT_DIR}"/jcef.jar -C "${OUT_DIR}" org + jar -cf "${OUT_DIR}"/jcef-tests.jar -C "${OUT_DIR}" tests fi diff --git a/tools/make_jni_header.sh b/tools/make_jni_header.sh index f809344..e59bd44 100755 --- a/tools/make_jni_header.sh +++ b/tools/make_jni_header.sh @@ -3,30 +3,27 @@ # reserved. Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file. -cd .. - if [ -z "$1" ]; then echo "ERROR: Please specify a target platform: linux32, linux64 or macosx64" else if [ -z "$2" ]; then echo "ERROR: Please specify a class name" else + DIR="$( cd "$( dirname "$0" )" && cd .. && pwd )" if [ $1 == "macosx64" ]; then - export CLS_OUT_PATH="./jcef_build/native/Release" + CLS_OUT_PATH="${DIR}/jcef_build/native/Release" if [ ! -d "$CLS_OUT_PATH" ]; then - export CLS_OUT_PATH="./jcef_build/native/Debug" + CLS_OUT_PATH="${DIR}/jcef_build/native/Debug" fi else - export CLS_OUT_PATH="./out/$1" + CLS_OUT_PATH="${DIR}/out/$1" fi - export HEADER_PATH="./native" - export CLS_PATH="./third_party/jogamp/jar/*:${CLS_OUT_PATH}" - export CLS_NAME="${2##*.}" + HEADER_PATH="${DIR}/native" + CLS_PATH="${DIR}/third_party/jogamp/jar/*:${CLS_OUT_PATH}" + CLS_NAME="${2##*.}" - javah -force -classpath $CLS_PATH -o $HEADER_PATH/$CLS_NAME.h $2 + javah -force -classpath "$CLS_PATH" -o "$HEADER_PATH/$CLS_NAME.h" $2 fi fi -cd tools - diff --git a/tools/make_readme.sh b/tools/make_readme.sh index b6f312a..c3d75f4 100755 --- a/tools/make_readme.sh +++ b/tools/make_readme.sh @@ -6,15 +6,12 @@ if [ -z "$1" ]; then echo "ERROR: Please specify a target platform: linux32, linux64 or macosx64" else - cd .. - - export DISTRIB_PATH="./binary_distrib/$1" + DIR="$( cd "$( dirname "$0" )" && cd .. && pwd )" + DISTRIB_PATH="${DIR}/binary_distrib/$1" if [ ! -d "$DISTRIB_PATH" ]; then mkdir -p "$DISTRIB_PATH" fi # Create README.txt - python tools/make_readme.py --output-dir $DISTRIB_PATH/ --platform $1 - - cd tools + python "${DIR}"/tools/make_readme.py --output-dir "$DISTRIB_PATH/" --platform $1 fi diff --git a/tools/run.sh b/tools/run.sh index 66115e4..df7c5d7 100755 --- a/tools/run.sh +++ b/tools/run.sh @@ -3,8 +3,6 @@ # reserved. Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file. -cd .. - if [ -z "$1" ]; then echo "ERROR: Please specify a target platform: linux32 | linux64 | macos" else @@ -13,10 +11,10 @@ else elif [ -z "$3" ]; then echo "ERROR: Please specify a run type: detailed or simple" else - export OUT_PATH="./out/$1" + DIR="$( cd "$( dirname "$0" )" && cd .. && pwd )" + OUT_PATH="${DIR}/out/$1" - #export LIB_PATH=$(readlink -f "./jcef_build/native/$2") - export LIB_PATH=`pwd`/jcef_build/native/$2 + export LIB_PATH="${DIR}/jcef_build/native/$2" if [ ! -d "$LIB_PATH" ]; then echo "ERROR: Native build output path does not exist" exit 1 @@ -26,14 +24,14 @@ else export OUT_PATH=$LIB_PATH fi - export CLS_PATH="./third_party/jogamp/jar/*:$OUT_PATH" + export CLS_PATH="${DIR}/third_party/jogamp/jar/*:$OUT_PATH" export RUN_TYPE="$3" # Necessary for jcef_helper to find libcef.so. if [ -n "$LD_LIBRARY_PATH" ]; then - LD_LIBRARY_PATH=$LIB_PATH:${LD_LIBRARY_PATH} + LD_LIBRARY_PATH="$LIB_PATH:${LD_LIBRARY_PATH}" else - LD_LIBRARY_PATH=$LIB_PATH + LD_LIBRARY_PATH="$LIB_PATH" fi export LD_LIBRARY_PATH @@ -59,6 +57,5 @@ else fi fi -cd tools exit $exit_status diff --git a/tools/run_tests.sh b/tools/run_tests.sh index 2f4aae3..12e3707 100755 --- a/tools/run_tests.sh +++ b/tools/run_tests.sh @@ -3,19 +3,16 @@ # reserved. Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file. -echo "Usage: " -cd .. - if [ -z "$1" ]; then echo "ERROR: Please specify a target platform: linux32 | linux64 | macos" else if [ -z "$2" ]; then echo "ERROR: Please specify a build type: Debug or Release" else - export OUT_PATH="./out/$1" + DIR="$( cd "$( dirname "$0" )" && cd .. && pwd )" + OUT_PATH="${DIR}/out/$1" - #export LIB_PATH=$(readlink -f "./jcef_build/native/$2") - export LIB_PATH=`pwd`/jcef_build/native/$2 + export LIB_PATH=$(readlink -f "./jcef_build/native/$2") if [ ! -d "$LIB_PATH" ]; then echo "ERROR: Native build output path does not exist" exit 1 @@ -25,16 +22,21 @@ else export OUT_PATH=$LIB_PATH fi - export CLS_PATH="./third_party/jogamp/jar/*:$OUT_PATH" + export CLS_PATH="${DIR}/third_party/jogamp/jar/*:$OUT_PATH" # Necessary for jcef_helper to find libcef.so. - #export LD_LIBRARY_PATH=$LIB_PATH + #if [ -n "$LD_LIBRARY_PATH" ]; then + # LD_LIBRARY_PATH="$LIB_PATH:${LD_LIBRARY_PATH}" + #else + # LD_LIBRARY_PATH="$LIB_PATH" + #fi + #export LD_LIBRARY_PATH # Remove the first two params ($1 and $2) and pass the rest to java. shift shift - #LD_PRELOAD=$LIB_PATH/libcef.so java -Djava.library.path=$LIB_PATH -jar ./third_party/junit/junit-platform-console-standalone-*.jar -cp $OUT_PATH --select-package tests.junittests "$@" + #LD_PRELOAD=libcef.so java -Djava.library.path="$LIB_PATH" -jar "${DIR}"/third_party/junit/junit-platform-console-standalone-*.jar -cp "$OUT_PATH" --select-package tests.junittests "$@" echo "TEST_JAVA_HOME=$TEST_JAVA_HOME" if [ ! -d "$TEST_JAVA_HOME" ]; then |