1 /*
   2  * Copyright (c) 1999, 2010, 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 LANGID_JA_JP   0x411
 218 #define LANGID_ZH_CN   0x0804
 219 #define LANGID_ZH_SG   0x1004
 220 #define LANGID_ZH_TW   0x0404
 221 #define LANGID_ZH_HK   0x0c04
 222 #define LANGID_ZH_MO   0x1404
 223 #define LANGID_KO_KR   0x0412
 224 
 225 
 226 JNIEXPORT jstring JNICALL
 227 Java_sun_awt_Win32FontManager_getEUDCFontFile(JNIEnv *env, jclass cl) {
 228     int    rc;
 229     HKEY   key;
 230     DWORD  type;
 231     WCHAR  fontPathBuf[MAX_PATH + 1];
 232     unsigned long fontPathLen = MAX_PATH + 1;
 233     WCHAR  tmpPath[MAX_PATH + 1];
 234     LPWSTR fontPath = fontPathBuf;
 235     LPWSTR eudcKey = NULL;
 236 
 237     LANGID langID = GetSystemDefaultLangID();
 238     //lookup for encoding ID, EUDC only supported in
 239     //codepage 932, 936, 949, 950 (and unicode)
 240     if (langID == LANGID_JA_JP) {
 241         eudcKey = EUDCKEY_JA_JP;
 242     } else if (langID == LANGID_ZH_CN || langID == LANGID_ZH_SG) {
 243         eudcKey = EUDCKEY_ZH_CN;
 244     } else if (langID == LANGID_ZH_HK || langID == LANGID_ZH_TW ||
 245                langID == LANGID_ZH_MO) {
 246       eudcKey = EUDCKEY_ZH_TW;
 247     } else if (langID == LANGID_KO_KR) {
 248         eudcKey = EUDCKEY_KO_KR;
 249     } else {
 250         return NULL;
 251     }
 252 
 253     rc = RegOpenKeyEx(HKEY_CURRENT_USER, eudcKey, 0, KEY_READ, &key);
 254     if (rc != ERROR_SUCCESS) {
 255         return NULL;
 256     }
 257     rc = RegQueryValueEx(key,
 258                          L"SystemDefaultEUDCFont",
 259                          0,
 260                          &type,
 261                          (LPBYTE)fontPath,
 262                          &fontPathLen);
 263     RegCloseKey(key);
 264     if (rc != ERROR_SUCCESS || type != REG_SZ) {
 265         return NULL;
 266     }
 267     fontPath[fontPathLen] = L'\0';
 268     if (wcsstr(fontPath, L"%SystemRoot%")) {
 269         //if the fontPath includes %SystemRoot%
 270         LPWSTR systemRoot = _wgetenv(L"SystemRoot");
 271         if (systemRoot != NULL
 272             && swprintf(tmpPath, MAX_PATH, L"%s%s", systemRoot, fontPath + 12) != -1) {
 273             fontPath = tmpPath;
 274         }
 275         else {
 276             return NULL;
 277         }
 278     } else if (wcscmp(fontPath, L"EUDC.TTE") == 0) {
 279         //else to see if it only inludes "EUDC.TTE"
 280         WCHAR systemRoot[MAX_PATH + 1];
 281         if (GetWindowsDirectory(systemRoot, MAX_PATH + 1) != 0) {
 282             swprintf(tmpPath, MAX_PATH, L"%s\\FONTS\\EUDC.TTE", systemRoot);
 283             fontPath = tmpPath;
 284         }
 285         else {
 286             return NULL;
 287         }
 288     }
 289     return JNU_NewStringPlatform(env, fontPath);
 290 }
 291 
 292 /*
 293  * Class:     sun_awt_Win32GraphicsEnvironment
 294  * Method:    getXResolution
 295  * Signature: ()I
 296  */
 297 JNIEXPORT jint JNICALL
 298 Java_sun_awt_Win32GraphicsEnvironment_getXResolution(JNIEnv *env, jobject wge)
 299 {
 300     TRY;
 301 
 302     HWND hWnd = ::GetDesktopWindow();
 303     HDC hDC = ::GetDC(hWnd);
 304     jint result = ::GetDeviceCaps(hDC, LOGPIXELSX);
 305     ::ReleaseDC(hWnd, hDC);
 306     return result;
 307 
 308     CATCH_BAD_ALLOC_RET(0);
 309 }
 310 
 311 /*
 312  * Class:     sun_awt_Win32GraphicsEnvironment
 313  * Method:    getYResolution
 314  * Signature: ()I
 315  */
 316 JNIEXPORT jint JNICALL
 317 Java_sun_awt_Win32GraphicsEnvironment_getYResolution(JNIEnv *env, jobject wge)
 318 {
 319     TRY;
 320 
 321     HWND hWnd = ::GetDesktopWindow();
 322     HDC hDC = ::GetDC(hWnd);
 323     jint result = ::GetDeviceCaps(hDC, LOGPIXELSY);
 324     ::ReleaseDC(hWnd, hDC);
 325     return result;
 326 
 327     CATCH_BAD_ALLOC_RET(0);
 328 }
 329 
 330 /*
 331  * Class:     sun_awt_Win32GraphicsEnvironment
 332  * Method:    isVistaOS
 333  * Signature: ()Z
 334  */
 335 JNIEXPORT jboolean JNICALL Java_sun_awt_Win32GraphicsEnvironment_isVistaOS
 336   (JNIEnv *env, jclass wgeclass)
 337 {
 338     return IS_WINVISTA;
 339 }