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