1 /*
   2  * Copyright (c) 1996, 2014, 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.awt.image;
  27 
  28 import java.awt.Component;
  29 import java.awt.Color;
  30 import java.awt.SystemColor;
  31 import java.awt.Font;
  32 import java.awt.Graphics;
  33 import java.awt.Graphics2D;
  34 import java.awt.GraphicsConfiguration;
  35 import java.awt.GraphicsEnvironment;
  36 import java.awt.Rectangle;
  37 import java.awt.image.BufferedImage;
  38 import java.awt.image.ImageProducer;
  39 import java.awt.image.ColorModel;
  40 import java.awt.image.DataBuffer;
  41 import java.awt.image.ImageObserver;
  42 import java.awt.image.WritableRaster;
  43 import sun.java2d.SunGraphics2D;
  44 import sun.java2d.loops.SurfaceType;
  45 
  46 /**
  47  * This is a special variant of BufferedImage that keeps a reference to
  48  * a Component.  The Component's foreground and background colors and
  49  * default font are used as the defaults for this image.
  50  */
  51 public class OffScreenImage extends BufferedImage {
  52 
  53     protected Component c;
  54     private OffScreenImageSource osis;
  55     private Font defaultFont;
  56     
  57     // The layout size of the image.
  58     private int width;
  59     private int height;
  60     
  61     // The scale factor which determines the physical size of the raster.
  62     private int scale = 1;
  63     
  64     // Affects the value returned by the size methods.
  65     // When {@code true}, the returned size value matches
  66     // the layout size of the image, otherwise the returned
  67     // size value matches the physical size of the raster,
  68     // which is determined by the scale factor.
  69     private boolean returnLayoutSize;
  70     
  71     /**
  72      * Constructs an OffScreenImage given a color model and tile,
  73      * for offscreen rendering to be used with a given component.
  74      * The component is used to obtain the foreground color, background
  75      * color and font.
  76      */
  77     public OffScreenImage(Component c, ColorModel cm, WritableRaster raster,
  78                           boolean isRasterPremultiplied)
  79     {
  80         super(cm, raster, isRasterPremultiplied, null);
  81         this.c = c;
  82         initSurface(raster.getWidth(), raster.getHeight());
  83     }
  84     
  85     private OffScreenImage(Component c, ColorModel cm, WritableRaster raster,
  86                            boolean isRasterPremultiplied,
  87                            int width, int height,
  88                            int scale)
  89     {
  90         this(c, cm, raster, isRasterPremultiplied);
  91         this.width = width;
  92         this.height = height;
  93         this.scale = scale;
  94     }
  95     
  96     /**
  97      * Constructs an OffScreenImage with the {@code scale} factor.
  98      * The scale determines the physical size of the raster, compared
  99      * to the layout {@code width/height} size of the image.
 100      */
 101     public OffScreenImage(Component c, int width, int height,
 102                           int imageType,
 103                           int scale)
 104     {
 105          super(width * scale, height * scale, imageType);
 106          this.c = c;
 107          this.width = width;
 108          this.height = height;
 109          this.scale = scale;
 110     }  
 111     
 112     /**
 113      * Constructs an OffScreenImage with the {@code scale} factor.
 114      * The scale determines the physical size of the raster, compared
 115      * to the layout {@code width/height} size of the image.
 116      */
 117     public static OffScreenImage create(Component c, GraphicsConfiguration gc,
 118                                         int width, int height,
 119                                         int transparency,
 120                                         int scale)
 121     {
 122         ColorModel cm = gc.getColorModel(transparency);
 123         WritableRaster wr = cm.createCompatibleWritableRaster(width * scale, height * scale);
 124         return new OffScreenImage(c, cm, wr, cm.isAlphaPremultiplied(),
 125                                   width, height, scale);        
 126     }
 127     
 128     /**
 129      * Sets whether the {@code getWidth/Height} methods should
 130      * return the layout or physical size of the image.
 131      * @param value 
 132      */
 133     public void setReturnLayoutSize(boolean value) {
 134         returnLayoutSize = value;
 135     }
 136     
 137     /**
 138      * Gets whether the {@code getWidth/Height} methods should
 139      * return the layout or physical size of the image.
 140      * @param value 
 141      */
 142     public boolean isReturnLayoutSize() {
 143         return returnLayoutSize;
 144     }
 145     
 146     @Override
 147     public int getWidth() {
 148         return returnLayoutSize ? width : super.getWidth();
 149     }
 150     
 151     @Override
 152     public int getWidth(ImageObserver o) {
 153         return getWidth();
 154     }
 155     
 156     @Override
 157     public int getHeight() {
 158         return returnLayoutSize ? height : super.getHeight();
 159     }
 160     
 161     @Override
 162     public int getHeight(ImageObserver o) {
 163         return getHeight();
 164     }
 165     
 166     /**
 167      * Gets the layout width of the image.
 168      * 
 169      * @return the layout width of the image
 170      */
 171     public int getLayoutWidth() {
 172         return width;
 173     }
 174     
 175     /**
 176      * Gets the layout height of the image.
 177      * 
 178      * @return the layout height of the image
 179      */
 180     public int getLayoutHeight() {
 181         return height;
 182     }
 183     
 184     /**
 185      * Gets the scale factor used to scale the image on HiDPI devices
 186      * 
 187      * @return the HiDPI scale factor
 188      */
 189     public int getHiDPIScale() {
 190         return scale;
 191     }
 192     
 193     public Graphics getGraphics() {
 194         return createGraphics();
 195     }
 196 
 197     public Graphics2D createGraphics() {
 198         if (c == null) {
 199             GraphicsEnvironment env =
 200                 GraphicsEnvironment.getLocalGraphicsEnvironment();
 201             return env.createGraphics(this);
 202         }
 203 
 204         Color bg = c.getBackground();
 205         if (bg == null) {
 206             bg = SystemColor.window;
 207         }
 208 
 209         Color fg = c.getForeground();
 210         if (fg == null) {
 211             fg = SystemColor.windowText;
 212         }
 213 
 214         Font font = c.getFont();
 215         if (font == null) {
 216             if (defaultFont == null) {
 217                 defaultFont = new Font("Dialog", Font.PLAIN, 12);
 218             }
 219             font = defaultFont;
 220         }
 221 
 222         return new SunGraphics2D(SurfaceData.getPrimarySurfaceData(this),
 223                                  fg, bg, font);
 224     }
 225 
 226     private void initSurface(int width, int height) {
 227         Graphics2D g2 = createGraphics();
 228         try {
 229             g2.clearRect(0, 0, width, height);
 230         } finally {
 231             g2.dispose();
 232         }
 233     }
 234 
 235     public ImageProducer getSource() {
 236         if (osis == null) {
 237             osis = new OffScreenImageSource(this);
 238         }
 239         return osis;
 240     }
 241     
 242     /**
 243      * Creates a scaled OffScreenImage.
 244      */
 245     public class GraphicsConfig extends BufferedImageGraphicsConfig {
 246         public GraphicsConfig() {
 247             super(OffScreenImage.this, null);
 248         }
 249         
 250         public BufferedImage createCompatibleHiDPIImage(int width, int height, int transparency) {
 251             return OffScreenImage.create(null, this,
 252                                          width, height,
 253                                          transparency,
 254                                          OffScreenImage.this.getHiDPIScale());
 255         }
 256     }
 257     
 258     /**
 259      * Returns correct physical bounds and the scale factor.
 260      */
 261     public class SurfaceData extends BufImgSurfaceData {
 262         public SurfaceData(DataBuffer db, SurfaceType sType) {
 263             super(db, OffScreenImage.this, sType);
 264         }
 265         
 266         @Override
 267         public Rectangle getBounds() {
 268             return new Rectangle(OffScreenImage.this.getRaster().getWidth(),
 269                                  OffScreenImage.this.getRaster().getHeight());
 270         }
 271         
 272         @Override
 273         public int getDefaultScale() {
 274             return OffScreenImage.this.getHiDPIScale();
 275         }
 276     }
 277     
 278     /**
 279      * Backed by a scaled OffScreenImage.
 280      */
 281     public static class VolatileImage extends SunVolatileImage {
 282         public VolatileImage(OffScreenImage.GraphicsConfig graphicsConfig,
 283                              int width, int height,
 284                              int transparency)
 285         {
 286             super(graphicsConfig, width, height, transparency, null);
 287         }
 288         
 289         @Override
 290         public BufferedImage getBackupImage() {
 291             OffScreenImage img = (OffScreenImage)
 292                 ((OffScreenImage.GraphicsConfig)getGraphicsConfig()).
 293                 createCompatibleHiDPIImage(getWidth(), getHeight(), transparency);
 294             img.setReturnLayoutSize(true);
 295             return img;
 296         }
 297     }
 298     
 299 }