1 /*
   2  * Copyright (c) 1999, 2011, 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 #include <awt.h>
  27 #include <sun_awt_Win32GraphicsEnvironment.h>
  28 #include <sun_awt_Win32FontManager.h>
  29 #include "awt_Canvas.h"
  30 #include "awt_Win32GraphicsDevice.h"
  31 #include "Devices.h"
  32 #include "WindowsFlags.h"
  33 #include "DllUtil.h"
  34 
  35 BOOL DWMIsCompositionEnabled();
  36 
  37 void initScreens(JNIEnv *env) {
  38 
  39     if (!Devices::UpdateInstance(env)) {
  40         JNU_ThrowInternalError(env, "Could not update the devices array.");
  41         return;
  42     }
  43 }
  44 
  45 /**
  46  * This function attempts to make a Win32 API call to
  47  *   BOOL SetProcessDPIAware(VOID);
  48  * which is only present on Windows Vista, and which instructs the
  49  * Vista Windows Display Manager that this application is High DPI Aware
  50  * and does not need to be scaled by the WDM and lied about the
  51  * actual system dpi.
  52  */
  53 static void
  54 SetProcessDPIAwareProperty()
  55 {
  56     typedef BOOL (WINAPI SetProcessDPIAwareFunc)(void);
  57     static BOOL bAlreadySet = FALSE;
  58 
  59     // setHighDPIAware is set in WindowsFlags.cpp
  60     if (!setHighDPIAware || bAlreadySet) {
  61         return;
  62     }
  63 
  64     bAlreadySet = TRUE;
  65 
  66     HMODULE hLibUser32Dll = ::LoadLibrary(TEXT("user32.dll"));
  67 
  68     if (hLibUser32Dll != NULL) {
  69         SetProcessDPIAwareFunc *lpSetProcessDPIAware =
  70             (SetProcessDPIAwareFunc*)GetProcAddress(hLibUser32Dll,
  71                                                     "SetProcessDPIAware");
  72         if (lpSetProcessDPIAware != NULL) {
  73             lpSetProcessDPIAware();
  74         }
  75         ::FreeLibrary(hLibUser32Dll);
  76     }
  77 }
  78 
  79 #define DWM_COMP_UNDEFINED (~(TRUE|FALSE))
  80 static int dwmIsCompositionEnabled = DWM_COMP_UNDEFINED;
  81 
  82 /**
  83  * This function is called from toolkit event handling code when
  84  * WM_DWMCOMPOSITIONCHANGED event is received
  85  */
  86 void DWMResetCompositionEnabled() {
  87     dwmIsCompositionEnabled = DWM_COMP_UNDEFINED;
  88     (void)DWMIsCompositionEnabled();
  89 }
  90 
  91 /**
  92  * Returns true if dwm composition is enabled, false if it is not applicable
  93  * (if the OS is not Vista) or dwm composition is disabled.
  94  */
  95 BOOL DWMIsCompositionEnabled() {
  96     // cheaper to check than whether it's vista or not
  97     if (dwmIsCompositionEnabled != DWM_COMP_UNDEFINED) {
  98         return (BOOL)dwmIsCompositionEnabled;
  99     }
 100 
 101     if (!IS_WINVISTA) {
 102         dwmIsCompositionEnabled = FALSE;
 103         return FALSE;
 104     }
 105 
 106     BOOL bRes = FALSE;
 107 
 108     try {
 109         BOOL bEnabled;
 110         HRESULT res = DwmAPI::DwmIsCompositionEnabled(&bEnabled);
 111         if (SUCCEEDED(res)) {
 112             bRes = bEnabled;
 113             J2dTraceLn1(J2D_TRACE_VERBOSE, " composition enabled: %d",bRes);
 114         } else {
 115             J2dTraceLn1(J2D_TRACE_ERROR,
 116                     "IsDWMCompositionEnabled: error %x when detecting"\
 117                     "if composition is enabled", res);
 118         }
 119     } catch (const DllUtil::Exception &) {
 120         J2dTraceLn(J2D_TRACE_ERROR,
 121                 "IsDWMCompositionEnabled: no DwmIsCompositionEnabled() "\
 122                 "in dwmapi.dll or dwmapi.dll cannot be loaded");
 123     }
 124 
 125     dwmIsCompositionEnabled = bRes;
 126 
 127     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 128     JNU_CallStaticMethodByName(env, NULL,
 129                               "sun/awt/Win32GraphicsEnvironment",
 130                               "dwmCompositionChanged", "(Z)V", (jboolean)bRes);
 131     return bRes;
 132 }
 133 
 134 /*
 135  * Class:     sun_awt_Win32GraphicsEnvironment
 136  * Method:    initDisplay
 137  * Signature: ()V
 138  */
 139 JNIEXPORT void JNICALL
 140 Java_sun_awt_Win32GraphicsEnvironment_initDisplay(JNIEnv *env,
 141                                                   jclass thisClass)
 142 {
 143     // This method needs to be called prior to any display-related activity
 144     SetProcessDPIAwareProperty();
 145 
 146     DWMIsCompositionEnabled();
 147 
 148     initScreens(env);
 149 }
 150 
 151 /*
 152  * Class:     sun_awt_Win32GraphicsEnvironment
 153  * Method:    getNumScreens
 154  * Signature: ()I
 155  */
 156 JNIEXPORT jint JNICALL
 157 Java_sun_awt_Win32GraphicsEnvironment_getNumScreens(JNIEnv *env,
 158                                                     jobject thisobj)
 159 {
 160     Devices::InstanceAccess devices;
 161     return devices->GetNumDevices();
 162 }
 163 
 164 /*
 165  * Class:     sun_awt_Win32GraphicsEnvironment
 166  * Method:    getDefaultScreen
 167  * Signature: ()I
 168  */
 169 JNIEXPORT jint JNICALL
 170 Java_sun_awt_Win32GraphicsEnvironment_getDefaultScreen(JNIEnv *env,
 171                                                        jobject thisobj)
 172 {
 173     return AwtWin32GraphicsDevice::GetDefaultDeviceIndex();
 174 }
 175 
 176 /*
 177  * Class:     sun_awt_Win32FontManager
 178  * Method:    registerFontWithPlatform
 179  * Signature: (Ljava/lang/String;)V
 180  */
 181 JNIEXPORT void JNICALL
 182 Java_sun_awt_Win32FontManager_registerFontWithPlatform(JNIEnv *env,
 183                                                        jclass cl,
 184                                                        jstring fontName)
 185 {
 186     LPTSTR file = (LPTSTR)JNU_GetStringPlatformChars(env, fontName, JNI_FALSE);
 187     if (file) {
 188         ::AddFontResourceEx(file, FR_PRIVATE, NULL);
 189         JNU_ReleaseStringPlatformChars(env, fontName, file);
 190     }
 191 }
 192 
 193 
 194 /*
 195  * Class:     sun_awt_Win32FontManagerEnvironment
 196  * Method:    deRegisterFontWithPlatform
 197  * Signature: (Ljava/lang/String;)V
 198  *
 199  * This method intended for future use.
 200  */
 201 JNIEXPORT void JNICALL
 202 Java_sun_awt_Win32FontManager_deRegisterFontWithPlatform(JNIEnv *env,
 203                                                          jclass cl,
 204                                                          jstring fontName)
 205 {
 206     LPTSTR file = (LPTSTR)JNU_GetStringPlatformChars(env, fontName, JNI_FALSE);
 207     if (file) {
 208         ::RemoveFontResourceEx(file, FR_PRIVATE, NULL);
 209         JNU_ReleaseStringPlatformChars(env, fontName, file);
 210     }
 211 }
 212 
 213 #define EUDCKEY_JA_JP  L"EUDC\\932"
 214 #define EUDCKEY_ZH_CN  L"EUDC\\936"
 215 #define EUDCKEY_ZH_TW  L"EUDC\\950"
 216 #define EUDCKEY_KO_KR  L"EUDC\\949"
 217 #define EUDCKEY_EN_US  L"EUDC\\1252"
 218 #define LANGID_JA_JP   0x411
 219 #define LANGID_ZH_CN   0x0804
 220 #define LANGID_ZH_SG   0x1004
 221 #define LANGID_ZH_TW   0x0404
 222 #define LANGID_ZH_HK   0x0c04
 223 #define LANGID_ZH_MO   0x1404
 224 #define LANGID_KO_KR   0x0412
 225 #define LANGID_EN_US   0x0409
 226 
 227 
 228 JNIEXPORT jstring JNICALL
 229 Java_sun_awt_Win32FontManager_getEUDCFontFile(JNIEnv *env, jclass cl) {
 230     int    rc;
 231     HKEY   key;
 232     DWORD  type;
 233     WCHAR  fontPathBuf[MAX_PATH + 1];
 234     unsigned long fontPathLen = MAX_PATH + 1;
 235     WCHAR  tmpPath[MAX_PATH + 1];
 236     LPWSTR fontPath = fontPathBuf;
 237     LPWSTR eudcKey = NULL;
 238 
 239     LANGID langID = GetSystemDefaultLangID();
 240     //lookup for encoding ID, EUDC only supported in
 241     //codepage 932, 936, 949, 950 (and unicode)
 242     // On Windows 7, at least for me, it shows up in Cp1252 if
 243     // I create a custom font. Might as well support that as it makes
 244     // verification easier.
 245     if (langID == LANGID_JA_JP) {
 246         eudcKey = EUDCKEY_JA_JP;
 247     } else if (langID == LANGID_ZH_CN || langID == LANGID_ZH_SG) {
 248         eudcKey = EUDCKEY_ZH_CN;
 249     } else if (langID == LANGID_ZH_HK || langID == LANGID_ZH_TW ||
 250                langID == LANGID_ZH_MO) {
 251       eudcKey = EUDCKEY_ZH_TW;
 252     } else if (langID == LANGID_KO_KR) {
 253         eudcKey = EUDCKEY_KO_KR;
 254     } else if (langID == LANGID_EN_US) {
 255         eudcKey = EUDCKEY_EN_US;
 256     } else {
 257         return NULL;
 258     }
 259 
 260     rc = RegOpenKeyEx(HKEY_CURRENT_USER, eudcKey, 0, KEY_READ, &key);
 261     if (rc != ERROR_SUCCESS) {
 262         return NULL;
 263     }
 264     rc = RegQueryValueEx(key,
 265                          L"SystemDefaultEUDCFont",
 266                          0,
 267                          &type,
 268                          (LPBYTE)fontPath,
 269                          &fontPathLen);
 270     RegCloseKey(key);
 271     if (rc != ERROR_SUCCESS || type != REG_SZ) {
 272         return NULL;
 273     }
 274     fontPath[fontPathLen] = L'\0';
 275     if (wcsstr(fontPath, L"%SystemRoot%")) {
 276         //if the fontPath includes %SystemRoot%
 277         LPWSTR systemRoot = _wgetenv(L"SystemRoot");
 278         if (systemRoot != NULL
 279             && swprintf(tmpPath, MAX_PATH, L"%s%s", systemRoot, fontPath + 12) != -1) {
 280             fontPath = tmpPath;
 281         }
 282         else {
 283             return NULL;
 284         }
 285     } else if (wcscmp(fontPath, L"EUDC.TTE") == 0) {
 286         //else to see if it only inludes "EUDC.TTE"
 287         WCHAR systemRoot[MAX_PATH + 1];
 288         if (GetWindowsDirectory(systemRoot, MAX_PATH + 1) != 0) {
 289             swprintf(tmpPath, MAX_PATH, L"%s\\FONTS\\EUDC.TTE", systemRoot);
 290             fontPath = tmpPath;
 291         }
 292         else {
 293             return NULL;
 294         }
 295     }
 296     return JNU_NewStringPlatform(env, fontPath);
 297 }
 298 
 299 /*
 300  * Class:     sun_awt_Win32GraphicsEnvironment
 301  * Method:    getXResolution
 302  * Signature: ()I
 303  */
 304 JNIEXPORT jint JNICALL
 305 Java_sun_awt_Win32GraphicsEnvironment_getXResolution(JNIEnv *env, jobject wge)
 306 {
 307     TRY;
 308 
 309     HWND hWnd = ::GetDesktopWindow();
 310     HDC hDC = ::GetDC(hWnd);
 311     jint result = ::GetDeviceCaps(hDC, LOGPIXELSX);
 312     ::ReleaseDC(hWnd, hDC);
 313     return result;
 314 
 315     CATCH_BAD_ALLOC_RET(0);
 316 }
 317 
 318 /*
 319  * Class:     sun_awt_Win32GraphicsEnvironment
 320  * Method:    getYResolution
 321  * Signature: ()I
 322  */
 323 JNIEXPORT jint JNICALL
 324 Java_sun_awt_Win32GraphicsEnvironment_getYResolution(JNIEnv *env, jobject wge)
 325 {
 326     TRY;
 327 
 328     HWND hWnd = ::GetDesktopWindow();
 329     HDC hDC = ::GetDC(hWnd);
 330     jint result = ::GetDeviceCaps(hDC, LOGPIXELSY);
 331     ::ReleaseDC(hWnd, hDC);
 332     return result;
 333 
 334     CATCH_BAD_ALLOC_RET(0);
 335 }
 336 
 337 /*
 338  * Class:     sun_awt_Win32GraphicsEnvironment
 339  * Method:    isVistaOS
 340  * Signature: ()Z
 341  */
 342 JNIEXPORT jboolean JNICALL Java_sun_awt_Win32GraphicsEnvironment_isVistaOS
 343   (JNIEnv *env, jclass wgeclass)
 344 {
 345     return IS_WINVISTA;
 346 }