1 /*
   2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.swing;
  27 
  28 import java.awt.BorderLayout;
  29 import java.awt.Color;
  30 import java.awt.Component;
  31 import java.awt.Container;
  32 import java.awt.EventQueue;
  33 import java.awt.Graphics;
  34 import java.awt.Graphics2D;
  35 import java.awt.Rectangle;
  36 import java.awt.image.BufferedImage;
  37 import java.awt.image.DataBufferInt;
  38 
  39 import javax.swing.JLayeredPane;
  40 import javax.swing.JPanel;
  41 import javax.swing.JRootPane;
  42 import javax.swing.RootPaneContainer;
  43 
  44 import sun.awt.LightweightFrame;
  45 
  46 /**
  47  * The frame serves as a lightweight container which paints its content to an offscreen image
  48  * and provides access to the image's data via the {@link LightweightContent} interface.
  49  * Note, that it may not be shown as a standalone toplevel frame. Its purpose is to provide
  50  * functionality for lightweight embedding.
  51  * 
  52  * @author Artem Ananiev
  53  * @author Anton Tarasov
  54  */
  55 public final class JLightweightFrame extends LightweightFrame implements RootPaneContainer {
  56     
  57     private final JRootPane rootPane = new JRootPane();
  58     
  59     private LightweightContent content;
  60 
  61     private Component component;
  62     private JPanel contentPane;
  63 
  64     private BufferedImage bbImage;
  65     
  66     /**
  67      * Constructs a new, initially invisible {@code JLightweightFrame} instance.
  68      */
  69     public JLightweightFrame() {
  70         super();
  71         add(rootPane, BorderLayout.CENTER);
  72         setBackground(new Color(0, 0, 0, 0));
  73     }
  74     
  75     /**
  76      * Sets the {@link LightweightContent} instance for this frame.
  77      * The {@code JComponent} object returned by the {@link LightweightContent#getComponent()}
  78      * method is immediately added to the frame's content pane.
  79      * 
  80      * @param content the {@link LightweightContent} instance
  81      */
  82     public void setContent(LightweightContent content) {
  83         this.content = content;
  84         this.component = content.getComponent();
  85 
  86         initInterior();
  87     }
  88 
  89     @Override
  90     public Graphics getGraphics() {
  91         if (bbImage == null) return null;
  92         
  93         Graphics2D g = bbImage.createGraphics();
  94         g.setBackground(getBackground());
  95         g.setColor(getForeground());
  96         g.setFont(getFont());
  97         return g;
  98     }
  99     
 100     @Override
 101     public void grabFocus() {
 102         super.grabFocus();
 103         if (content != null) {
 104             content.focusGrabbed();
 105         }
 106     }
 107     
 108     @Override
 109     public void ungrabFocus(boolean postEvent) {
 110         super.ungrabFocus(postEvent);
 111         if (content != null) {
 112             content.focusUngrabbed();
 113         }        
 114     }
 115     
 116     private void initInterior() {
 117         contentPane = new JPanel() {
 118             @Override
 119             public void paint(Graphics g) {
 120                 content.paintLock();
 121                 try {
 122                     super.paint(g);
 123                     
 124                     final Rectangle clip = g.getClipBounds() != null ?
 125                             g.getClipBounds() : new Rectangle(0, 0, contentPane.getWidth(), contentPane.getHeight());
 126 
 127                     clip.x = Math.max(0, clip.x);
 128                     clip.y = Math.max(0, clip.y);
 129                     clip.width = Math.min(contentPane.getWidth(), clip.width);
 130                     clip.height = Math.min(contentPane.getHeight(), clip.height);
 131                     
 132                     EventQueue.invokeLater(new Runnable() {
 133                         @Override
 134                         public void run() {
 135                             content.imageUpdated(clip.x, clip.y, clip.width, clip.height);
 136                         }
 137                     });
 138                 } finally {
 139                     content.paintUnlock();
 140                 }
 141             }
 142             @Override
 143             protected boolean isPaintingOrigin() {
 144                 return true;
 145             }
 146         };
 147         contentPane.setLayout(new BorderLayout());
 148         contentPane.add(component);
 149         setContentPane(contentPane);
 150     }
 151 
 152     @SuppressWarnings("deprecation")
 153     @Override public void reshape(int x, int y, int width, int height) {
 154         super.reshape(x, y, width, height);
 155         
 156         if (width == 0 || height == 0) {
 157             return;
 158         }
 159 
 160         content.paintLock();
 161         try {
 162             if ((bbImage == null) || (width != bbImage.getWidth()) || (height != bbImage.getHeight())) {
 163                 boolean createBB = true;
 164                 int newW = width;
 165                 int newH = height;
 166                 if (bbImage != null) {
 167                     int oldW = bbImage.getWidth();
 168                     int oldH = bbImage.getHeight();
 169                     if ((oldW >= newW) && (oldH >= newH)) {
 170                         createBB = false;
 171                     } else {
 172                         if (oldW >= newW) {
 173                             newW = oldW;
 174                         } else {
 175                             newW = Math.max((int)(oldW * 1.2), width);
 176                         }
 177                         if (oldH >= newH) {
 178                             newH = oldH;
 179                         } else {
 180                             newH = Math.max((int)(oldH * 1.2), height);
 181                         }
 182                     }
 183                 }
 184                 if (createBB) {
 185                     BufferedImage oldBB = bbImage;
 186                     bbImage = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_ARGB_PRE);
 187                     if (oldBB != null) {
 188                         Graphics g = bbImage.getGraphics();
 189                         try {
 190                             g.drawImage(oldBB, 0, 0, newW, newH, null);
 191                         } finally {
 192                             g.dispose();
 193                             oldBB.flush();
 194                         }
 195                     }
 196                     DataBufferInt dataBuf = (DataBufferInt)bbImage.getRaster().getDataBuffer();
 197                     content.imageBufferReset(dataBuf.getData(), 0, 0, width, height, bbImage.getWidth());
 198                 } else {
 199                     content.imageReshaped(0, 0, width, height);
 200                 }
 201             }
 202         } finally {
 203             content.paintUnlock();
 204         }
 205     }
 206 
 207     @Override
 208     public JRootPane getRootPane() {
 209         return rootPane;
 210     }
 211 
 212     @Override
 213     public void setContentPane(Container contentPane) {
 214         getRootPane().setContentPane(contentPane);
 215     }
 216 
 217     @Override
 218     public Container getContentPane() {
 219         return getRootPane().getContentPane();
 220     }
 221 
 222     @Override
 223     public void setLayeredPane(JLayeredPane layeredPane) {
 224         getRootPane().setLayeredPane(layeredPane);
 225     }
 226 
 227     @Override
 228     public JLayeredPane getLayeredPane() {
 229         return getRootPane().getLayeredPane();
 230     }
 231 
 232     @Override
 233     public void setGlassPane(Component glassPane) {
 234         getRootPane().setGlassPane(glassPane);
 235     }
 236 
 237     @Override
 238     public Component getGlassPane() {
 239         return getRootPane().getGlassPane();
 240     }
 241 }