Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/swing/JLightweightFrame.java
38829 views
/*1* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.swing;2627import java.awt.BorderLayout;28import java.awt.Color;29import java.awt.Component;30import java.awt.Container;31import java.awt.Dimension;32import java.awt.EventQueue;33import java.awt.Graphics;34import java.awt.Graphics2D;35import java.awt.MouseInfo;36import java.awt.Point;37import java.awt.Rectangle;38import java.awt.Window;39import java.awt.dnd.DragGestureEvent;40import java.awt.dnd.DragGestureListener;41import java.awt.dnd.DragGestureRecognizer;42import java.awt.dnd.DragSource;43import java.awt.dnd.DropTarget;44import java.awt.dnd.InvalidDnDOperationException;45import java.awt.dnd.peer.DragSourceContextPeer;46import java.awt.event.ContainerEvent;47import java.awt.event.ContainerListener;48import java.awt.image.BufferedImage;49import java.awt.image.DataBufferInt;50import java.beans.PropertyChangeEvent;51import java.beans.PropertyChangeListener;52import java.security.AccessController;53import javax.swing.JComponent;5455import javax.swing.JLayeredPane;56import javax.swing.JPanel;57import javax.swing.JRootPane;58import javax.swing.LayoutFocusTraversalPolicy;59import javax.swing.RepaintManager;60import javax.swing.RootPaneContainer;61import javax.swing.SwingUtilities;6263import sun.awt.AWTAccessor;64import sun.awt.DisplayChangedListener;65import sun.awt.LightweightFrame;66import sun.awt.OverrideNativeWindowHandle;67import sun.security.action.GetPropertyAction;68import sun.swing.SwingUtilities2.RepaintListener;6970/**71* The frame serves as a lightweight container which paints its content72* to an offscreen image and provides access to the image's data via the73* {@link LightweightContent} interface. Note, that it may not be shown74* as a standalone toplevel frame. Its purpose is to provide functionality75* for lightweight embedding.76*77* @author Artem Ananiev78* @author Anton Tarasov79*/80public final class JLightweightFrame extends LightweightFrame implements RootPaneContainer {8182private final JRootPane rootPane = new JRootPane();8384private LightweightContent content;8586private Component component;87private JPanel contentPane;8889private BufferedImage bbImage;9091private volatile int scaleFactor = 1;9293/**94* {@code copyBufferEnabled}, true by default, defines the following strategy.95* A duplicating (copy) buffer is created for the original pixel buffer.96* The copy buffer is synchronized with the original buffer every time the97* latter changes. {@code JLightweightFrame} passes the copy buffer array98* to the {@link LightweightContent#imageBufferReset} method. The code spot99* which synchronizes two buffers becomes the only critical section guarded100* by the lock (managed with the {@link LightweightContent#paintLock()},101* {@link LightweightContent#paintUnlock()} methods).102*/103private static boolean copyBufferEnabled;104private int[] copyBuffer;105106private PropertyChangeListener layoutSizeListener;107private RepaintListener repaintListener;108109static {110SwingAccessor.setJLightweightFrameAccessor(new SwingAccessor.JLightweightFrameAccessor() {111@Override112public void updateCursor(JLightweightFrame frame) {113frame.updateClientCursor();114}115});116copyBufferEnabled = "true".equals(AccessController.117doPrivileged(new GetPropertyAction("swing.jlf.copyBufferEnabled", "true")));118}119120/**121* Constructs a new, initially invisible {@code JLightweightFrame}122* instance.123*/124public JLightweightFrame() {125super();126copyBufferEnabled = "true".equals(AccessController.127doPrivileged(new GetPropertyAction("swing.jlf.copyBufferEnabled", "true")));128129add(rootPane, BorderLayout.CENTER);130setFocusTraversalPolicy(new LayoutFocusTraversalPolicy());131if (getGraphicsConfiguration().isTranslucencyCapable()) {132setBackground(new Color(0, 0, 0, 0));133}134135layoutSizeListener = new PropertyChangeListener() {136@Override137public void propertyChange(PropertyChangeEvent e) {138Dimension d = (Dimension)e.getNewValue();139140if ("preferredSize".equals(e.getPropertyName())) {141content.preferredSizeChanged(d.width, d.height);142143} else if ("maximumSize".equals(e.getPropertyName())) {144content.maximumSizeChanged(d.width, d.height);145146} else if ("minimumSize".equals(e.getPropertyName())) {147content.minimumSizeChanged(d.width, d.height);148}149}150};151152repaintListener = (JComponent c, int x, int y, int w, int h) -> {153Window jlf = SwingUtilities.getWindowAncestor(c);154if (jlf != JLightweightFrame.this) {155return;156}157Point p = SwingUtilities.convertPoint(c, x, y, jlf);158Rectangle r = new Rectangle(p.x, p.y, w, h).intersection(159new Rectangle(0, 0, bbImage.getWidth() / scaleFactor,160bbImage.getHeight() / scaleFactor));161162if (!r.isEmpty()) {163notifyImageUpdated(r.x, r.y, r.width, r.height);164}165};166167SwingAccessor.getRepaintManagerAccessor().addRepaintListener(168RepaintManager.currentManager(this), repaintListener);169}170171@Override172public void dispose() {173SwingAccessor.getRepaintManagerAccessor().removeRepaintListener(174RepaintManager.currentManager(this), repaintListener);175super.dispose();176}177178/**179* Sets the {@link LightweightContent} instance for this frame.180* The {@code JComponent} object returned by the181* {@link LightweightContent#getComponent()} method is immediately182* added to the frame's content pane.183*184* @param content the {@link LightweightContent} instance185*/186public void setContent(final LightweightContent content) {187if (content == null) {188System.err.println("JLightweightFrame.setContent: content may not be null!");189return;190}191this.content = content;192this.component = content.getComponent();193194Dimension d = this.component.getPreferredSize();195content.preferredSizeChanged(d.width, d.height);196197d = this.component.getMaximumSize();198content.maximumSizeChanged(d.width, d.height);199200d = this.component.getMinimumSize();201content.minimumSizeChanged(d.width, d.height);202203initInterior();204}205206@Override207public Graphics getGraphics() {208if (bbImage == null) return null;209210Graphics2D g = bbImage.createGraphics();211g.setBackground(getBackground());212g.setColor(getForeground());213g.setFont(getFont());214g.scale(scaleFactor, scaleFactor);215return g;216}217218/**219* {@inheritDoc}220*221* @see LightweightContent#focusGrabbed()222*/223@Override224public void grabFocus() {225if (content != null) content.focusGrabbed();226}227228/**229* {@inheritDoc}230*231* @see LightweightContent#focusUngrabbed()232*/233@Override234public void ungrabFocus() {235if (content != null) content.focusUngrabbed();236}237238@Override239public int getScaleFactor() {240return scaleFactor;241}242243@Override244public void notifyDisplayChanged(final int scaleFactor) {245if (scaleFactor != this.scaleFactor) {246if (!copyBufferEnabled) content.paintLock();247try {248if (bbImage != null) {249resizeBuffer(getWidth(), getHeight(), scaleFactor);250}251} finally {252if (!copyBufferEnabled) content.paintUnlock();253}254this.scaleFactor = scaleFactor;255}256if (getPeer() instanceof DisplayChangedListener) {257((DisplayChangedListener)getPeer()).displayChanged();258}259repaint();260}261262@Override263public void addNotify() {264super.addNotify();265if (getPeer() instanceof DisplayChangedListener) {266((DisplayChangedListener)getPeer()).displayChanged();267}268}269270private void syncCopyBuffer(boolean reset, int x, int y, int w, int h, int scale) {271content.paintLock();272try {273int[] srcBuffer = ((DataBufferInt)bbImage.getRaster().getDataBuffer()).getData();274if (reset) {275copyBuffer = new int[srcBuffer.length];276}277int linestride = bbImage.getWidth();278279x *= scale;280y *= scale;281w *= scale;282h *= scale;283284for (int i=0; i<h; i++) {285int from = (y + i) * linestride + x;286System.arraycopy(srcBuffer, from, copyBuffer, from, w);287}288} finally {289content.paintUnlock();290}291}292293private void notifyImageUpdated(int x, int y, int width, int height) {294if (copyBufferEnabled) {295syncCopyBuffer(false, x, y, width, height, scaleFactor);296}297content.imageUpdated(x, y, width, height);298}299300private void initInterior() {301contentPane = new JPanel() {302@Override303public void paint(Graphics g) {304if (!copyBufferEnabled) {305content.paintLock();306}307try {308super.paint(g);309310final Rectangle clip = g.getClipBounds() != null ?311g.getClipBounds() :312new Rectangle(0, 0, contentPane.getWidth(), contentPane.getHeight());313314clip.x = Math.max(0, clip.x);315clip.y = Math.max(0, clip.y);316clip.width = Math.min(contentPane.getWidth(), clip.width);317clip.height = Math.min(contentPane.getHeight(), clip.height);318319EventQueue.invokeLater(new Runnable() {320@Override321public void run() {322Rectangle c = contentPane.getBounds().intersection(clip);323notifyImageUpdated(c.x, c.y, c.width, c.height);324}325});326} finally {327if (!copyBufferEnabled) {328content.paintUnlock();329}330}331}332@Override333protected boolean isPaintingOrigin() {334return true;335}336};337contentPane.setLayout(new BorderLayout());338contentPane.add(component);339if ("true".equals(AccessController.340doPrivileged(new GetPropertyAction("swing.jlf.contentPaneTransparent", "false"))))341{342contentPane.setOpaque(false);343}344setContentPane(contentPane);345346contentPane.addContainerListener(new ContainerListener() {347@Override348public void componentAdded(ContainerEvent e) {349Component c = JLightweightFrame.this.component;350if (e.getChild() == c) {351c.addPropertyChangeListener("preferredSize", layoutSizeListener);352c.addPropertyChangeListener("maximumSize", layoutSizeListener);353c.addPropertyChangeListener("minimumSize", layoutSizeListener);354}355}356@Override357public void componentRemoved(ContainerEvent e) {358Component c = JLightweightFrame.this.component;359if (e.getChild() == c) {360c.removePropertyChangeListener(layoutSizeListener);361}362}363});364}365366@SuppressWarnings("deprecation")367@Override public void reshape(int x, int y, int width, int height) {368super.reshape(x, y, width, height);369370if (width == 0 || height == 0) {371return;372}373if (!copyBufferEnabled) {374content.paintLock();375}376try {377boolean createBB = (bbImage == null);378int newW = width;379int newH = height;380if (bbImage != null) {381int imgWidth = bbImage.getWidth() / scaleFactor;382int imgHeight = bbImage.getHeight() / scaleFactor;383if (width != imgWidth || height != imgHeight) {384createBB = true;385if (bbImage != null) {386int oldW = imgWidth;387int oldH = imgHeight;388if ((oldW >= newW) && (oldH >= newH)) {389createBB = false;390} else {391if (oldW >= newW) {392newW = oldW;393} else {394newW = Math.max((int)(oldW * 1.2), width);395}396if (oldH >= newH) {397newH = oldH;398} else {399newH = Math.max((int)(oldH * 1.2), height);400}401}402}403}404}405if (createBB) {406resizeBuffer(newW, newH, scaleFactor);407return;408}409content.imageReshaped(0, 0, width, height);410411} finally {412if (!copyBufferEnabled) {413content.paintUnlock();414}415}416}417418private void resizeBuffer(int width, int height, int newScaleFactor) {419bbImage = new BufferedImage(width*newScaleFactor,height*newScaleFactor,420BufferedImage.TYPE_INT_ARGB_PRE);421int[] pixels= ((DataBufferInt)bbImage.getRaster().getDataBuffer()).getData();422if (copyBufferEnabled) {423syncCopyBuffer(true, 0, 0, width, height, newScaleFactor);424pixels = copyBuffer;425}426content.imageBufferReset(pixels, 0, 0, width, height,427width * newScaleFactor, newScaleFactor);428}429430@Override431public JRootPane getRootPane() {432return rootPane;433}434435@Override436public void setContentPane(Container contentPane) {437getRootPane().setContentPane(contentPane);438}439440@Override441public Container getContentPane() {442return getRootPane().getContentPane();443}444445@Override446public void setLayeredPane(JLayeredPane layeredPane) {447getRootPane().setLayeredPane(layeredPane);448}449450@Override451public JLayeredPane getLayeredPane() {452return getRootPane().getLayeredPane();453}454455@Override456public void setGlassPane(Component glassPane) {457getRootPane().setGlassPane(glassPane);458}459460@Override461public Component getGlassPane() {462return getRootPane().getGlassPane();463}464465466/*467* Notifies client toolkit that it should change a cursor.468*469* Called from the peer via SwingAccessor, because the470* Component.updateCursorImmediately method is final471* and could not be overridden.472*/473private void updateClientCursor() {474Point p = MouseInfo.getPointerInfo().getLocation();475SwingUtilities.convertPointFromScreen(p, this);476Component target = SwingUtilities.getDeepestComponentAt(this, p.x, p.y);477if (target != null) {478content.setCursor(target.getCursor());479}480}481482//Called by reflection by SwingNode483public void overrideNativeWindowHandle(long handle, Runnable closeWindow) {484final Object peer = AWTAccessor.getComponentAccessor().getPeer(this);485if (peer instanceof OverrideNativeWindowHandle) {486((OverrideNativeWindowHandle) peer).overrideWindowHandle(handle);487}488if (closeWindow != null) {489closeWindow.run();490}491}492493public <T extends DragGestureRecognizer> T createDragGestureRecognizer(494Class<T> abstractRecognizerClass,495DragSource ds, Component c, int srcActions,496DragGestureListener dgl)497{498return content == null ? null : content.createDragGestureRecognizer(499abstractRecognizerClass, ds, c, srcActions, dgl);500}501502public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException {503return content == null ? null : content.createDragSourceContextPeer(dge);504}505506public void addDropTarget(DropTarget dt) {507if (content == null) return;508content.addDropTarget(dt);509}510511public void removeDropTarget(DropTarget dt) {512if (content == null) return;513content.removeDropTarget(dt);514}515}516517518