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