1 /*
   2  * Copyright (c) 2003, 2014, 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 "sun_awt_windows_ThemeReader.h"
  27 #include <string.h>
  28 
  29 #include "awt.h"
  30 #include "awt_Toolkit.h"
  31 #include "awt_Object.h"
  32 #include "awt_Component.h"
  33 
  34 #include "math.h"
  35 
  36 // Important note about VC6 and VC7 (or XP Platform SDK)   !
  37 //
  38 // These type definitions have been imported from UxTheme.h
  39 // They have been imported instead of including them, because
  40 // currently we don't require Platform SDK for building J2SE and
  41 // VC6 includes do not have UxTheme.h. When we move to VC7
  42 // we should remove these imports and just include
  43 //
  44 //  Uncomment these when we start using VC 7 (or XP Platform SDK)
  45 //
  46 //  #include <uxtheme.h>
  47 //  #incldue <tmschema.h>
  48 
  49 
  50 // Remove everyting inside this ifdef when we start using VC 7 (or XP Platform SDK)
  51 #ifndef  _UXTHEME_H_
  52 typedef HANDLE HTHEME;          // handle to a section of theme data for class
  53 
  54 typedef enum {
  55     TS_MIN,
  56     TS_TRUE,
  57     TS_DRAW
  58 } THEME_SIZE;
  59 
  60 
  61 // Remove these when we start using VC 7 (or XP Platform SDK)
  62 typedef struct _MARGINS
  63 {
  64     int cxLeftWidth;      // width of left border that retains its size
  65     int cxRightWidth;     // width of right border that retains its size
  66     int cyTopHeight;      // height of top border that retains its size
  67     int cyBottomHeight;   // height of bottom border that retains its size
  68 } MARGINS, *PMARGINS;
  69 
  70 #define TMT_TRANSPARENT 2201
  71 #endif // _UXTHEME_H_
  72 
  73 
  74 #define ALPHA_MASK 0xff000000
  75 #define RED_MASK 0xff0000
  76 #define GREEN_MASK 0xff00
  77 #define BLUE_MASK 0xff
  78 #define ALPHA_SHIFT 24
  79 #define RED_SHIFT 16
  80 #define GREEN_SHIFT 8
  81 
  82 
  83 typedef HRESULT(__stdcall *PFNCLOSETHEMEDATA)(HTHEME hTheme);
  84 
  85 typedef HRESULT(__stdcall *PFNDRAWTHEMEBACKGROUND)(HTHEME hTheme, HDC hdc,
  86         int iPartId, int iStateId, const RECT *pRect,  const RECT *pClipRect);
  87 
  88 typedef HTHEME(__stdcall *PFNOPENTHEMEDATA)(HWND hwnd, LPCWSTR pszClassList);
  89 
  90 typedef HRESULT (__stdcall *PFNDRAWTHEMETEXT)(HTHEME hTheme, HDC hdc,
  91           int iPartId, int iStateId, LPCWSTR pszText, int iCharCount,
  92           DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect);
  93 
  94 typedef HRESULT (__stdcall *PFNGETTHEMEBACKGROUNDCONTENTRECT)(HTHEME hTheme,
  95         HDC hdc, int iPartId, int iStateId,  const RECT *pBoundingRect,
  96         RECT *pContentRect);
  97 
  98 typedef HRESULT (__stdcall *PFNGETTHEMEMARGINS)(HTHEME hTheme,
  99         OPTIONAL HDC hdc, int iPartId, int iStateId, int iPropId,
 100         OPTIONAL RECT *prc, OUT MARGINS *pMargins);
 101 
 102 typedef BOOL (__stdcall *PFNISTHEMEPARTDEFINED)(HTHEME hTheme, int iPartId, int iStateId);
 103 
 104 typedef HRESULT (__stdcall *PFNGETTHEMEBOOL)(HTHEME hTheme, int iPartId,
 105         int iStateId, int iPropId, BOOL *pfVal);
 106 
 107 typedef BOOL (__stdcall *PFNGETTHEMESYSBOOL)(HTHEME hTheme, int iPropId);
 108 
 109 typedef HRESULT (__stdcall *PFNGETTHEMECOLOR)(HTHEME hTheme, int iPartId,
 110         int iStateId, int iPropId, COLORREF *pColor);
 111 
 112 typedef HRESULT (__stdcall *PFNGETTHEMEENUMVALUE)(HTHEME hTheme, int iPartId,
 113         int iStateId, int iPropId, int *val);
 114 typedef HRESULT (__stdcall *PFNGETTHEMEINT)(HTHEME hTheme, int iPartId,
 115         int iStateId, int iPropId, int *val);
 116 typedef HRESULT (__stdcall *PFNGETTHEMEPARTSIZE)(HTHEME hTheme, HDC hdc,
 117         int iPartId, int iStateId, RECT *prc, THEME_SIZE eSize, SIZE *size);
 118 
 119 typedef HRESULT (__stdcall *PFNGETTHEMEPOSITION)(HTHEME hTheme, int iPartId,
 120         int iStateId, int propID, POINT *point);
 121 
 122 typedef HRESULT(__stdcall *PFNSETWINDOWTHEME)(HWND hwnd, LPCWSTR pszSubAppName,
 123             LPCWSTR pszSubIdList);
 124 
 125 typedef HRESULT (__stdcall *PFNISTHEMEBACKGROUNDPARTIALLYTRANSPARENT)
 126                 (HTHEME hTheme, int iPartId, int iStateId);
 127 
 128 typedef HRESULT (__stdcall *PFNGETTHEMETRANSITIONDURATION)
 129                 (HTHEME hTheme, int iPartId, int iStateIdFrom, int iStateIdTo,
 130                  int iPropId, DWORD *pdwDuration);
 131 
 132 static PFNOPENTHEMEDATA OpenThemeData = NULL;
 133 static PFNDRAWTHEMEBACKGROUND DrawThemeBackground = NULL;
 134 static PFNCLOSETHEMEDATA CloseThemeData = NULL;
 135 static PFNDRAWTHEMETEXT DrawThemeText = NULL;
 136 static PFNGETTHEMEBACKGROUNDCONTENTRECT GetThemeBackgroundContentRect = NULL;
 137 static PFNGETTHEMEMARGINS GetThemeMargins = NULL;
 138 static PFNISTHEMEPARTDEFINED IsThemePartDefined = NULL;
 139 static PFNGETTHEMEBOOL GetThemeBool=NULL;
 140 static PFNGETTHEMESYSBOOL GetThemeSysBool=NULL;
 141 static PFNGETTHEMECOLOR GetThemeColor=NULL;
 142 static PFNGETTHEMEENUMVALUE GetThemeEnumValue = NULL;
 143 static PFNGETTHEMEINT GetThemeInt = NULL;
 144 static PFNGETTHEMEPARTSIZE GetThemePartSize = NULL;
 145 static PFNGETTHEMEPOSITION GetThemePosition = NULL;
 146 static PFNSETWINDOWTHEME SetWindowTheme = NULL;
 147 static PFNISTHEMEBACKGROUNDPARTIALLYTRANSPARENT
 148                                    IsThemeBackgroundPartiallyTransparent = NULL;
 149 //this function might not exist on Windows XP
 150 static PFNGETTHEMETRANSITIONDURATION GetThemeTransitionDuration = NULL;
 151 
 152 
 153 BOOL InitThemes() {
 154     static HMODULE hModThemes = NULL;
 155     hModThemes = JDK_LoadSystemLibrary("UXTHEME.DLL");
 156     DTRACE_PRINTLN1("InitThemes hModThemes = %x\n", hModThemes);
 157     if(hModThemes) {
 158         DTRACE_PRINTLN("Loaded UxTheme.dll\n");
 159         OpenThemeData = (PFNOPENTHEMEDATA)GetProcAddress(hModThemes,
 160                                                         "OpenThemeData");
 161         DrawThemeBackground = (PFNDRAWTHEMEBACKGROUND)GetProcAddress(
 162                                         hModThemes, "DrawThemeBackground");
 163         CloseThemeData = (PFNCLOSETHEMEDATA)GetProcAddress(
 164                                                 hModThemes, "CloseThemeData");
 165         DrawThemeText = (PFNDRAWTHEMETEXT)GetProcAddress(
 166                                         hModThemes, "DrawThemeText");
 167         GetThemeBackgroundContentRect = (PFNGETTHEMEBACKGROUNDCONTENTRECT)
 168                 GetProcAddress(hModThemes, "GetThemeBackgroundContentRect");
 169         GetThemeMargins = (PFNGETTHEMEMARGINS)GetProcAddress(
 170                                         hModThemes, "GetThemeMargins");
 171         IsThemePartDefined = (PFNISTHEMEPARTDEFINED)GetProcAddress(
 172                                         hModThemes, "IsThemePartDefined");
 173         GetThemeBool = (PFNGETTHEMEBOOL)GetProcAddress(
 174                                         hModThemes, "GetThemeBool");
 175         GetThemeSysBool = (PFNGETTHEMESYSBOOL)GetProcAddress(hModThemes,
 176                                                         "GetThemeSysBool");
 177         GetThemeColor = (PFNGETTHEMECOLOR)GetProcAddress(hModThemes,
 178                                                         "GetThemeColor");
 179         GetThemeEnumValue = (PFNGETTHEMEENUMVALUE)GetProcAddress(hModThemes,
 180                                                 "GetThemeEnumValue");
 181         GetThemeInt = (PFNGETTHEMEINT)GetProcAddress(hModThemes, "GetThemeInt");
 182         GetThemePosition = (PFNGETTHEMEPOSITION)GetProcAddress(hModThemes,
 183                                                         "GetThemePosition");
 184         GetThemePartSize = (PFNGETTHEMEPARTSIZE)GetProcAddress(hModThemes,
 185                                                          "GetThemePartSize");
 186         SetWindowTheme = (PFNSETWINDOWTHEME)GetProcAddress(hModThemes,
 187                                                         "SetWindowTheme");
 188         IsThemeBackgroundPartiallyTransparent =
 189             (PFNISTHEMEBACKGROUNDPARTIALLYTRANSPARENT)GetProcAddress(hModThemes,
 190                                        "IsThemeBackgroundPartiallyTransparent");
 191         //this function might not exist
 192         GetThemeTransitionDuration =
 193             (PFNGETTHEMETRANSITIONDURATION)GetProcAddress(hModThemes,
 194                                         "GetThemeTransitionDuration");
 195 
 196         if(OpenThemeData
 197            && DrawThemeBackground
 198            && CloseThemeData
 199            && DrawThemeText
 200            && GetThemeBackgroundContentRect
 201            && GetThemeMargins
 202            && IsThemePartDefined
 203            && GetThemeBool
 204            && GetThemeSysBool
 205            && GetThemeColor
 206            && GetThemeEnumValue
 207            && GetThemeInt
 208            && GetThemePartSize
 209            && GetThemePosition
 210            && SetWindowTheme
 211            && IsThemeBackgroundPartiallyTransparent
 212           ) {
 213               DTRACE_PRINTLN("Loaded function pointers.\n");
 214               // We need to make sure we can load the Theme. This may not be
 215               // the case on a WinXP machine with classic mode enabled.
 216               HTHEME hTheme = OpenThemeData(AwtToolkit::GetInstance().GetHWnd(), L"Button");
 217               if(hTheme) {
 218                   DTRACE_PRINTLN("Loaded Theme data.\n");
 219                   CloseThemeData(hTheme);
 220                   return TRUE;
 221               }
 222             } else {
 223                FreeLibrary(hModThemes);
 224                hModThemes = NULL;
 225             }
 226     }
 227     return FALSE;
 228 }
 229 
 230 JNIEXPORT jboolean JNICALL Java_sun_awt_windows_ThemeReader_isThemed
 231 (JNIEnv *env, jclass klass) {
 232     static BOOL TryLoadingThemeLib = FALSE;
 233     static BOOL Themed = FALSE;
 234     if (!TryLoadingThemeLib) {
 235         Themed = InitThemes();
 236         TryLoadingThemeLib = TRUE;
 237     }
 238     return JNI_IS_TRUE(Themed);
 239 }
 240 
 241 
 242 
 243 static void assert_result(HRESULT hres, JNIEnv *env) {
 244 #ifdef _DEBUG
 245     if (hres != 0) {
 246         DWORD lastError = GetLastError();
 247         if (lastError != 0) {
 248             LPSTR msgBuffer = NULL;
 249             FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
 250                     FORMAT_MESSAGE_FROM_SYSTEM |
 251                     FORMAT_MESSAGE_IGNORE_INSERTS,
 252                     NULL,
 253                     lastError,
 254                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
 255                     (LPSTR)&msgBuffer,
 256                     // it's an output parameter when allocate buffer is used
 257                     0,
 258                     NULL);
 259             DTRACE_PRINTLN3("Error: hres=0x%x lastError=0x%x %s\n", hres,
 260                                                 lastError, msgBuffer);
 261         }
 262     }
 263 #endif
 264 }
 265 
 266 
 267 /*
 268  * Class:     sun_awt_windows_ThemeReader
 269  * Method:    openTheme
 270  * Signature: (Ljava/lang/String;)J
 271  */
 272 JNIEXPORT jlong JNICALL Java_sun_awt_windows_ThemeReader_openTheme
 273 (JNIEnv *env, jclass klass, jstring widget) {
 274 
 275     LPCTSTR str = (LPCTSTR) JNU_GetStringPlatformChars(env, widget, NULL);
 276     if (str == NULL) {
 277         JNU_ThrowOutOfMemoryError(env, 0);
 278         return 0;
 279     }
 280     // We need to open the Theme on a Window that will stick around.
 281     // The best one for that purpose is the Toolkit window.
 282     HTHEME htheme = OpenThemeData(AwtToolkit::GetInstance().GetHWnd(), str);
 283     JNU_ReleaseStringPlatformChars(env, widget, str);
 284     return (jlong) htheme;
 285 }
 286 
 287 /*
 288  * Class:     sun_awt_windows_ThemeReader
 289  * Method:    setWindowTheme
 290  * Signature: (Ljava/lang/String;)V
 291  */
 292 JNIEXPORT void JNICALL Java_sun_awt_windows_ThemeReader_setWindowTheme
 293 (JNIEnv *env, jclass klass, jstring subAppName) {
 294 
 295     LPCTSTR str = NULL;
 296     if (subAppName != NULL) {
 297         str = (LPCTSTR) JNU_GetStringPlatformChars(env, subAppName, NULL);
 298     }
 299     // We need to set the Window theme on the same theme that we opened it with.
 300     HRESULT hres = SetWindowTheme(AwtToolkit::GetInstance().GetHWnd(), str, NULL);
 301     assert_result(hres, env);
 302     if (subAppName != NULL) {
 303         JNU_ReleaseStringPlatformChars(env, subAppName, str);
 304     }
 305 }
 306 
 307 /*
 308  * Class:     sun_awt_windows_ThemeReader
 309  * Method:    closeTheme
 310  * Signature: (J)V
 311  */
 312 JNIEXPORT void JNICALL Java_sun_awt_windows_ThemeReader_closeTheme
 313 (JNIEnv *env, jclass klass, jlong theme) {
 314 
 315     HRESULT hres = CloseThemeData((HTHEME)theme);
 316     assert_result(hres, env);
 317 }
 318 
 319 static void copyDIBToBufferedImage(int *pDstBits, int *pSrcBits,
 320                 BOOL transparent, int w, int h, int stride) {
 321 
 322     int offsetToNextLine = stride - w;
 323     int *dst = pDstBits;
 324     int *src = pSrcBits;
 325     double alphaScale;
 326     int r,g,b,a;
 327     int pixel;
 328 
 329     BOOL translucent = FALSE;
 330 
 331     for (int i=0;i<h;i++) {
 332         for (int j=0;j<w;j++) {
 333             pixel = *src++;
 334             a = (pixel & ALPHA_MASK)  >> ALPHA_SHIFT;
 335             if ((a != 0) && (a != 255)) {
 336                 translucent = TRUE;
 337                 break;
 338             }
 339         }
 340         if (translucent) break;
 341     }
 342     src = pSrcBits;
 343 
 344     if (translucent) {
 345         for (int i=0;i<h;i++) {
 346             for (int j=0;j<w;j++) {
 347                 pixel = *src++;
 348                 if (pixel != 0) {
 349                     // The UxTheme API seems to do the blending and
 350                     // premultiply the resulting values.
 351                     // so we have to divide by the alpha to get the
 352                     // original component values.
 353                     a = (pixel & ALPHA_MASK)  >> ALPHA_SHIFT;
 354                     if ((a != 255) && (a != 0)) {
 355                         r = (pixel & RED_MASK)  >> RED_SHIFT;
 356                         g = (pixel & GREEN_MASK)  >> GREEN_SHIFT;
 357                         b = (pixel & BLUE_MASK);
 358                         alphaScale = 255.0 / a;
 359                         r = (int) ((double) r * alphaScale);
 360                         if (r > 255) r = 255;
 361                         g = (int) ((double) g * alphaScale);
 362                         if (g > 255) g = 255;
 363                         b = (int) ((double) b * alphaScale);
 364                         if (b > 255) b = 255;
 365                         pixel = (a << ALPHA_SHIFT) | (r << RED_SHIFT) |
 366                                                    (g << GREEN_SHIFT) | b ;
 367                     }
 368                     else {
 369                         // Frame maximize and minimize buttons
 370                         // have transparent pixels with alpha
 371                         // set to FF and nontransparent pixels have zero alpha.
 372                         pixel |= 0xFF000000;
 373                     }
 374                 }
 375                 *dst++ = pixel;
 376             }
 377             dst += offsetToNextLine;
 378         }
 379     }
 380     else if (transparent) {
 381          for (int i=0;i<h;i++) {
 382              for (int j=0;j<w;j++) {
 383                  pixel = *src++;
 384                  if (pixel == 0) {
 385                      *dst++ = 0;
 386                  }
 387                  else {
 388                      *dst++ = 0xFF000000 | pixel;
 389                  }
 390              }
 391              dst += offsetToNextLine;
 392          }
 393      }
 394      else {
 395          for (int i=0;i<h;i++) {
 396              for (int j=0;j<w;j++) {
 397                  pixel = *src++;
 398                  *dst++ = 0xFF000000 | pixel;
 399              }
 400              dst += offsetToNextLine;
 401          }
 402      }
 403 
 404 }
 405 
 406 
 407 
 408 /*
 409  * Class:     sun_awt_windows_ThemeReader
 410  * Method:    paintBackground
 411  * Signature: ([IJIIIIIII)V
 412  */
 413 JNIEXPORT void JNICALL Java_sun_awt_windows_ThemeReader_paintBackground
 414   (JNIEnv *env, jclass klass, jintArray array, jlong theme, jint part, jint state,
 415     jint x, jint y, jint w, jint h, jint stride) {
 416 
 417     int *pDstBits=NULL;
 418     int *pSrcBits=NULL;
 419     HDC memDC,defaultDC;
 420     HBITMAP hDibSection = NULL;
 421     RECT rect;
 422     BITMAPINFO bmi;
 423     HTHEME hTheme = (HTHEME) theme;
 424 
 425     DTRACE_PRINTLN3("Java_sun_awt_windows_ThemeReader_paintButtonBackground w=%d h=%d\n stride=%d\n",w,h,stride);
 426 
 427     if (hTheme == NULL) {
 428         JNU_ThrowInternalError(env, "HTHEME is null");
 429         return;
 430     }
 431 
 432     defaultDC = GetDC(NULL);
 433 
 434     memDC = CreateCompatibleDC(defaultDC);
 435 
 436     static const int BITS_PER_PIXEL = 32;
 437 
 438     ZeroMemory(&bmi,sizeof(BITMAPINFO));
 439     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 440     bmi.bmiHeader.biWidth = w;
 441     bmi.bmiHeader.biHeight = -h;
 442     bmi.bmiHeader.biPlanes = 1;
 443     bmi.bmiHeader.biBitCount = BITS_PER_PIXEL;
 444     bmi.bmiHeader.biCompression = BI_RGB;
 445     bmi.bmiHeader.biSizeImage = w * h * (BITS_PER_PIXEL>>3);
 446 
 447 
 448     hDibSection = ::CreateDIBSection(memDC, (BITMAPINFO*) &bmi,
 449             DIB_RGB_COLORS, (void **) &pSrcBits,
 450             NULL, 0);
 451     if (hDibSection == NULL) {
 452         DTRACE_PRINTLN("Error creating DIB section");
 453         ReleaseDC(NULL,defaultDC);
 454         return;
 455     }
 456 
 457     SelectObject(memDC,hDibSection);
 458 
 459     rect.left = 0;
 460     rect.top = 0;
 461     rect.bottom = h;
 462     rect.right = w;
 463 
 464     ZeroMemory(pSrcBits,(BITS_PER_PIXEL>>3)*w*h);
 465 
 466     HRESULT hres = DrawThemeBackground(hTheme, memDC, part, state, &rect, NULL);
 467     assert_result(hres, env);
 468     if (SUCCEEDED(hres)) {
 469         // Make sure GDI is done.
 470         GdiFlush();
 471         // Copy the resulting pixels to our Java BufferedImage.
 472         pDstBits = (int *)env->GetPrimitiveArrayCritical(array, 0);
 473         BOOL transparent = FALSE;
 474         transparent = IsThemeBackgroundPartiallyTransparent(hTheme,part,state);
 475         copyDIBToBufferedImage(pDstBits, pSrcBits, transparent, w, h, stride);
 476         env->ReleasePrimitiveArrayCritical(array, pDstBits, 0);
 477     }
 478 
 479     // Delete resources.
 480     DeleteObject(hDibSection);
 481     DeleteDC(memDC);
 482     ReleaseDC(NULL,defaultDC);
 483 }
 484 
 485 jobject newInsets(JNIEnv *env, jint top, jint left, jint bottom, jint right) {
 486     if (env->EnsureLocalCapacity(2) < 0) {
 487         return NULL;
 488     }
 489 
 490     static jclass insetsClassID = NULL;
 491 
 492     if (insetsClassID == NULL) {
 493         jclass insetsClassIDLocal = env->FindClass("java/awt/Insets");
 494         CHECK_NULL_RETURN(insetsClassIDLocal, NULL);
 495         insetsClassID = (jclass)env->NewGlobalRef(insetsClassIDLocal);
 496         env->DeleteLocalRef(insetsClassIDLocal);
 497     }
 498 
 499     jobject insets = env->NewObject(insetsClassID,
 500         AwtToolkit::insetsMID,
 501         top, left, bottom, right);
 502 
 503     if (safe_ExceptionOccurred(env)) {
 504         env->ExceptionDescribe();
 505         env->ExceptionClear();
 506     }
 507 
 508     return insets;
 509 }
 510 
 511 /*
 512  * Class:     sun_awt_windows_ThemeReader
 513  * Method:    getThemeMargins
 514  * Signature: (JIII)Ljava/awt/Insets;
 515  */
 516 JNIEXPORT jobject JNICALL Java_sun_awt_windows_ThemeReader_getThemeMargins
 517 (JNIEnv *env, jclass klass, jlong theme, jint part, jint state, jint property) {
 518     MARGINS margins;
 519     HTHEME hTheme = (HTHEME) theme;
 520 
 521     if (hTheme != NULL) {
 522         HRESULT hres = GetThemeMargins(hTheme, NULL, part, state, property, NULL, &margins);
 523         assert_result(hres, env);
 524         if (FAILED(hres)) {
 525             return NULL;
 526         }
 527 
 528         return newInsets(env,
 529                 margins.cyTopHeight,
 530                 margins.cxLeftWidth, margins.cyBottomHeight, margins.cxRightWidth);
 531     }
 532     return NULL;
 533 }
 534 
 535 /*
 536  * Class: sun_awt_windows_ThemeReader
 537  * Method: isThemePartDefined
 538  * Signature: (JII)Z
 539  */
 540 JNIEXPORT jboolean JNICALL Java_sun_awt_windows_ThemeReader_isThemePartDefined
 541 (JNIEnv *env, jclass klass, jlong theme, jint part, jint state) {
 542     HTHEME hTheme = (HTHEME) theme;
 543     return JNI_IS_TRUE(IsThemePartDefined(hTheme, part, state));
 544 }
 545 
 546 /*
 547  * Class:     sun_awt_windows_ThemeReader
 548  * Method:    getColor
 549  * Signature: (JIII)Ljava/awt/Color;
 550  */
 551 JNIEXPORT jobject JNICALL Java_sun_awt_windows_ThemeReader_getColor
 552 (JNIEnv *env, jclass klass, jlong theme, jint part, jint state, jint type) {
 553 
 554     HTHEME hTheme = (HTHEME) theme;
 555 
 556     if (hTheme != NULL) {
 557         COLORREF color=0;
 558 
 559         if (GetThemeColor(hTheme, part, state, type, &color) != S_OK) {
 560             return NULL;
 561         }
 562 
 563         if (env->EnsureLocalCapacity(1) < 0) {
 564             return NULL;
 565         }
 566 
 567         static jmethodID colorMID = NULL;
 568         static jclass colorClassID = NULL;
 569 
 570         if (colorClassID == NULL) {
 571             jclass colorClassIDLocal = env->FindClass("java/awt/Color");
 572             CHECK_NULL_RETURN(colorClassIDLocal, NULL);
 573             colorClassID = (jclass)env->NewGlobalRef(colorClassIDLocal);
 574             env->DeleteLocalRef(colorClassIDLocal);
 575         }
 576 
 577         if (colorMID == NULL) {
 578             colorMID = env->GetMethodID(colorClassID, "<init>", "(III)V");
 579             CHECK_NULL_RETURN(colorMID, NULL);
 580         }
 581         jobject colorObj = env->NewObject(colorClassID,
 582                 colorMID, GetRValue(color), GetGValue(color),GetBValue(color));
 583 
 584         if (safe_ExceptionOccurred(env)) {
 585             env->ExceptionDescribe();
 586             env->ExceptionClear();
 587         }
 588 
 589         return colorObj;
 590     }
 591     return NULL;
 592 }
 593 
 594 /*
 595  * Class:     sun_awt_windows_ThemeReader
 596  * Method:    getInt
 597  * Signature: (JIII)I
 598  */
 599 JNIEXPORT jint JNICALL Java_sun_awt_windows_ThemeReader_getInt
 600 (JNIEnv *env, jclass klass, jlong theme, jint part, jint state, jint prop) {
 601 
 602     HTHEME hTheme = (HTHEME) theme;
 603     int retVal = -1;
 604     if (hTheme != NULL) {
 605         HRESULT hres = GetThemeInt(hTheme, part, state, prop, &retVal);
 606         assert_result(hres, env);
 607     }
 608     return retVal;
 609 }
 610 
 611 /*
 612  * Class:     sun_awt_windows_ThemeReader
 613  * Method:    getEnum
 614  * Signature: (JIII)I
 615  */
 616 JNIEXPORT jint JNICALL Java_sun_awt_windows_ThemeReader_getEnum
 617 (JNIEnv *env, jclass klass, jlong theme, jint part, jint state, jint prop) {
 618     HTHEME hTheme = (HTHEME) theme;
 619     int retVal = -1;
 620     if (hTheme != NULL) {
 621         HRESULT hres = GetThemeEnumValue(hTheme, part, state, prop, &retVal);
 622         assert_result(hres, env);
 623     }
 624     return retVal;
 625 }
 626 
 627 /*
 628  * Class:     sun_awt_windows_ThemeReader
 629  * Method:    getBoolean
 630  * Signature: (JIII)Z
 631  */
 632 JNIEXPORT jboolean JNICALL Java_sun_awt_windows_ThemeReader_getBoolean
 633 (JNIEnv *env, jclass klass, jlong  theme, jint part, jint state, jint prop) {
 634     HTHEME hTheme = (HTHEME) theme;
 635     BOOL retVal = FALSE;
 636     if (hTheme != NULL) {
 637         HRESULT hres = GetThemeBool(hTheme, part, state, prop, &retVal);
 638         assert_result(hres, env);
 639     }
 640     return JNI_IS_TRUE(retVal);
 641 }
 642 
 643 /*
 644  * Class:     sun_awt_windows_ThemeReader
 645  * Method:    getSysBoolean
 646  * Signature: (JI)Z
 647  */
 648 JNIEXPORT jboolean JNICALL Java_sun_awt_windows_ThemeReader_getSysBoolean
 649 (JNIEnv *env, jclass klass, jlong  theme, jint prop) {
 650     HTHEME hTheme = (HTHEME)theme;
 651     if (hTheme != NULL) {
 652         return JNI_IS_TRUE(GetThemeSysBool(hTheme, prop));
 653     }
 654     return JNI_FALSE;
 655 }
 656 
 657 /*
 658  * Class:     sun_awt_windows_ThemeReader
 659  * Method:    getPoint
 660  * Signature: (JIII)Ljava/awt/Point;
 661  */
 662 JNIEXPORT jobject JNICALL Java_sun_awt_windows_ThemeReader_getPoint
 663 (JNIEnv *env, jclass klass, jlong theme, jint part, jint state, jint prop) {
 664     HTHEME hTheme = (HTHEME) theme;
 665     POINT point;
 666 
 667     if (hTheme != NULL) {
 668         if (GetThemePosition(hTheme, part, state, prop, &point) != S_OK) {
 669             return NULL;
 670         }
 671 
 672         if (env->EnsureLocalCapacity(2) < 0) {
 673             return NULL;
 674         }
 675 
 676         static jmethodID pointMID = NULL;
 677         static jclass pointClassID = NULL;
 678 
 679         if (pointClassID == NULL) {
 680             jclass pointClassIDLocal = env->FindClass("java/awt/Point");
 681             CHECK_NULL_RETURN(pointClassIDLocal, NULL);
 682             pointClassID = (jclass)env->NewGlobalRef(pointClassIDLocal);
 683             env->DeleteLocalRef(pointClassIDLocal);
 684         }
 685 
 686         if (pointMID == NULL) {
 687             pointMID = env->GetMethodID(pointClassID, "<init>", "(II)V");
 688             CHECK_NULL_RETURN(pointMID, NULL);
 689         }
 690         jobject pointObj = env->NewObject(pointClassID, pointMID, point.x, point.y);
 691 
 692         if (safe_ExceptionOccurred(env)) {
 693             env->ExceptionDescribe();
 694             env->ExceptionClear();
 695         }
 696 
 697         return pointObj;
 698     }
 699     return NULL;
 700 }
 701 
 702 /*
 703  * Class:     sun_awt_windows_ThemeReader
 704  * Method:    getPosition
 705  * Signature: (JIII)Ljava/awt/Dimension;
 706  */
 707 JNIEXPORT jobject JNICALL Java_sun_awt_windows_ThemeReader_getPosition
 708 (JNIEnv *env, jclass klass, jlong theme, jint part, jint state, jint prop) {
 709 
 710     HTHEME hTheme = (HTHEME) theme;
 711     if (hTheme != NULL) {
 712 
 713         POINT point;
 714 
 715         HRESULT hres = GetThemePosition(hTheme, part, state, prop, &point);
 716         assert_result(hres, env);
 717         if (FAILED(hres)) {
 718             return NULL;
 719         }
 720 
 721 
 722         if (env->EnsureLocalCapacity(2) < 0) {
 723             return NULL;
 724         }
 725 
 726         static jmethodID dimMID = NULL;
 727         static jclass dimClassID = NULL;
 728         if (dimClassID == NULL) {
 729             jclass dimClassIDLocal = env->FindClass("java/awt/Dimension");
 730             CHECK_NULL_RETURN(dimClassIDLocal, NULL);
 731             dimClassID = (jclass)env->NewGlobalRef(dimClassIDLocal);
 732             env->DeleteLocalRef(dimClassIDLocal);
 733         }
 734         if (dimMID == NULL) {
 735             dimMID = env->GetMethodID(dimClassID, "<init>", "(II)V");
 736             CHECK_NULL_RETURN(dimMID, NULL);
 737         }
 738         jobject dimObj = env->NewObject(dimClassID, dimMID, point.x, point.y);
 739 
 740         if (safe_ExceptionOccurred(env)) {
 741             env->ExceptionDescribe();
 742             env->ExceptionClear();
 743         }
 744 
 745         return dimObj;
 746     }
 747     return NULL;
 748 }
 749 
 750 void rescale(SIZE *size) {
 751     HWND hWnd = ::GetDesktopWindow();
 752     HDC hDC = ::GetDC(hWnd);
 753     int dpiX = ::GetDeviceCaps(hDC, LOGPIXELSX);
 754     int dpiY = ::GetDeviceCaps(hDC, LOGPIXELSY);
 755 
 756     if (dpiX !=0 && dpiX != 96) {
 757         float invScaleX = 96.0f / dpiX;
 758         size->cx = (int)round(size->cx * invScaleX);
 759     }
 760     if (dpiY != 0 && dpiY != 96) {
 761         float invScaleY = 96.0f / dpiY;
 762         size->cy = (int)round(size->cy * invScaleY);
 763     }
 764     ::ReleaseDC(hWnd, hDC);
 765 }
 766 
 767 /*
 768  * Class:     sun_awt_windows_ThemeReader
 769  * Method:    getPartSize
 770  * Signature: (JII)Ljava/awt/Dimension;
 771  */
 772 JNIEXPORT jobject JNICALL Java_sun_awt_windows_ThemeReader_getPartSize
 773 (JNIEnv *env, jclass klass, jlong theme, jint part, jint state) {
 774     if (theme != NULL) {
 775         SIZE size;
 776 
 777         if (SUCCEEDED(GetThemePartSize((HTHEME)theme, NULL, part, state,
 778            NULL, TS_TRUE, &size)) && (env->EnsureLocalCapacity(2) >= 0)) {
 779 
 780             static jmethodID dimMID = NULL;
 781             static jclass dimClassID = NULL;
 782             if (dimClassID == NULL) {
 783                 jclass dimClassIDLocal = env->FindClass("java/awt/Dimension");
 784                 CHECK_NULL_RETURN(dimClassIDLocal, NULL);
 785                 dimClassID = (jclass)env->NewGlobalRef(dimClassIDLocal);
 786                 env->DeleteLocalRef(dimClassIDLocal);
 787             }
 788             if (dimMID == NULL) {
 789                 dimMID = env->GetMethodID(dimClassID, "<init>", "(II)V");
 790                 CHECK_NULL_RETURN(dimMID, NULL);
 791             }
 792 
 793             rescale(&size);
 794             jobject dimObj = env->NewObject(dimClassID, dimMID, size.cx, size.cy);
 795             if (safe_ExceptionOccurred(env)) {
 796                 env->ExceptionDescribe();
 797                 env->ExceptionClear();
 798             }
 799 
 800             return dimObj;
 801         }
 802     }
 803     return NULL;
 804 }
 805 
 806 /*
 807  * Class:     sun_awt_windows_ThemeReader
 808  * Method:    getThemeBackgroundContentMargins
 809  * Signature: (JIIII)Ljava/awt/Insets;
 810  */
 811 JNIEXPORT jobject JNICALL Java_sun_awt_windows_ThemeReader_getThemeBackgroundContentMargins
 812 (JNIEnv *env, jclass klass, jlong hTheme, jint part, jint state,
 813 jint boundingWidth, jint boundingHeight) {
 814     if (hTheme != NULL) {
 815         RECT boundingRect;
 816         boundingRect.left = 0;
 817         boundingRect.top = 0;
 818         boundingRect.right = boundingWidth;
 819         boundingRect.bottom = boundingHeight;
 820         RECT contentRect;
 821         if (SUCCEEDED(GetThemeBackgroundContentRect((HTHEME) hTheme, NULL, part,
 822                                                     state, &boundingRect,
 823                                                     &contentRect))) {
 824             return newInsets(env,
 825                              contentRect.top, contentRect.left,
 826                              boundingHeight - contentRect.bottom,
 827                              boundingWidth - contentRect.right);
 828         }
 829     }
 830     return NULL;
 831 }
 832 
 833 /*
 834  * Class:     sun_awt_windows_ThemeReader
 835  * Method:    getThemeTransitionDuration
 836  * Signature: (JIIII)J
 837  */
 838 JNIEXPORT jlong JNICALL
 839 Java_sun_awt_windows_ThemeReader_getThemeTransitionDuration
 840 (JNIEnv *env, jclass klass, jlong theme, jint part, jint stateFrom,
 841  jint stateTo, jint propId) {
 842     jlong rv = -1;
 843     if (GetThemeTransitionDuration != NULL) {
 844         DWORD duration = 0;
 845         if (SUCCEEDED(GetThemeTransitionDuration((HTHEME) theme, part,
 846                                       stateFrom, stateTo, propId, &duration))) {
 847             rv = duration;
 848         }
 849     }
 850     return rv;
 851 }
 852 
 853 /*
 854  * Class:     sun_awt_windows_ThemeReader
 855  * Method:    isGetThemeTransitionDurationDefined
 856  * Signature: ()Z
 857  */
 858 JNIEXPORT jboolean JNICALL
 859 Java_sun_awt_windows_ThemeReader_isGetThemeTransitionDurationDefined
 860 (JNIEnv *env, jclass klass) {
 861     return (GetThemeTransitionDuration != NULL) ? JNI_TRUE : JNI_FALSE;
 862 }