Path: blob/master/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java
41152 views
/*1* Copyright (c) 1997, 2021, 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.java2d;2627import java.awt.AWTError;28import java.awt.Color;29import java.awt.Dimension;30import java.awt.Font;31import java.awt.Graphics2D;32import java.awt.GraphicsConfiguration;33import java.awt.GraphicsDevice;34import java.awt.GraphicsEnvironment;35import java.awt.Insets;36import java.awt.Point;37import java.awt.Rectangle;38import java.awt.Toolkit;39import java.awt.geom.AffineTransform;40import java.awt.image.BufferedImage;41import java.awt.peer.ComponentPeer;42import java.security.AccessController;43import java.util.Locale;44import java.util.TreeMap;4546import sun.awt.DisplayChangedListener;47import sun.awt.SunDisplayChanger;48import sun.font.FontManager;49import sun.font.FontManagerFactory;50import sun.font.FontManagerForSGE;51import sun.java2d.pipe.Region;52import sun.security.action.GetPropertyAction;5354/**55* This is an implementation of a GraphicsEnvironment object for the56* default local GraphicsEnvironment.57*58* @see GraphicsDevice59* @see GraphicsConfiguration60*/61@SuppressWarnings("removal")62public abstract class SunGraphicsEnvironment extends GraphicsEnvironment63implements DisplayChangedListener {6465/** Establish the default font to be used by SG2D. */66private final Font defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12);6768private static final boolean uiScaleEnabled;69private static final double debugScale;7071static {72uiScaleEnabled = "true".equals(AccessController.doPrivileged(73new GetPropertyAction("sun.java2d.uiScale.enabled", "true")));74debugScale = uiScaleEnabled ? getScaleFactor("sun.java2d.uiScale") : -1;75}7677protected GraphicsDevice[] screens;7879/**80* Returns an array of all of the screen devices.81*/82public synchronized GraphicsDevice[] getScreenDevices() {83GraphicsDevice[] ret = screens;84if (ret == null) {85int num = getNumScreens();86ret = new GraphicsDevice[num];87for (int i = 0; i < num; i++) {88ret[i] = makeScreenDevice(i);89}90screens = ret;91}92return ret;93}9495/**96* Returns the number of screen devices of this graphics environment.97*98* @return the number of screen devices of this graphics environment99*/100protected abstract int getNumScreens();101102/**103* Create and return the screen device with the specified number. The104* device with number {@code 0} will be the default device (returned105* by {@link #getDefaultScreenDevice()}.106*107* @param screennum the number of the screen to create108*109* @return the created screen device110*/111protected abstract GraphicsDevice makeScreenDevice(int screennum);112113/**114* Returns the default screen graphics device.115*/116public GraphicsDevice getDefaultScreenDevice() {117GraphicsDevice[] screens = getScreenDevices();118if (screens.length == 0) {119throw new AWTError("no screen devices");120}121return screens[0];122}123124/**125* Returns a Graphics2D object for rendering into the126* given BufferedImage.127* @throws NullPointerException if BufferedImage argument is null128*/129public Graphics2D createGraphics(BufferedImage img) {130if (img == null) {131throw new NullPointerException("BufferedImage cannot be null");132}133SurfaceData sd = SurfaceData.getPrimarySurfaceData(img);134return new SunGraphics2D(sd, Color.white, Color.black, defaultFont);135}136137public static FontManagerForSGE getFontManagerForSGE() {138FontManager fm = FontManagerFactory.getInstance();139return (FontManagerForSGE) fm;140}141142/* Modifies the behaviour of a subsequent call to preferLocaleFonts()143* to use Mincho instead of Gothic for dialoginput in JA locales144* on windows. Not needed on other platforms.145*146* @deprecated as of JDK9. To be removed in a future release147*/148@Deprecated149public static void useAlternateFontforJALocales() {150getFontManagerForSGE().useAlternateFontforJALocales();151}152153/**154* Returns all fonts available in this environment.155*/156public Font[] getAllFonts() {157FontManagerForSGE fm = getFontManagerForSGE();158Font[] installedFonts = fm.getAllInstalledFonts();159Font[] created = fm.getCreatedFonts();160if (created == null || created.length == 0) {161return installedFonts;162} else {163int newlen = installedFonts.length + created.length;164Font [] fonts = java.util.Arrays.copyOf(installedFonts, newlen);165System.arraycopy(created, 0, fonts,166installedFonts.length, created.length);167return fonts;168}169}170171public String[] getAvailableFontFamilyNames(Locale requestedLocale) {172FontManagerForSGE fm = getFontManagerForSGE();173String[] installed = fm.getInstalledFontFamilyNames(requestedLocale);174/* Use a new TreeMap as used in getInstalledFontFamilyNames175* and insert all the keys in lower case, so that the sort order176* is the same as the installed families. This preserves historical177* behaviour and inserts new families in the right place.178* It would have been marginally more efficient to directly obtain179* the tree map and just insert new entries, but not so much as180* to justify the extra internal interface.181*/182TreeMap<String, String> map = fm.getCreatedFontFamilyNames();183if (map == null || map.size() == 0) {184return installed;185} else {186for (int i=0; i<installed.length; i++) {187map.put(installed[i].toLowerCase(requestedLocale),188installed[i]);189}190String[] retval = new String[map.size()];191Object [] keyNames = map.keySet().toArray();192for (int i=0; i < keyNames.length; i++) {193retval[i] = map.get(keyNames[i]);194}195return retval;196}197}198199public String[] getAvailableFontFamilyNames() {200return getAvailableFontFamilyNames(Locale.getDefault());201}202203/**204* Return the bounds of a GraphicsDevice, less its screen insets.205* See also java.awt.GraphicsEnvironment.getUsableBounds();206*/207public static Rectangle getUsableBounds(GraphicsDevice gd) {208GraphicsConfiguration gc = gd.getDefaultConfiguration();209Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);210Rectangle usableBounds = gc.getBounds();211212usableBounds.x += insets.left;213usableBounds.y += insets.top;214usableBounds.width -= (insets.left + insets.right);215usableBounds.height -= (insets.top + insets.bottom);216217return usableBounds;218}219220/**221* From the DisplayChangedListener interface; called222* when the display mode has been changed.223*/224public void displayChanged() {225// notify screens in device array to do display update stuff226for (GraphicsDevice gd : getScreenDevices()) {227if (gd instanceof DisplayChangedListener) {228((DisplayChangedListener) gd).displayChanged();229}230}231232// notify SunDisplayChanger list (e.g. VolatileSurfaceManagers and233// SurfaceDataProxies) about the display change event234displayChanger.notifyListeners();235}236237/**238* Part of the DisplayChangedListener interface:239* propagate this event to listeners240*/241public void paletteChanged() {242displayChanger.notifyPaletteChanged();243}244245/**246* Returns true when the display is local, false for remote displays.247*248* @return true when the display is local, false for remote displays249*/250public abstract boolean isDisplayLocal();251252/*253* ----DISPLAY CHANGE SUPPORT----254*/255256protected SunDisplayChanger displayChanger = new SunDisplayChanger();257258/**259* Add a DisplayChangeListener to be notified when the display settings260* are changed.261*/262public void addDisplayChangedListener(DisplayChangedListener client) {263displayChanger.add(client);264}265266/**267* Remove a DisplayChangeListener from Win32GraphicsEnvironment268*/269public void removeDisplayChangedListener(DisplayChangedListener client) {270displayChanger.remove(client);271}272273/*274* ----END DISPLAY CHANGE SUPPORT----275*/276277/**278* Returns true if FlipBufferStrategy with COPIED buffer contents279* is preferred for this peer's GraphicsConfiguration over280* BlitBufferStrategy, false otherwise.281*282* The reason FlipBS could be preferred is that in some configurations283* an accelerated copy to the screen is supported (like Direct3D 9)284*285* @return true if flip strategy should be used, false otherwise286*/287public boolean isFlipStrategyPreferred(ComponentPeer peer) {288return false;289}290291public static boolean isUIScaleEnabled() {292return uiScaleEnabled;293}294295public static double getDebugScale() {296return debugScale;297}298299public static double getScaleFactor(String propertyName) {300301String scaleFactor = AccessController.doPrivileged(302new GetPropertyAction(propertyName, "-1"));303304if (scaleFactor == null || scaleFactor.equals("-1")) {305return -1;306}307308try {309double units = 1.0;310311if (scaleFactor.endsWith("x")) {312scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 1);313} else if (scaleFactor.endsWith("dpi")) {314units = 96;315scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 3);316} else if (scaleFactor.endsWith("%")) {317units = 100;318scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 1);319}320321double scale = Double.parseDouble(scaleFactor);322return scale <= 0 ? -1 : scale / units;323} catch (NumberFormatException ignored) {324return -1;325}326}327328/**329* Returns the graphics configuration which bounds contain the given point.330*331* @param current the default configuration which is checked in the first332* place333* @param x the x coordinate of the given point334* @param y the y coordinate of the given point335* @return the graphics configuration336*/337public static GraphicsConfiguration getGraphicsConfigurationAtPoint(338GraphicsConfiguration current, double x, double y) {339if (current.getBounds().contains(x, y)) {340return current;341}342GraphicsEnvironment env = getLocalGraphicsEnvironment();343for (GraphicsDevice device : env.getScreenDevices()) {344GraphicsConfiguration config = device.getDefaultConfiguration();345if (config.getBounds().contains(x, y)) {346return config;347}348}349return current;350}351352/**353* Returns the bounds of the graphics configuration in device space.354*355* @param config the graphics configuration which bounds are requested356* @return the bounds of the area covered by this357* {@code GraphicsConfiguration} in device space (pixels)358*/359public static Rectangle getGCDeviceBounds(GraphicsConfiguration config) {360AffineTransform tx = config.getDefaultTransform();361Rectangle bounds = config.getBounds();362bounds.width *= tx.getScaleX();363bounds.height *= tx.getScaleY();364return bounds;365}366367/**368* Converts the size (w, h) from the device space to the user's space using369* passed graphics configuration.370*371* @param gc the graphics configuration to be used for transformation372* @param w the width in the device space373* @param h the height in the device space374* @return the size in the user's space375*/376public static Dimension toUserSpace(GraphicsConfiguration gc,377int w, int h) {378AffineTransform tx = gc.getDefaultTransform();379return new Dimension(380Region.clipRound(w / tx.getScaleX()),381Region.clipRound(h / tx.getScaleY())382);383}384385/**386* Converts absolute coordinates from the user's space to the device space387* using appropriate device transformation.388*389* @param x absolute coordinate in the user's space390* @param y absolute coordinate in the user's space391* @return the point which uses device space (pixels)392*/393public static Point toDeviceSpaceAbs(int x, int y) {394GraphicsConfiguration gc = getLocalGraphicsEnvironment()395.getDefaultScreenDevice().getDefaultConfiguration();396gc = getGraphicsConfigurationAtPoint(gc, x, y);397return toDeviceSpaceAbs(gc, x, y, 0, 0).getLocation();398}399400/**401* Converts the rectangle from the user's space to the device space using402* appropriate device transformation.403*404* @param rect the rectangle in the user's space405* @return the rectangle which uses device space (pixels)406*/407public static Rectangle toDeviceSpaceAbs(Rectangle rect) {408GraphicsConfiguration gc = getLocalGraphicsEnvironment()409.getDefaultScreenDevice().getDefaultConfiguration();410gc = getGraphicsConfigurationAtPoint(gc, rect.x, rect.y);411return toDeviceSpaceAbs(gc, rect.x, rect.y, rect.width, rect.height);412}413414/**415* Converts absolute coordinates (x, y) and the size (w, h) from the user's416* space to the device space using passed graphics configuration.417*418* @param gc the graphics configuration to be used for transformation419* @param x absolute coordinate in the user's space420* @param y absolute coordinate in the user's space421* @param w the width in the user's space422* @param h the height in the user's space423* @return the rectangle which uses device space (pixels)424*/425public static Rectangle toDeviceSpaceAbs(GraphicsConfiguration gc,426int x, int y, int w, int h) {427AffineTransform tx = gc.getDefaultTransform();428Rectangle screen = gc.getBounds();429return new Rectangle(430screen.x + Region.clipRound((x - screen.x) * tx.getScaleX()),431screen.y + Region.clipRound((y - screen.y) * tx.getScaleY()),432Region.clipRound(w * tx.getScaleX()),433Region.clipRound(h * tx.getScaleY())434);435}436437/**438* Converts coordinates from the user's space to the device space using439* appropriate device transformation.440*441* @param x coordinate in the user's space442* @param y coordinate in the user's space443* @return the point which uses device space (pixels)444*/445public static Point toDeviceSpace(int x, int y) {446GraphicsConfiguration gc = getLocalGraphicsEnvironment()447.getDefaultScreenDevice().getDefaultConfiguration();448gc = getGraphicsConfigurationAtPoint(gc, x, y);449return toDeviceSpace(gc, x, y, 0, 0).getLocation();450}451452/**453* Converts coordinates (x, y) and the size (w, h) from the user's454* space to the device space using passed graphics configuration.455*456* @param gc the graphics configuration to be used for transformation457* @param x coordinate in the user's space458* @param y coordinate in the user's space459* @param w the width in the user's space460* @param h the height in the user's space461* @return the rectangle which uses device space (pixels)462*/463public static Rectangle toDeviceSpace(GraphicsConfiguration gc,464int x, int y, int w, int h) {465AffineTransform tx = gc.getDefaultTransform();466return new Rectangle(467Region.clipRound(x * tx.getScaleX()),468Region.clipRound(y * tx.getScaleY()),469Region.clipRound(w * tx.getScaleX()),470Region.clipRound(h * tx.getScaleY())471);472}473}474475476