1 /*
   2  * Copyright (c) 1996, 2015, 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.windows;
  27 
  28 import sun.awt.*;
  29 import java.awt.*;
  30 import java.awt.event.InvocationEvent;
  31 import java.awt.peer.ComponentPeer;
  32 import java.awt.image.*;
  33 
  34 import sun.awt.image.ByteInterleavedRaster;
  35 import sun.security.action.GetPropertyAction;
  36 
  37 import java.awt.peer.FramePeer;
  38 import java.security.PrivilegedAction;
  39 import  java.security.AccessController;
  40 
  41 @SuppressWarnings("serial") // JDK-implementation class
  42 public class WEmbeddedFrame extends EmbeddedFrame {
  43 
  44     static {
  45         initIDs();
  46     }
  47 
  48     private long handle;
  49 
  50     private int bandWidth = 0;
  51     private int bandHeight = 0;
  52     private int imgWid = 0;
  53     private int imgHgt = 0;
  54 
  55     private static int pScale = 0;
  56     private static final int MAX_BAND_SIZE = (1024*30);
  57 
  58     /**
  59      * This flag is set to {@code true} if this embedded frame is hosted by Internet Explorer.
  60      */
  61     private boolean isEmbeddedInIE = false;
  62 
  63     private static String printScale = AccessController.doPrivileged(
  64         new GetPropertyAction("sun.java2d.print.pluginscalefactor"));
  65 
  66     public WEmbeddedFrame() {
  67         this((long)0);
  68     }
  69 
  70     /**
  71      * @deprecated This constructor will be removed in 1.5
  72      */
  73     @Deprecated
  74     public WEmbeddedFrame(int handle) {
  75         this((long)handle);
  76     }
  77 
  78     public WEmbeddedFrame(long handle) {
  79         this.handle = handle;
  80         if (handle != 0) {
  81             addNotify();
  82             show();
  83         }
  84     }
  85 
  86     public void addNotify() {
  87         if (!isDisplayable()) {
  88             WToolkit toolkit = (WToolkit)Toolkit.getDefaultToolkit();
  89             setPeer(toolkit.createEmbeddedFrame(this));
  90         }
  91         super.addNotify();
  92     }
  93 
  94     /*
  95      * Get the native handle
  96     */
  97     public long getEmbedderHandle() {
  98         return handle;
  99     }
 100 
 101     /*
 102      * Print the embedded frame and its children using the specified HDC.
 103      */
 104 
 105     void print(long hdc) {
 106         BufferedImage bandImage = null;
 107 
 108         int xscale = 1;
 109         int yscale = 1;
 110 
 111         /* Is this is either a printer DC or an enhanced meta file DC ?
 112          * Mozilla passes in a printer DC, IE passes plug-in a DC for an
 113          * enhanced meta file. Its possible we may be passed to a memory
 114          * DC. If we here create a larger image, draw in to it and have
 115          * that memory DC then lose the image resolution only to scale it
 116          * back up again when sending to a printer it will look really bad.
 117          * So, is this is either a printer DC or an enhanced meta file DC ?
 118          * Scale only if it is. Use a 4x scale factor, partly since for
 119          * an enhanced meta file we don't know anything about the
 120          * real resolution of the destination.
 121          *
 122          * For a printer DC we could probably derive the scale factor to use
 123          * by querying LOGPIXELSX/Y, and dividing that by the screen
 124          * resolution (typically 96 dpi or 120 dpi) but that would typically
 125          * make for even bigger output for marginal extra quality.
 126          * But for enhanced meta file we don't know anything about the
 127          * real resolution of the destination so
 128          */
 129         if (isPrinterDC(hdc)) {
 130             xscale = yscale = getPrintScaleFactor();
 131         }
 132 
 133         int frameHeight = getHeight();
 134         if (bandImage == null) {
 135             bandWidth = getWidth();
 136             if (bandWidth % 4 != 0) {
 137                 bandWidth += (4 - (bandWidth % 4));
 138             }
 139             if (bandWidth <= 0) {
 140                 return;
 141             }
 142 
 143             bandHeight = Math.min(MAX_BAND_SIZE/bandWidth, frameHeight);
 144 
 145             imgWid = bandWidth * xscale;
 146             imgHgt = bandHeight * yscale;
 147             bandImage = new BufferedImage(imgWid, imgHgt,
 148                                           BufferedImage.TYPE_3BYTE_BGR);
 149         }
 150 
 151         Graphics clearGraphics = bandImage.getGraphics();
 152         clearGraphics.setColor(Color.white);
 153         Graphics2D g2d = (Graphics2D)bandImage.getGraphics();
 154         g2d.translate(0, imgHgt);
 155         g2d.scale(xscale, -yscale);
 156 
 157         ByteInterleavedRaster ras = (ByteInterleavedRaster)bandImage.getRaster();
 158         byte[] data = ras.getDataStorage();
 159 
 160         for (int bandTop = 0; bandTop < frameHeight; bandTop += bandHeight) {
 161             clearGraphics.fillRect(0, 0, bandWidth, bandHeight);
 162 
 163             printComponents(g2d);
 164             int imageOffset =0;
 165             int currBandHeight = bandHeight;
 166             int currImgHeight = imgHgt;
 167             if ((bandTop+bandHeight) > frameHeight) {
 168                 // last band
 169                 currBandHeight = frameHeight - bandTop;
 170                 currImgHeight = currBandHeight*yscale;
 171 
 172                 // multiply by 3 because the image is a 3 byte BGR
 173                 imageOffset = imgWid*(imgHgt-currImgHeight)*3;
 174             }
 175 
 176             printBand(hdc, data, imageOffset,
 177                       0, 0, imgWid, currImgHeight,
 178                       0, bandTop, bandWidth, currBandHeight);
 179             g2d.translate(0, -bandHeight);
 180         }
 181     }
 182 
 183     protected static int getPrintScaleFactor() {
 184         // check if value is already cached
 185         if (pScale != 0)
 186             return pScale;
 187         if (printScale == null) {
 188             // if no system property is specified,
 189             // check for environment setting
 190             printScale = AccessController.doPrivileged(
 191                 new PrivilegedAction<String>() {
 192                     public String run() {
 193                         return System.getenv("JAVA2D_PLUGIN_PRINT_SCALE");
 194                     }
 195                 }
 196             );
 197         }
 198         int default_printDC_scale = 4;
 199         int scale = default_printDC_scale;
 200         if (printScale != null) {
 201             try {
 202                 scale = Integer.parseInt(printScale);
 203                 if (scale > 8 || scale < 1) {
 204                     scale = default_printDC_scale;
 205                 }
 206             } catch (NumberFormatException nfe) {
 207             }
 208         }
 209         pScale = scale;
 210         return pScale;
 211     }
 212 
 213 
 214     private native boolean isPrinterDC(long hdc);
 215 
 216     private native void printBand(long hdc, byte[] data, int offset, int sx,
 217                                   int sy, int swidth, int sheight, int dx,
 218                                   int dy, int dwidth, int dheight);
 219 
 220     /**
 221      * Initialize JNI field IDs
 222      */
 223     private static native void initIDs();
 224 
 225     /**
 226      * This method is called from the native code when this embedded
 227      * frame should be activated. It is expected to be overridden in
 228      * subclasses, for example, in plugin to activate the browser
 229      * window that contains this embedded frame.
 230      *
 231      * NOTE: This method may be called by privileged threads.
 232      *     DO NOT INVOKE CLIENT CODE ON THIS THREAD!
 233      */
 234     public void activateEmbeddingTopLevel() {
 235     }
 236 
 237     public void synthesizeWindowActivation(final boolean activate) {
 238         final FramePeer peer = AWTAccessor.getComponentAccessor().getPeer(this);
 239         if (!activate || EventQueue.isDispatchThread()) {
 240             peer.emulateActivation(activate);
 241         } else {
 242             // To avoid focus concurrence b/w IE and EmbeddedFrame
 243             // activation is postponed by means of posting it to EDT.
 244             Runnable r = new Runnable() {
 245                 public void run() {
 246                     peer.emulateActivation(true);
 247                 }
 248             };
 249             WToolkit.postEvent(WToolkit.targetToAppContext(this),
 250                                new InvocationEvent(this, r));
 251         }
 252     }
 253 
 254     public boolean requestFocusToEmbedder() {
 255         if (isEmbeddedInIE) {
 256             final WEmbeddedFramePeer peer = AWTAccessor.getComponentAccessor()
 257                                                        .getPeer(this);
 258             return peer.requestFocusToEmbedder();
 259         }
 260         return false;
 261     }
 262 
 263     public void registerAccelerator(AWTKeyStroke stroke) {}
 264     public void unregisterAccelerator(AWTKeyStroke stroke) {}
 265 
 266     /**
 267      * Should be overridden in subclasses. Call to
 268      *     super.notifyModalBlocked(blocker, blocked) must be present
 269      *     when overriding.
 270      * It may occur that embedded frame is not put into its
 271      *     container at the moment when it is blocked, for example,
 272      *     when running an applet in IE. Then the call to this method
 273      *     should be delayed until embedded frame is reparented.
 274      *
 275      * NOTE: This method may be called by privileged threads.
 276      *     DO NOT INVOKE CLIENT CODE ON THIS THREAD!
 277      */
 278     public void notifyModalBlocked(Dialog blocker, boolean blocked) {
 279         try {
 280             ComponentPeer thisPeer = (ComponentPeer)WToolkit.targetToPeer(this);
 281             ComponentPeer blockerPeer = (ComponentPeer)WToolkit.targetToPeer(blocker);
 282             notifyModalBlockedImpl((WEmbeddedFramePeer)thisPeer,
 283                                    (WWindowPeer)blockerPeer, blocked);
 284         } catch (Exception z) {
 285             z.printStackTrace(System.err);
 286         }
 287     }
 288     native void notifyModalBlockedImpl(WEmbeddedFramePeer peer, WWindowPeer blockerPeer, boolean blocked);
 289 }