blob: 60901a7bfc373a9f487594d529b2aa8a5adb6478 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.internal;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
/**
* This class hold common constants and utility functions w.r.t. to SWT high DPI
* functionality.
* <p>
* The {@code autoScaleUp(..)} methods convert from API coordinates (in
* SWT points) to internal high DPI coordinates (in pixels) that interface with
* native widgets.
* </p>
* <p>
* The {@code autoScaleDown(..)} convert from high DPI pixels to API coordinates
* (in SWT points).
* </p>
*
* @since 3.105
*/
public class DPIUtil {
/* DPI Constants */
static final int DPI_ZOOM_100 = 96;
private static final double MIN_ZOOM_INTERVAL = 25;
private static boolean autoScaleEnable = true;
private static int deviceZoom = 100;
/*
* The AutoScale functionality is enabled by default on HighDPI monitors &
* can be disabled by setting below system property to "false"(Ignore case).
*/
static final String SWT_ENABLE_AUTOSCALE = "swt.enable.autoScale";
static {
String value = System.getProperty (SWT_ENABLE_AUTOSCALE);
if (value != null && "false".equalsIgnoreCase (value))
autoScaleEnable = false;
}
/**
* Auto-scale down ImageData
*/
public static ImageData autoScaleDown (ImageData imageData) {
if (deviceZoom == 100 || !isAutoScaleEnable () || imageData == null) return imageData;
float scaleFactor = getScalingFactor ();
return imageData.scaledTo (Math.round ((float)imageData.width / scaleFactor), Math.round ((float)imageData.height / scaleFactor));
}
public static int[] autoScaleDown(int[] pointArray) {
if (deviceZoom == 100 || !isAutoScaleEnable () || pointArray == null) return pointArray;
float scaleFactor = getScalingFactor ();
int [] returnArray = new int[pointArray.length];
for (int i = 0; i < pointArray.length; i++) {
returnArray [i] = Math.round (pointArray [i] / scaleFactor);
}
return returnArray;
}
/**
* Auto-scale up float array dimensions.
*/
public static float[] autoScaleDown (float size[]) {
if (deviceZoom == 100 || !isAutoScaleEnable () || size == null) return size;
float scaleFactor = getScalingFactor ();
float scaledSize[] = new float[size.length];
for (int i = 0; i < scaledSize.length; i++) {
scaledSize[i] = size[i] / scaleFactor;
}
return scaledSize;
}
/**
* Auto-scale down int dimensions.
*/
public static int autoScaleDown (int size) {
if (deviceZoom == 100 || !isAutoScaleEnable ()||size == SWT.DEFAULT) return size;
float scaleFactor = getScalingFactor ();
return Math.round (size / scaleFactor);
}
/**
* Auto-scale down float dimensions.
*/
public static float autoScaleDown (float size) {
if (deviceZoom == 100 || !isAutoScaleEnable ()||size == SWT.DEFAULT) return size;
float scaleFactor = getScalingFactor ();
return (size / scaleFactor);
}
/**
* Returns a new scaled down Point.
*/
public static Point autoScaleDown (Point point) {
if (deviceZoom == 100 || !isAutoScaleEnable () || point == null) return point;
float scaleFactor = getScalingFactor ();
Point scaledPoint = new Point (0,0);
scaledPoint.x = Math.round (point.x / scaleFactor);
scaledPoint.y = Math.round (point.y / scaleFactor);
return scaledPoint;
}
/**
* Returns a new scaled down Rectangle.
*/
public static Rectangle autoScaleDown (Rectangle rect) {
if (deviceZoom == 100 || !isAutoScaleEnable () || rect == null) return rect;
Rectangle scaledRect = new Rectangle (0,0,0,0);
Point scaledTopLeft = DPIUtil.autoScaleDown (new Point (rect.x, rect.y));
Point scaledBottomRight = DPIUtil.autoScaleDown (new Point (rect.x + rect.width, rect.y + rect.height));
scaledRect.x = scaledTopLeft.x;
scaledRect.y = scaledTopLeft.y;
scaledRect.width = scaledBottomRight.x - scaledTopLeft.x;
scaledRect.height = scaledBottomRight.y - scaledTopLeft.y;
return scaledRect;
}
/**
* Auto-scale image with ImageData
*/
public static ImageData autoScaleImageData (ImageData imageData, int targetZoom, int currentZoom) {
if (!isAutoScaleEnable () || imageData == null || targetZoom == currentZoom) return imageData;
float scaleFactor = ((float) targetZoom)/((float) currentZoom);
return imageData.scaledTo (Math.round ((float)imageData.width * scaleFactor), Math.round ((float)imageData.height * scaleFactor));
}
/**
* Returns a new rectangle as per the scaleFactor.
*/
public static Rectangle autoScaleBounds (Rectangle rect, int targetZoom, int currentZoom) {
if (!isAutoScaleEnable () || rect == null || targetZoom == currentZoom) return rect;
float scaleFactor = ((float)targetZoom) / (float)currentZoom;
Rectangle returnRect = new Rectangle (0,0,0,0);
returnRect.x = Math.round (rect.x * scaleFactor);
returnRect.y = Math.round (rect.y * scaleFactor);
returnRect.width = Math.round (rect.width * scaleFactor);
returnRect.height = Math.round (rect.height * scaleFactor);
return returnRect;
}
/**
* Auto-scale up ImageData
*/
public static ImageData autoScaleUp (ImageData imageData) {
if (deviceZoom == 100 || !isAutoScaleEnable () || imageData == null) return imageData;
float scaleFactor = getScalingFactor ();
return imageData.scaledTo (Math.round ((float)imageData.width * scaleFactor), Math.round ((float)imageData.height * scaleFactor));
}
public static int[] autoScaleUp(int[] pointArray) {
if (deviceZoom == 100 || !isAutoScaleEnable () || pointArray == null) return pointArray;
float scaleFactor = getScalingFactor ();
int [] returnArray = new int[pointArray.length];
for (int i = 0; i < pointArray.length; i++) {
returnArray [i] = Math.round (pointArray [i] * scaleFactor);
}
return returnArray;
}
/**
* Auto-scale up int dimensions.
*/
public static int autoScaleUp (int size) {
if (deviceZoom == 100 || !isAutoScaleEnable ()||size == SWT.DEFAULT) return size;
float scaleFactor = getScalingFactor ();
return Math.round (size * scaleFactor);
}
public static float autoScaleUp(float size) {
if (deviceZoom == 100 || !isAutoScaleEnable ()||size == SWT.DEFAULT) return size;
float scaleFactor = getScalingFactor ();
return (size * scaleFactor);
}
/**
* Returns a new scaled up Point.
*/
public static Point autoScaleUp (Point point) {
if (deviceZoom == 100 || !isAutoScaleEnable () || point == null) return point;
float scaleFactor = getScalingFactor ();
Point scaledPoint = new Point (0,0);
scaledPoint.x = Math.round (point.x * scaleFactor);
scaledPoint.y = Math.round (point.y * scaleFactor);
return scaledPoint;
}
/**
* Returns a new scaled up Rectangle.
*/
public static Rectangle autoScaleUp (Rectangle rect) {
if (deviceZoom == 100 || !isAutoScaleEnable () || rect == null) return rect;
Rectangle scaledRect = new Rectangle (0,0,0,0);
Point scaledTopLeft = DPIUtil.autoScaleUp (new Point (rect.x, rect.y));
Point scaledBottomRight = DPIUtil.autoScaleUp (new Point (rect.x + rect.width, rect.y + rect.height));
scaledRect.x = scaledTopLeft.x;
scaledRect.y = scaledTopLeft.y;
scaledRect.width = scaledBottomRight.x - scaledTopLeft.x;
scaledRect.height = scaledBottomRight.y - scaledTopLeft.y;
return scaledRect;
}
public static boolean isAutoScaleEnable () {
return autoScaleEnable;
}
/**
* Returns Scaling factor from the display
* @return float scaling factor
*/
private static float getScalingFactor () {
float scalingFactor = 1;
if (isAutoScaleEnable ()) {
scalingFactor = getDeviceZoom ()/100f;
}
return scalingFactor;
}
/**
* Compute the zoom value based on the scaleFactor value.
*
* @return zoom
*/
public static int mapSFToZoom (float scaleFactor) {
return mapDPIToZoom ((int) (scaleFactor * DPI_ZOOM_100));
}
/**
* Compute the zoom value based on the DPI value.
*
* @return zoom
*/
public static int mapDPIToZoom (int dpi) {
double zoom = (double)dpi * 100 / DPI_ZOOM_100; //convert to percentage
int roundedZoom = (int) (Math.round (zoom / MIN_ZOOM_INTERVAL) * MIN_ZOOM_INTERVAL); //rounding to MIN_ZOOM_INTERVAL steps
return Math.max(100, roundedZoom); //We are setting the minimum zoom value as 100%. below that it causing too many problems
}
/**
* Gets Image data at specified zoom level, if image is missing then
* fall-back to 100% image. If provider or fall-back image is not available,
* throw error.
*/
public static ImageData validateAndGetImageDataAtZoom (ImageDataProvider provider, int zoom, boolean[] found) {
if (provider == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
ImageData data = provider.getImageData (zoom);
found [0] = (data != null);
/* If image is null when (zoom != 100%), fall-back to image at 100% zoom */
if (zoom != 100 && !found [0]) data = provider.getImageData (100);
if (data == null) SWT.error (SWT.ERROR_INVALID_ARGUMENT);
return data;
}
/**
* Gets Image file path at specified zoom level, if image is missing then
* fall-back to 100% image. If provider or fall-back image is not available,
* throw error.
*/
public static String validateAndGetImagePathAtZoom (ImageFileNameProvider provider, int zoom, boolean[] found) {
if (provider == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
String filename = provider.getImagePath (zoom);
found [0] = (filename != null);
/* If image is null when (zoom != 100%), fall-back to image at 100% zoom */
if (zoom != 100 && !found [0]) filename = provider.getImagePath (100);
if (filename == null) SWT.error (SWT.ERROR_INVALID_ARGUMENT);
return filename;
}
/**
* @return the deviceZoom
*/
public static int getDeviceZoom() {
return isAutoScaleEnable () ? deviceZoom : 100;
}
/**
* @param deviceZoom the deviceZoom to set
*/
public static void setDeviceZoom(int deviceZoom) {
DPIUtil.deviceZoom = deviceZoom;
System.setProperty("org.eclipse.swt.internal.deviceZoom", Integer.toString(deviceZoom));
}
/**
* AutoScale ImageDataProvider.
*/
public static final class AutoScaleImageDataProvider implements ImageDataProvider {
ImageData imageData;
int currentZoom;
public AutoScaleImageDataProvider(ImageData data, int zoom){
this.imageData = data;
this.currentZoom = zoom;
}
@Override
public ImageData getImageData(int zoom) {
return DPIUtil.autoScaleImageData(imageData, zoom, currentZoom);
}
}
}