Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/macosx/native_NOTIOS/sun/awt/CGraphicsDevice.m
38829 views
/*1* Copyright (c) 2012, 2019, 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*/2425#import "LWCToolkit.h"26#import "ThreadUtilities.h"2728/*29* Convert the mode string to the more convinient bits per pixel value30*/31static int getBPPFromModeString(CFStringRef mode)32{33if ((CFStringCompare(mode, CFSTR(kIO30BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {34// This is a strange mode, where we using 10 bits per RGB component and pack it into 32 bits35// Java is not ready to work with this mode but we have to specify it as supported36return 30;37}38else if (CFStringCompare(mode, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {39return 32;40}41else if (CFStringCompare(mode, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {42return 16;43}44else if (CFStringCompare(mode, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {45return 8;46}4748return 0;49}5051static BOOL isValidDisplayMode(CGDisplayModeRef mode){52return (1 < CGDisplayModeGetWidth(mode) && 1 < CGDisplayModeGetHeight(mode));53}5455static CFMutableArrayRef getAllValidDisplayModes(jint displayID){56CFArrayRef allModes = CGDisplayCopyAllDisplayModes(displayID, NULL);5758CFIndex numModes = CFArrayGetCount(allModes);59CFMutableArrayRef validModes = CFArrayCreateMutable(kCFAllocatorDefault, numModes + 1, &kCFTypeArrayCallBacks);6061CFIndex n;62for (n=0; n < numModes; n++) {63CGDisplayModeRef cRef = (CGDisplayModeRef) CFArrayGetValueAtIndex(allModes, n);64if (cRef != NULL && isValidDisplayMode(cRef)) {65CFArrayAppendValue(validModes, cRef);66}67}68CFRelease(allModes);6970CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(displayID);7172BOOL containsCurrentMode = NO;73numModes = CFArrayGetCount(validModes);74for (n=0; n < numModes; n++) {75if(CFArrayGetValueAtIndex(validModes, n) == currentMode){76containsCurrentMode = YES;77break;78}79}8081if (!containsCurrentMode) {82CFArrayAppendValue(validModes, currentMode);83}84CGDisplayModeRelease(currentMode);8586return validModes;87}8889/*90* Find the best possible match in the list of display modes that we can switch to based on91* the provided parameters.92*/93static CGDisplayModeRef getBestModeForParameters(CFArrayRef allModes, int w, int h, int bpp, int refrate) {94CGDisplayModeRef bestGuess = NULL;95CFIndex numModes = CFArrayGetCount(allModes), n;9697for(n = 0; n < numModes; n++ ) {98CGDisplayModeRef cRef = (CGDisplayModeRef) CFArrayGetValueAtIndex(allModes, n);99if(cRef == NULL) {100continue;101}102CFStringRef modeString = CGDisplayModeCopyPixelEncoding(cRef);103int thisBpp = getBPPFromModeString(modeString);104CFRelease(modeString);105int thisH = (int)CGDisplayModeGetHeight(cRef);106int thisW = (int)CGDisplayModeGetWidth(cRef);107if (thisBpp != bpp || thisH != h || thisW != w) {108// One of the key parameters does not match109continue;110}111112if (refrate == 0) { // REFRESH_RATE_UNKNOWN113return cRef;114}115116// Refresh rate might be 0 in display mode and we ask for specific display rate117// but if we do not find exact match then 0 refresh rate might be just Ok118int thisRefrate = (int)CGDisplayModeGetRefreshRate(cRef);119if (thisRefrate == refrate) {120// Exact match121return cRef;122}123if (thisRefrate == 0) {124// Not exactly what was asked for, but may fit our needs if we don't find an exact match125bestGuess = cRef;126}127}128return bestGuess;129}130131/*132* Create a new java.awt.DisplayMode instance based on provided CGDisplayModeRef133*/134static jobject createJavaDisplayMode(CGDisplayModeRef mode, JNIEnv *env, jint displayID) {135jobject ret = NULL;136jint h, w, bpp, refrate;137JNF_COCOA_ENTER(env);138CFStringRef currentBPP = CGDisplayModeCopyPixelEncoding(mode);139bpp = getBPPFromModeString(currentBPP);140refrate = CGDisplayModeGetRefreshRate(mode);141h = CGDisplayModeGetHeight(mode);142w = CGDisplayModeGetWidth(mode);143CFRelease(currentBPP);144static JNF_CLASS_CACHE(jc_DisplayMode, "java/awt/DisplayMode");145static JNF_CTOR_CACHE(jc_DisplayMode_ctor, jc_DisplayMode, "(IIII)V");146ret = JNFNewObject(env, jc_DisplayMode_ctor, w, h, bpp, refrate);147JNF_COCOA_EXIT(env);148return ret;149}150151152/*153* Class: sun_awt_CGraphicsDevice154* Method: nativeGetXResolution155* Signature: (I)D156*/157JNIEXPORT jdouble JNICALL158Java_sun_awt_CGraphicsDevice_nativeGetXResolution159(JNIEnv *env, jclass class, jint displayID)160{161// TODO: this is the physically correct answer, but we probably want162// to use NSScreen API instead...163CGSize size = CGDisplayScreenSize(displayID);164CGRect rect = CGDisplayBounds(displayID);165// 1 inch == 25.4 mm166jfloat inches = size.width / 25.4f;167jfloat dpi = rect.size.width / inches;168return dpi;169}170171/*172* Class: sun_awt_CGraphicsDevice173* Method: nativeGetYResolution174* Signature: (I)D175*/176JNIEXPORT jdouble JNICALL177Java_sun_awt_CGraphicsDevice_nativeGetYResolution178(JNIEnv *env, jclass class, jint displayID)179{180// TODO: this is the physically correct answer, but we probably want181// to use NSScreen API instead...182CGSize size = CGDisplayScreenSize(displayID);183CGRect rect = CGDisplayBounds(displayID);184// 1 inch == 25.4 mm185jfloat inches = size.height / 25.4f;186jfloat dpi = rect.size.height / inches;187return dpi;188}189190/*191* Class: sun_awt_CGraphicsDevice192* Method: nativeGetScreenInsets193* Signature: (I)D194*/195JNIEXPORT jobject JNICALL196Java_sun_awt_CGraphicsDevice_nativeGetScreenInsets197(JNIEnv *env, jclass class, jint displayID)198{199jobject ret = NULL;200__block NSRect frame = NSZeroRect;201__block NSRect visibleFrame = NSZeroRect;202JNF_COCOA_ENTER(env);203204[ThreadUtilities performOnMainThreadWaiting:YES block:^(){205NSArray *screens = [NSScreen screens];206for (NSScreen *screen in screens) {207NSDictionary *screenInfo = [screen deviceDescription];208NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"];209if ([screenID pointerValue] == displayID){210frame = [screen frame];211visibleFrame = [screen visibleFrame];212break;213}214}215}];216// Convert between Cocoa's coordinate system and Java.217jint bottom = visibleFrame.origin.y - frame.origin.y;218jint top = frame.size.height - visibleFrame.size.height - bottom;219jint left = visibleFrame.origin.x - frame.origin.x;220jint right = frame.size.width - visibleFrame.size.width - left;221222static JNF_CLASS_CACHE(jc_Insets, "java/awt/Insets");223static JNF_CTOR_CACHE(jc_Insets_ctor, jc_Insets, "(IIII)V");224ret = JNFNewObject(env, jc_Insets_ctor, top, left, bottom, right);225226JNF_COCOA_EXIT(env);227228return ret;229}230231/*232* Class: sun_awt_CGraphicsDevice233* Method: nativeSetDisplayMode234* Signature: (IIIII)V235*/236JNIEXPORT void JNICALL237Java_sun_awt_CGraphicsDevice_nativeSetDisplayMode238(JNIEnv *env, jclass class, jint displayID, jint w, jint h, jint bpp, jint refrate)239{240JNF_COCOA_ENTER(env);241CFArrayRef allModes = getAllValidDisplayModes(displayID);242CGDisplayModeRef closestMatch = getBestModeForParameters(allModes, (int)w, (int)h, (int)bpp, (int)refrate);243244__block CGError retCode = kCGErrorSuccess;245if (closestMatch != NULL) {246CGDisplayModeRetain(closestMatch);247[ThreadUtilities performOnMainThreadWaiting:YES block:^(){248CGDisplayConfigRef config;249retCode = CGBeginDisplayConfiguration(&config);250if (retCode == kCGErrorSuccess) {251CGConfigureDisplayWithDisplayMode(config, displayID, closestMatch, NULL);252retCode = CGCompleteDisplayConfiguration(config, kCGConfigureForAppOnly);253}254CGDisplayModeRelease(closestMatch);255}];256} else {257[JNFException raise:env as:kIllegalArgumentException reason:"Invalid display mode"];258}259260if (retCode != kCGErrorSuccess){261[JNFException raise:env as:kIllegalArgumentException reason:"Unable to set display mode!"];262}263CFRelease(allModes);264JNF_COCOA_EXIT(env);265}266/*267* Class: sun_awt_CGraphicsDevice268* Method: nativeGetDisplayMode269* Signature: (I)Ljava/awt/DisplayMode270*/271JNIEXPORT jobject JNICALL272Java_sun_awt_CGraphicsDevice_nativeGetDisplayMode273(JNIEnv *env, jclass class, jint displayID)274{275jobject ret = NULL;276CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(displayID);277ret = createJavaDisplayMode(currentMode, env, displayID);278CGDisplayModeRelease(currentMode);279return ret;280}281282/*283* Class: sun_awt_CGraphicsDevice284* Method: nativeGetDisplayMode285* Signature: (I)[Ljava/awt/DisplayModes286*/287JNIEXPORT jobjectArray JNICALL288Java_sun_awt_CGraphicsDevice_nativeGetDisplayModes289(JNIEnv *env, jclass class, jint displayID)290{291jobjectArray jreturnArray = NULL;292JNF_COCOA_ENTER(env);293CFArrayRef allModes = getAllValidDisplayModes(displayID);294295CFIndex numModes = CFArrayGetCount(allModes);296static JNF_CLASS_CACHE(jc_DisplayMode, "java/awt/DisplayMode");297298jreturnArray = JNFNewObjectArray(env, &jc_DisplayMode, (jsize) numModes);299if (!jreturnArray) {300NSLog(@"CGraphicsDevice can't create java array of DisplayMode objects");301return nil;302}303304CFIndex n;305for (n=0; n < numModes; n++) {306CGDisplayModeRef cRef = (CGDisplayModeRef) CFArrayGetValueAtIndex(allModes, n);307if (cRef != NULL) {308jobject oneMode = createJavaDisplayMode(cRef, env, displayID);309(*env)->SetObjectArrayElement(env, jreturnArray, n, oneMode);310if ((*env)->ExceptionOccurred(env)) {311(*env)->ExceptionDescribe(env);312(*env)->ExceptionClear(env);313continue;314}315(*env)->DeleteLocalRef(env, oneMode);316}317}318CFRelease(allModes);319JNF_COCOA_EXIT(env);320321return jreturnArray;322}323324/*325* Class: sun_awt_CGraphicsDevice326* Method: nativeGetScaleFactor327* Signature: (I)D328*/329JNIEXPORT jdouble JNICALL330Java_sun_awt_CGraphicsDevice_nativeGetScaleFactor331(JNIEnv *env, jclass class, jint displayID)332{333__block jdouble ret = 1.0f;334335JNF_COCOA_ENTER(env);336337[ThreadUtilities performOnMainThreadWaiting:YES block:^(){338NSArray *screens = [NSScreen screens];339for (NSScreen *screen in screens) {340NSDictionary *screenInfo = [screen deviceDescription];341NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"];342if ([screenID pointerValue] == displayID){343if ([screen respondsToSelector:@selector(backingScaleFactor)]) {344ret = [screen backingScaleFactor];345}346break;347}348}349}];350351JNF_COCOA_EXIT(env);352return ret;353}354355356