java/org/cef/CefClient.java (1,048 lines of code) (raw):

// Copyright (c) 2013 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; import com.jetbrains.cef.JCefAppConfig; import com.jetbrains.cef.JdkEx; import com.jetbrains.cef.remote.browser.RemoteBrowser; import com.jetbrains.cef.remote.browser.RemoteClient; import org.cef.browser.*; import org.cef.callback.*; import org.cef.handler.*; import org.cef.misc.BoolRef; import org.cef.misc.CefLog; import org.cef.misc.CefPrintSettings; import org.cef.misc.CefRange; import org.cef.network.CefRequest; import org.cef.network.CefRequest.TransitionType; import org.cef.security.CefSSLInfo; import java.awt.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import java.util.function.Supplier; /** * Client that owns a browser and renderer. */ public class CefClient extends CefClientHandler implements CefContextMenuHandler, CefDialogHandler, CefDisplayHandler, CefDownloadHandler, CefDragHandler, CefFocusHandler, CefPermissionHandler, CefJSDialogHandler, CefKeyboardHandler, CefLifeSpanHandler, CefLoadHandler, CefPrintHandler, CefRenderHandler, CefRequestHandler, CefWindowHandler { private static final boolean TRACE_LIFESPAN = Boolean.getBoolean("jcef.trace.cefclient.lifespan"); // Delegate for remote implementation. private final RemoteClient remoteClient; // Fields for JNI implementation. private final ConcurrentHashMap<Integer, CefBrowser> browser_ = new ConcurrentHashMap<Integer, CefBrowser>(); private CefContextMenuHandler contextMenuHandler_ = null; private CefDialogHandler dialogHandler_ = null; private CefDisplayHandler displayHandler_ = null; private CefDownloadHandler downloadHandler_ = null; private CefDragHandler dragHandler_ = null; private CefFocusHandler focusHandler_ = null; private CefPermissionHandler permissionHandler_ = null; private CefJSDialogHandler jsDialogHandler_ = null; private CefKeyboardHandler keyboardHandler_ = null; private final List<CefLifeSpanHandler> lifeSpanHandlers_ = new ArrayList<>(); private CefLoadHandler loadHandler_ = null; private CefPrintHandler printHandler_ = null; private CefRequestHandler requestHandler_ = null; private boolean isDisposed_ = false; private Runnable onDisposed_ = null; // just for convenience (for tests debugging) private volatile CefBrowser focusedBrowser_ = null; // allow(by making propertyChangeListener protected) custom disposing of this listener for GTW-4830 // TODO(kharitonov): make dispose() work w/o warnings and side effects for rem-dev server implementation protected final PropertyChangeListener propertyChangeListener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (focusedBrowser_ != null && !focusedBrowser_.isWindowless()) { Component browserUI = focusedBrowser_.getUIComponent(); if (browserUI == null) return; Object oldUI = evt.getOldValue(); if (isPartOf(oldUI, browserUI)) { focusedBrowser_.setFocus(false); focusedBrowser_ = null; } } } }; /** * The CTOR is only accessible within this package. * Use CefApp.createClient() to create an instance of * this class. * * @see org.cef.CefApp#createClient() */ protected CefClient() throws UnsatisfiedLinkError { super(); remoteClient = null; KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener(propertyChangeListener); if (TRACE_LIFESPAN) CefLog.Debug("CefClient %s: created in-process instance", this); } protected CefClient(RemoteClient _remoteClient) { super(); remoteClient = _remoteClient; if (TRACE_LIFESPAN) CefLog.Debug("CefClient %s: created remote client %s", this, remoteClient); } private boolean isPartOf(Object obj, Component browserUI) { if (obj == browserUI) return true; if (obj instanceof Container) { Component childs[] = ((Container) obj).getComponents(); for (Component child : childs) { return isPartOf(child, browserUI); } } return false; } @Override public void dispose() { if (TRACE_LIFESPAN) CefLog.Debug("CefClient: dispose client %s [remote=%s]", this, remoteClient); isDisposed_ = true; if (remoteClient != null) { // NOTE: super.dispose() shouldn't be called here CefApp app = remoteClient.getServer().getCefApp(); remoteClient.dispose(); if (app != null) app.clientWasDisposed(this); if (onDisposed_ != null) onDisposed_.run(); } else cleanupBrowser(-1); } public void setOnDisposeCallback(Runnable onDisposed) { this.onDisposed_ = onDisposed; } // CefClientHandler /** * @deprecated {@link #createBrowser(String, CefRendering, boolean)} */ @Deprecated public CefBrowser createBrowser( String url, boolean isOffscreenRendered, boolean isTransparent) { return createBrowser(url, isOffscreenRendered, isTransparent, null); } /** * @deprecated {@link #createBrowser(String, CefRendering, boolean, CefRequestContext)} */ @Deprecated public CefBrowser createBrowser(String url, boolean isOffscreenRendered, boolean isTransparent, CefRequestContext context) { return createBrowser(url, isOffscreenRendered ? CefRendering.OFFSCREEN : CefRendering.DEFAULT, isTransparent, context); } @Deprecated public CefBrowser createBrowser(String url, boolean isOffscreenRendered, boolean isTransparent, CefRequestContext context, CefBrowserSettings settings) { return createBrowser(url, isOffscreenRendered ? CefRendering.OFFSCREEN : CefRendering.DEFAULT, isTransparent, context, settings); } public CefBrowser createBrowser(String url, CefRendering rendering, boolean isTransparent) { return createBrowser(url, rendering, isTransparent, null); } public CefBrowser createBrowser(String url, CefRendering rendering, boolean isTransparent, CefRequestContext context) { if (isDisposed_) throw new IllegalStateException("Can't create browser. CefClient is disposed"); if (remoteClient != null) return remoteClient.createBrowser(url, context, this, rendering, null); return CefBrowserFactory.create(this, url, rendering, isTransparent, context, null); } public CefBrowser createBrowser(String url, CefRendering rendering, boolean isTransparent, CefRequestContext context, CefBrowserSettings settings) { if (isDisposed_) throw new IllegalStateException("Can't create browser. CefClient is disposed"); if (remoteClient != null) return remoteClient.createBrowser(url, context, this, rendering, settings); return CefBrowserFactory.create( this, url, rendering, isTransparent, context, settings); } public CefBrowser createBrowser(String url, Supplier<CefRendering> rendering, boolean isTransparent, CefRequestContext context, CefBrowserSettings settings) { if (isDisposed_) throw new IllegalStateException("Can't create browser. CefClient is disposed"); if (remoteClient != null) return remoteClient.createBrowser(url, context, this, rendering, settings); return CefBrowserFactory.create( this, url, rendering.get(), isTransparent, context, settings); } @Override protected CefBrowser getBrowser(int identifier) { if (remoteClient != null) return remoteClient.getRemoteBrowser(identifier); return browser_.get(identifier); } @Override protected Object[] getAllBrowser() { if (remoteClient != null) return remoteClient.getAllBrowsers(); return browser_.values().stream().filter(browser -> !browser.isClosing()).toArray(); } @Override protected CefContextMenuHandler getContextMenuHandler() { if (remoteClient != null) return remoteClient.getContextMenuHandler(); return this; } @Override protected CefDialogHandler getDialogHandler() { if (remoteClient != null) return remoteClient.getDialogHandler(); return this; } @Override protected CefDisplayHandler getDisplayHandler() { if (remoteClient != null) return remoteClient.getDisplayHandler(); return this; } @Override protected CefDownloadHandler getDownloadHandler() { if (remoteClient != null) return remoteClient.getDownloadHandler(); return this; } @Override protected CefDragHandler getDragHandler() { if (remoteClient != null) return remoteClient.getDragHandler(); return this; } @Override protected CefFocusHandler getFocusHandler() { if (remoteClient != null) return remoteClient.getFocusHandler(); return this; } @Override protected CefPermissionHandler getPermissionHandler() { if (remoteClient != null) return remoteClient.getPermissionHandler(); return this; } @Override protected CefJSDialogHandler getJSDialogHandler() { if (remoteClient != null) return remoteClient.getJSDialogHandler(); return this; } @Override protected CefKeyboardHandler getKeyboardHandler() { if (remoteClient != null) return remoteClient.getKeyboardHandler(); return this; } @Override protected CefLifeSpanHandler getLifeSpanHandler() { if (remoteClient != null) { CefLog.Error("CefClient.getLifeSpanHandler mustn't be called in remote mode."); return null; } return this; } @Override protected CefLoadHandler getLoadHandler() { if (remoteClient != null) return remoteClient.getLoadHandler(); return this; } @Override protected CefPrintHandler getPrintHandler() { if (remoteClient != null) return remoteClient.getPrintHandler(); return this; } @Override protected CefRenderHandler getRenderHandler() { if (remoteClient != null) { CefLog.Error("CefClient.getRenderHandler mustn't be called in remote mode."); return null; } return this; } @Override protected CefRequestHandler getRequestHandler() { if (remoteClient != null) return remoteClient.getRequestHandler(); return this; } @Override protected CefWindowHandler getWindowHandler() { if (remoteClient != null) return null; // only OSR rendering in remote mode return this; } // CefContextMenuHandler public CefClient addContextMenuHandler(CefContextMenuHandler handler) { if (remoteClient != null) remoteClient.addContextMenuHandler(handler); else if (contextMenuHandler_ == null) contextMenuHandler_ = handler; return this; } public void removeContextMenuHandler() { if (remoteClient != null) remoteClient.removeContextMenuHandler(); else contextMenuHandler_ = null; } @Override public void onBeforeContextMenu( CefBrowser browser, CefFrame frame, CefContextMenuParams params, CefMenuModel model) { if (remoteClient != null) CefLog.Error("onBeforeContextMenu mustn't be called in remote mode (it seems that user manually called this method)."); if (contextMenuHandler_ != null && browser != null) contextMenuHandler_.onBeforeContextMenu(browser, frame, params, model); } @Override public boolean runContextMenu(CefBrowser browser, CefFrame frame, CefContextMenuParams params, CefMenuModel model, CefRunContextMenuCallback callback) { if (remoteClient != null) CefLog.Error("The implementation for out-of-process is to be provided"); if (contextMenuHandler_ != null && browser != null) { return contextMenuHandler_.runContextMenu(browser, frame, params, model, callback); } return false; } @Override public boolean onContextMenuCommand(CefBrowser browser, CefFrame frame, CefContextMenuParams params, int commandId, int eventFlags) { if (remoteClient != null) CefLog.Error("onContextMenuCommand mustn't be called in remote mode (it seems that user manually called this method)."); if (contextMenuHandler_ != null && browser != null) return contextMenuHandler_.onContextMenuCommand( browser, frame, params, commandId, eventFlags); return false; } @Override public void onContextMenuDismissed(CefBrowser browser, CefFrame frame) { if (remoteClient != null) CefLog.Error("onContextMenuDismissed mustn't be called in remote mode (it seems that user manually called this method)."); if (contextMenuHandler_ != null && browser != null) contextMenuHandler_.onContextMenuDismissed(browser, frame); } // CefDialogHandler public CefClient addDialogHandler(CefDialogHandler handler) { if (remoteClient != null) remoteClient.addDialogHandler(handler); else if (dialogHandler_ == null) dialogHandler_ = handler; return this; } public void removeDialogHandler() { if (remoteClient != null) remoteClient.removeDialogHandler(); else dialogHandler_ = null; } @Override public boolean onFileDialog(CefBrowser browser, FileDialogMode mode, String title, String defaultFilePath, Vector<String> acceptFilters, Vector<String> acceptExtensions, Vector<String> acceptDescriptions, CefFileDialogCallback callback) { if (remoteClient != null) CefLog.Error("onFileDialog mustn't be called in remote mode (it seems that user manually called this method)."); if (dialogHandler_ != null && browser != null) { return dialogHandler_.onFileDialog(browser, mode, title, defaultFilePath, acceptFilters, acceptExtensions, acceptDescriptions, callback); } return false; } // CefDisplayHandler public CefClient addDisplayHandler(CefDisplayHandler handler) { if (remoteClient != null) remoteClient.addDisplayHandler(handler); else if (displayHandler_ == null) displayHandler_ = handler; return this; } public void removeDisplayHandler() { if (remoteClient != null) remoteClient.removeDisplayHandler(); else displayHandler_ = null; } @Override public void onAddressChange(CefBrowser browser, CefFrame frame, String url) { if (remoteClient != null) CefLog.Error("onAddressChange mustn't be called in remote mode (it seems that user manually called this method)."); if (displayHandler_ != null && browser != null) displayHandler_.onAddressChange(browser, frame, url); } @Override public void onTitleChange(CefBrowser browser, String title) { if (remoteClient != null) CefLog.Error("onTitleChange mustn't be called in remote mode (it seems that user manually called this method)."); if (displayHandler_ != null && browser != null) displayHandler_.onTitleChange(browser, title); } @Override public void onFullscreenModeChange(CefBrowser browser, boolean fullscreen) { if (displayHandler_ != null && browser != null) displayHandler_.onFullscreenModeChange(browser, fullscreen); } @Override public boolean onTooltip(CefBrowser browser, String text) { if (remoteClient != null) CefLog.Error("onTooltip mustn't be called in remote mode (it seems that user manually called this method)."); if (displayHandler_ != null && browser != null) { return displayHandler_.onTooltip(browser, text); } return false; } @Override public void onStatusMessage(CefBrowser browser, String value) { if (remoteClient != null) CefLog.Error("onStatusMessage mustn't be called in remote mode (it seems that user manually called this method)."); if (displayHandler_ != null && browser != null) { displayHandler_.onStatusMessage(browser, value); } } @Override public boolean onConsoleMessage(CefBrowser browser, CefSettings.LogSeverity level, String message, String source, int line) { if (remoteClient != null) CefLog.Error("onConsoleMessage mustn't be called in remote mode (it seems that user manually called this method)."); if (displayHandler_ != null && browser != null) { return displayHandler_.onConsoleMessage(browser, level, message, source, line); } return false; } @Override public boolean onCursorChange(CefBrowser browser, int cursorType) { if (remoteClient != null) CefLog.Error("onCursorChange mustn't be called in remote mode (it seems that user manually called this method)."); 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) { if (remoteClient != null) remoteClient.addDownloadHandler(handler); else if (downloadHandler_ == null) downloadHandler_ = handler; return this; } public void removeDownloadHandler() { if (remoteClient != null) remoteClient.removeDownloadHandler(); else downloadHandler_ = null; } @Override public boolean onBeforeDownload(CefBrowser browser, CefDownloadItem downloadItem, String suggestedName, CefBeforeDownloadCallback callback) { if (remoteClient != null) CefLog.Error("onBeforeDownload mustn't be called in remote mode (it seems that user manually called this method)."); if (downloadHandler_ != null && browser != null) return downloadHandler_.onBeforeDownload( browser, downloadItem, suggestedName, callback); return false; } @Override public void onDownloadUpdated( CefBrowser browser, CefDownloadItem downloadItem, CefDownloadItemCallback callback) { if (remoteClient != null) CefLog.Error("onDownloadUpdated mustn't be called in remote mode (it seems that user manually called this method)."); if (downloadHandler_ != null && browser != null) downloadHandler_.onDownloadUpdated(browser, downloadItem, callback); } // CefDragHandler public CefClient addDragHandler(CefDragHandler handler) { if (remoteClient != null) remoteClient.addDragHandler(handler); else if (dragHandler_ == null) dragHandler_ = handler; return this; } public void removeDragHandler() { if (remoteClient != null) remoteClient.removeDragHandler(); else dragHandler_ = null; } @Override public boolean onDragEnter(CefBrowser browser, CefDragData dragData, int mask) { if (remoteClient != null) CefLog.Error("onDragEnter mustn't be called in remote mode (it seems that user manually called this method)."); if (dragHandler_ != null && browser != null) return dragHandler_.onDragEnter(browser, dragData, mask); return false; } // CefFocusHandler public CefClient addFocusHandler(CefFocusHandler handler) { if (remoteClient != null) remoteClient.addFocusHandler(handler); else if (focusHandler_ == null) focusHandler_ = handler; return this; } public void removeFocusHandler() { if (remoteClient != null) remoteClient.removeFocusHandler(); else focusHandler_ = null; } @Override public void onTakeFocus(CefBrowser browser, boolean next) { if (remoteClient != null) CefLog.Error("onTakeFocus mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return; browser.setFocus(false); Component uiComponent = browser.getUIComponent(); if (uiComponent == null) return; Container parent = uiComponent.getParent(); if (parent != null) { FocusTraversalPolicy policy = null; while (parent != null) { policy = parent.getFocusTraversalPolicy(); if (policy != null) break; parent = parent.getParent(); } if (policy != null) { Component nextComp = next ? policy.getComponentAfter(parent, uiComponent) : policy.getComponentBefore(parent, uiComponent); if (nextComp == null) { policy.getDefaultComponent(parent).requestFocus(); } else { nextComp.requestFocus(); } } } focusedBrowser_ = null; if (focusHandler_ != null) focusHandler_.onTakeFocus(browser, next); } @Override public boolean onSetFocus(final CefBrowser browser, FocusSource source) { if (remoteClient != null) CefLog.Error("onSetFocus mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return false; Boolean alreadyHandled = Boolean.FALSE; if (focusHandler_ != null) { Component uiComponent = browser.getUIComponent(); if (uiComponent == null) return true; alreadyHandled = JdkEx.invokeOnEDTAndWait(() -> focusHandler_.onSetFocus(browser, source), Boolean.TRUE /*ignore focus*/, uiComponent); } return alreadyHandled; } @Override public void onGotFocus(CefBrowser browser) { if (remoteClient != null) CefLog.Error("onGotFocus mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return; if (focusedBrowser_ == browser) return; // prevent recursive call (in OSR) focusedBrowser_ = browser; browser.setFocus(true); if (focusHandler_ != null) { Component uiComponent = browser.getUIComponent(); if (uiComponent == null) return; JdkEx.invokeOnEDTAndWait(() -> focusHandler_.onGotFocus(browser), uiComponent); } } // CefPermissionHandler public CefClient addPermissionHandler(CefPermissionHandler handler) { if (remoteClient != null) remoteClient.addPermissionHandler(handler); else if (permissionHandler_ == null) permissionHandler_ = handler; return this; } public void removePermissionHandler() { if (remoteClient != null) remoteClient.removePermissionHandler(); else permissionHandler_ = null; } @Override public boolean onRequestMediaAccessPermission( CefBrowser browser, CefFrame frame, String requesting_url, int requested_permissions, CefMediaAccessCallback callback) { if (remoteClient != null) CefLog.Error("onRequestMediaAccessPermission mustn't be called in remote mode (it seems that user manually called this method)."); if (permissionHandler_ != null && browser != null) return permissionHandler_.onRequestMediaAccessPermission(browser, frame, requesting_url, requested_permissions, callback); return false; } // CefJSDialogHandler public CefClient addJSDialogHandler(CefJSDialogHandler handler) { if (remoteClient != null) remoteClient.addJSDialogHandler(handler); else if (jsDialogHandler_ == null) jsDialogHandler_ = handler; return this; } public void removeJSDialogHandler() { if (remoteClient != null) remoteClient.removeJSDialogHandler(); else jsDialogHandler_ = null; } @Override public boolean onJSDialog(CefBrowser browser, String origin_url, JSDialogType dialog_type, String message_text, String default_prompt_text, CefJSDialogCallback callback, BoolRef suppress_message) { if (remoteClient != null) CefLog.Error("onJSDialog mustn't be called in remote mode (it seems that user manually called this method)."); if (jsDialogHandler_ != null && browser != null) return jsDialogHandler_.onJSDialog(browser, origin_url, dialog_type, message_text, default_prompt_text, callback, suppress_message); return false; } @Override public boolean onBeforeUnloadDialog(CefBrowser browser, String message_text, boolean is_reload, CefJSDialogCallback callback) { if (remoteClient != null) CefLog.Error("onBeforeUnloadDialog mustn't be called in remote mode (it seems that user manually called this method)."); if (jsDialogHandler_ != null && browser != null) return jsDialogHandler_.onBeforeUnloadDialog( browser, message_text, is_reload, callback); return false; } @Override public void onResetDialogState(CefBrowser browser) { if (remoteClient != null) CefLog.Error("onResetDialogState mustn't be called in remote mode (it seems that user manually called this method)."); if (jsDialogHandler_ != null && browser != null) jsDialogHandler_.onResetDialogState(browser); } @Override public void onDialogClosed(CefBrowser browser) { if (remoteClient != null) CefLog.Error("onDialogClosed mustn't be called in remote mode (it seems that user manually called this method)."); if (jsDialogHandler_ != null && browser != null) jsDialogHandler_.onDialogClosed(browser); } // CefKeyboardHandler public CefClient addKeyboardHandler(CefKeyboardHandler handler) { if (remoteClient != null) remoteClient.addKeyboardHandler(handler); else if (keyboardHandler_ == null) keyboardHandler_ = handler; return this; } public void removeKeyboardHandler() { if (remoteClient != null) remoteClient.removeKeyboardHandler(); else keyboardHandler_ = null; } @Override public boolean onPreKeyEvent( CefBrowser browser, CefKeyEvent event, BoolRef is_keyboard_shortcut) { if (remoteClient != null) CefLog.Error("onPreKeyEvent mustn't be called in remote mode (it seems that user manually called this method)."); if (keyboardHandler_ != null && browser != null) return keyboardHandler_.onPreKeyEvent(browser, event, is_keyboard_shortcut); return false; } @Override public boolean onKeyEvent(CefBrowser browser, CefKeyEvent event) { if (remoteClient != null) CefLog.Error("onKeyEvent mustn't be called in remote mode (it seems that user manually called this method)."); if (keyboardHandler_ != null && browser != null) return keyboardHandler_.onKeyEvent(browser, event); return false; } // CefLifeSpanHandler public CefClient addLifeSpanHandler(CefLifeSpanHandler handler) { if (remoteClient != null) remoteClient.addLifeSpanHandler(handler); else synchronized (lifeSpanHandlers_) { lifeSpanHandlers_.add(handler); } return this; } public void removeLifeSpanHandler() { if (remoteClient != null) remoteClient.removeAllLifeSpanHandlers(); else synchronized (lifeSpanHandlers_) { lifeSpanHandlers_.clear(); } } @Override public boolean onBeforePopup( CefBrowser browser, CefFrame frame, String target_url, String target_frame_name) { if (remoteClient != null) CefLog.Error("onBeforePopup mustn't be called in remote mode (it seems that user manually called this method)."); if (isDisposed_) return true; if (browser == null) return false; synchronized (lifeSpanHandlers_) { boolean result = false; for (CefLifeSpanHandler lsh : lifeSpanHandlers_) { result |= lsh.onBeforePopup(browser, frame, target_url, target_frame_name); } return result; } } @Override public void onAfterCreated(CefBrowser browser) { if (remoteClient != null) CefLog.Error("onAfterCreated mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return; if (TRACE_LIFESPAN) CefLog.Debug("CefClient: browser=%s: onAfterCreated", browser); boolean disposed = isDisposed_; if (disposed) CefLog.Info("Browser %s was created while CefClient was marked as disposed", browser); // keep browser reference Integer identifier = browser.getIdentifier(); if (!disposed) { browser_.put(identifier, browser); } synchronized (lifeSpanHandlers_) { for (CefLifeSpanHandler lsh : lifeSpanHandlers_) lsh.onAfterCreated(browser); } if (disposed) { // Not sure, but it makes sense to close browser since it's not in browser_ browser.close(true); } } @Override public void onAfterParentChanged(CefBrowser browser) { if (remoteClient != null) CefLog.Error("onAfterParentChanged mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return; synchronized (lifeSpanHandlers_) { for (CefLifeSpanHandler lsh : lifeSpanHandlers_) lsh.onAfterParentChanged(browser); } } @Override public boolean doClose(CefBrowser browser) { if (remoteClient != null) CefLog.Error("doClose mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return false; synchronized (lifeSpanHandlers_) { for (CefLifeSpanHandler lsh : lifeSpanHandlers_) lsh.doClose(browser); } return browser.doClose(); } @Override public void onBeforeClose(CefBrowser browser) { if (remoteClient != null) CefLog.Error("onBeforeClose mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return; if (TRACE_LIFESPAN) CefLog.Debug("CefClient: browser=%s: onBeforeClose", browser); synchronized (lifeSpanHandlers_) { for (CefLifeSpanHandler lsh : lifeSpanHandlers_) lsh.onBeforeClose(browser); } browser.onBeforeClose(); // remove browser reference cleanupBrowser(browser.getIdentifier()); } private void cleanupBrowser(int identifier) { if (identifier >= 0) { // Remove the specific browser that closed. browser_.remove(identifier); } else { assert isDisposed_; Collection<CefBrowser> browserList = new ArrayList<>(browser_.values()); if (!browserList.isEmpty()) { if (TRACE_LIFESPAN) CefLog.Debug("CefClient: cleanup %d browsers", browserList.size()); // Close all browsers. // Once any of browsers close, it will invoke #onBeforeClose and #cleanupBrowser for (CefBrowser browser : browserList) { if (TRACE_LIFESPAN) CefLog.Debug("CefClient: close %s", browser); browser.close(true); } return; } } if (!isDisposed_) return; if (!browser_.isEmpty()) return; KeyboardFocusManager.getCurrentKeyboardFocusManager().removePropertyChangeListener( propertyChangeListener); removeContextMenuHandler(this); removeDialogHandler(this); removeDisplayHandler(this); removeDownloadHandler(this); removeDragHandler(this); removeFocusHandler(this); removeJSDialogHandler(this); removeKeyboardHandler(this); removeLifeSpanHandler(this); removeLoadHandler(this); removePrintHandler(this); removeRenderHandler(this); removeRequestHandler(this); removeWindowHandler(this); super.dispose(); CefApp app = CefApp.getInstanceIfAny(); if (app != null) app.clientWasDisposed(this); if (onDisposed_ != null) onDisposed_.run(); } // CefLoadHandler public CefClient addLoadHandler(CefLoadHandler handler) { if (remoteClient != null) remoteClient.addLoadHandler(handler); else if (loadHandler_ == null) loadHandler_ = handler; return this; } public void removeLoadHandler() { if (remoteClient != null) remoteClient.removeLoadHandler(); else loadHandler_ = null; } @Override public void onLoadingStateChange( CefBrowser browser, boolean isLoading, boolean canGoBack, boolean canGoForward) { if (remoteClient != null) CefLog.Error("onLoadingStateChange mustn't be called in remote mode (it seems that user manually called this method)."); if (loadHandler_ != null && browser != null) loadHandler_.onLoadingStateChange(browser, isLoading, canGoBack, canGoForward); } @Override public void onLoadStart(CefBrowser browser, CefFrame frame, TransitionType transitionType) { if (remoteClient != null) CefLog.Error("onLoadStart mustn't be called in remote mode (it seems that user manually called this method)."); if (loadHandler_ != null && browser != null) loadHandler_.onLoadStart(browser, frame, transitionType); } @Override public void onLoadEnd(CefBrowser browser, CefFrame frame, int httpStatusCode) { if (remoteClient != null) CefLog.Error("onLoadEnd mustn't be called in remote mode (it seems that user manually called this method)."); if (loadHandler_ != null && browser != null) loadHandler_.onLoadEnd(browser, frame, httpStatusCode); } @Override public void onLoadError(CefBrowser browser, CefFrame frame, ErrorCode errorCode, String errorText, String failedUrl) { if (remoteClient != null) CefLog.Error("onLoadError mustn't be called in remote mode (it seems that user manually called this method)."); if (loadHandler_ != null && browser != null) loadHandler_.onLoadError(browser, frame, errorCode, errorText, failedUrl); } // CefPrintHandler public CefClient addPrintHandler(CefPrintHandler handler) { if (remoteClient != null) remoteClient.addPrintHandler(handler); else if (printHandler_ == null) printHandler_ = handler; return this; } public void removePrintHandler() { if (remoteClient != null) remoteClient.removePrintHandler(); else printHandler_ = null; } @Override public void onPrintStart(CefBrowser browser) { if (remoteClient != null) CefLog.Error("onPrintStart mustn't be called in remote mode (it seems that user manually called this method)."); if (printHandler_ != null && browser != null) printHandler_.onPrintStart(browser); } @Override public void onPrintSettings( CefBrowser browser, CefPrintSettings settings, boolean getDefaults) { if (remoteClient != null) CefLog.Error("onPrintSettings mustn't be called in remote mode (it seems that user manually called this method)."); if (printHandler_ != null && browser != null) printHandler_.onPrintSettings(browser, settings, getDefaults); } @Override public boolean onPrintDialog( CefBrowser browser, boolean hasSelection, CefPrintDialogCallback callback) { if (remoteClient != null) CefLog.Error("onPrintDialog mustn't be called in remote mode (it seems that user manually called this method)."); if (printHandler_ != null && browser != null) return printHandler_.onPrintDialog(browser, hasSelection, callback); return false; } @Override public boolean onPrintJob(CefBrowser browser, String documentName, String pdfFilePath, CefPrintJobCallback callback) { if (remoteClient != null) CefLog.Error("onPrintJob mustn't be called in remote mode (it seems that user manually called this method)."); if (printHandler_ != null && browser != null) return printHandler_.onPrintJob(browser, documentName, pdfFilePath, callback); return false; } @Override public void onPrintReset(CefBrowser browser) { if (remoteClient != null) CefLog.Error("onPrintReset mustn't be called in remote mode (it seems that user manually called this method)."); if (printHandler_ != null && browser != null) printHandler_.onPrintReset(browser); } @Override public Dimension getPdfPaperSize(CefBrowser browser, int deviceUnitsPerInch) { if (remoteClient != null) CefLog.Error("getPdfPaperSize mustn't be called in remote mode (it seems that user manually called this method)."); if (printHandler_ != null && browser != null) return printHandler_.getPdfPaperSize(browser, deviceUnitsPerInch); return null; } // CefMessageRouter @Override public synchronized void addMessageRouter(CefMessageRouter messageRouter) { if (remoteClient != null) remoteClient.addMessageRouter(messageRouter); else super.addMessageRouter(messageRouter); } @Override public synchronized void removeMessageRouter(CefMessageRouter messageRouter) { if (remoteClient != null) remoteClient.removeMessageRouter(messageRouter); else super.removeMessageRouter(messageRouter); } // CefRenderHandler @Override public Rectangle getViewRect(CefBrowser browser) { if (remoteClient != null) CefLog.Error("getViewRect mustn't be called in remote mode (it seems that user manually called this method)."); // [tav] resize to 1x1 size to avoid crash in cef if (browser == null) return new Rectangle(0, 0, 1, 1); CefRenderHandler realHandler = browser.getRenderHandler(); if (realHandler != null) { Rectangle rect = realHandler.getViewRect(browser); if (rect.width <= 0 || rect.height <= 0) { rect = new Rectangle(rect.x, rect.y, 1, 1); } return rect; } return new Rectangle(0, 0, 1, 1); } @Override public Point getScreenPoint(CefBrowser browser, Point viewPoint) { if (remoteClient != null) CefLog.Error("getScreenPoint mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return new Point(0, 0); CefRenderHandler realHandler = browser.getRenderHandler(); if (realHandler != null) return realHandler.getScreenPoint(browser, viewPoint); return new Point(0, 0); } @Override public double getDeviceScaleFactor(CefBrowser browser) { if (remoteClient != null) CefLog.Error("getDeviceScaleFactor mustn't be called in remote mode (it seems that user manually called this method)."); CefRenderHandler realHandler = browser.getRenderHandler(); if (realHandler != null) { return realHandler.getDeviceScaleFactor(browser); } return JCefAppConfig.getDeviceScaleFactor(browser.getUIComponent()); } @Override public void onPopupShow(CefBrowser browser, boolean show) { if (remoteClient != null) CefLog.Error("onPopupShow mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return; CefRenderHandler realHandler = browser.getRenderHandler(); if (realHandler != null) realHandler.onPopupShow(browser, show); } @Override public void onPopupSize(CefBrowser browser, Rectangle size) { if (remoteClient != null) CefLog.Error("onPopupSize mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return; CefRenderHandler realHandler = browser.getRenderHandler(); if (realHandler != null) realHandler.onPopupSize(browser, size); } @Override public void onPaint(CefBrowser browser, boolean popup, Rectangle[] dirtyRects, ByteBuffer buffer, int width, int height) { if (remoteClient != null) CefLog.Error("onPaint mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return; CefRenderHandler realHandler = browser.getRenderHandler(); if (realHandler != null) realHandler.onPaint(browser, popup, dirtyRects, buffer, width, height); } @Override public void onAcceleratedPaint(CefBrowser browser, boolean popup, Rectangle[] dirtyRects, CefAcceleratedPaintInfo info) { if (remoteClient != null) CefLog.Error("onAcceleratedPaint mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return; CefRenderHandler realHandler = browser.getRenderHandler(); if (realHandler != null) { realHandler.onAcceleratedPaint(browser, popup, dirtyRects, info); } } @Override public void addOnPaintListener(Consumer<CefPaintEvent> listener) {} @Override public void setOnPaintListener(Consumer<CefPaintEvent> listener) {} @Override public void removeOnPaintListener(Consumer<CefPaintEvent> listener) {} @Override public boolean startDragging(CefBrowser browser, CefDragData dragData, int mask, int x, int y) { if (remoteClient != null) CefLog.Error("startDragging mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return false; CefRenderHandler realHandler = browser.getRenderHandler(); if (realHandler != null) return realHandler.startDragging(browser, dragData, mask, x, y); return false; } @Override public void updateDragCursor(CefBrowser browser, int operation) { if (remoteClient != null) CefLog.Error("updateDragCursor mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return; CefRenderHandler realHandler = browser.getRenderHandler(); if (realHandler != null) realHandler.updateDragCursor(browser, operation); } @Override public void OnImeCompositionRangeChanged(CefBrowser browser, CefRange selectionRange, Rectangle[] characterBounds) { if (remoteClient != null) CefLog.Error("OnImeCompositionRangeChanged mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return; CefRenderHandler realHandler = browser.getRenderHandler(); if (realHandler != null) realHandler.OnImeCompositionRangeChanged(browser, selectionRange, characterBounds); } @Override public void OnTextSelectionChanged(CefBrowser browser, String selectedText, CefRange selectionRange) { if (remoteClient != null) CefLog.Error("OnTextSelectionChanged mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return; CefRenderHandler realHandler = browser.getRenderHandler(); if (realHandler != null) realHandler.OnTextSelectionChanged(browser, selectedText, selectionRange); } @Override public boolean getScreenInfo(CefBrowser browser, CefScreenInfo screenInfo) { if (remoteClient != null) CefLog.Error("getScreenInfo mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return false; CefRenderHandler realHandler = browser.getRenderHandler(); if (realHandler != null) return realHandler.getScreenInfo(browser, screenInfo); return false; } // CefRequestHandler public CefClient addRequestHandler(CefRequestHandler handler) { if (remoteClient != null) remoteClient.addRequestHandler(handler); else if (requestHandler_ == null) requestHandler_ = handler; return this; } public void removeRequestHandler() { if (remoteClient != null) remoteClient.removeRequestHandler(); else requestHandler_ = null; } @Override public boolean onBeforeBrowse(CefBrowser browser, CefFrame frame, CefRequest request, boolean user_gesture, boolean is_redirect) { if (remoteClient != null) CefLog.Error("onBeforeBrowse mustn't be called in remote mode (it seems that user manually called this method)."); if (requestHandler_ != null && browser != null) return requestHandler_.onBeforeBrowse( browser, frame, request, user_gesture, is_redirect); return false; } @Override public boolean onOpenURLFromTab( CefBrowser browser, CefFrame frame, String target_url, boolean user_gesture) { if (remoteClient != null) CefLog.Error("onOpenURLFromTab mustn't be called in remote mode (it seems that user manually called this method)."); 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) { if (remoteClient != null) CefLog.Error("getResourceRequestHandler mustn't be called in remote mode (it seems that user manually called this method)."); if (requestHandler_ != null && browser != null) { return requestHandler_.getResourceRequestHandler(browser, frame, request, isNavigation, isDownload, requestInitiator, disableDefaultHandling); } return null; } @Override public boolean getAuthCredentials(CefBrowser browser, String origin_url, boolean isProxy, String host, int port, String realm, String scheme, CefAuthCallback callback) { if (remoteClient != null) CefLog.Error("getAuthCredentials mustn't be called in remote mode (it seems that user manually called this method)."); if (requestHandler_ != null && browser != null) return requestHandler_.getAuthCredentials( browser, origin_url, isProxy, host, port, realm, scheme, callback); return false; } @Override public boolean onCertificateError( CefBrowser browser, ErrorCode cert_error, String request_url, CefSSLInfo sslInfo, CefCallback callback) { if (remoteClient != null) { CefLog.Error("onCertificateError mustn't be called in remote mode (it seems that user manually called this method)."); // NOTE: next invocation us added just for IDEA tests. CefRequestHandler handler = remoteClient.getRequestHandler(); if (handler != null) return handler.onCertificateError(browser, cert_error, request_url, sslInfo, callback); } if (requestHandler_ != null) return requestHandler_.onCertificateError(browser, cert_error, request_url, sslInfo, callback); return false; } @Override public void onRenderProcessTerminated( CefBrowser browser, TerminationStatus status, int error_code, String error_string) { if (remoteClient != null) CefLog.Error("onRenderProcessTerminated mustn't be called in remote mode (it seems that user manually called this method)."); if (requestHandler_ != null) requestHandler_.onRenderProcessTerminated(browser, status, error_code, error_string); } // CefWindowHandler @Override public Rectangle getRect(CefBrowser browser) { if (remoteClient != null) CefLog.Error("getRect mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return new Rectangle(0, 0, 0, 0); CefWindowHandler realHandler = browser.getWindowHandler(); if (realHandler != null) return realHandler.getRect(browser); return new Rectangle(0, 0, 0, 0); } @Override public void onMouseEvent( CefBrowser browser, int event, int screenX, int screenY, int modifier, int button) { if (remoteClient != null) CefLog.Error("onMouseEvent mustn't be called in remote mode (it seems that user manually called this method)."); if (browser == null) return; CefWindowHandler realHandler = browser.getWindowHandler(); if (realHandler != null) realHandler.onMouseEvent(browser, event, screenX, screenY, modifier, button); } public String getInfo() { StringBuilder sb = new StringBuilder(toString()); if (browser_.isEmpty()) sb.append(" [0 active browsers]"); else { sb.append(" | "); for (CefBrowser b : browser_.values()) { sb.append(b); sb.append(", "); } } return sb.toString(); } public static boolean isNativeBrowserCreationStarted(CefBrowser browser) { if (browser instanceof RemoteBrowser) return ((RemoteBrowser)browser).isNativeBrowserCreationStarted(); // Fallback to old logic (incorrect in general, since creation is always started before native ref obtained) if (browser instanceof CefNativeAdapter) return ((CefNativeAdapter)browser).getNativeRef("CefBrowser") != 0; CefLog.Error("Unsupported CefBrowser: %s", browser); return false; } public static boolean isNativeBrowserCreated(CefBrowser cefBrowser) { if (cefBrowser instanceof RemoteBrowser) return ((RemoteBrowser)cefBrowser).isNativeBrowserCreated(); if (cefBrowser instanceof CefNativeAdapter) return ((CefNativeAdapter)cefBrowser).getNativeRef("CefBrowser") != 0; return false; } }