1 /*
   2  * Copyright (c) 1999, 2013, 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_java2d_windows_GDIWindowSurfaceData.h"
  27 
  28 #include "GDIWindowSurfaceData.h"
  29 #include "GraphicsPrimitiveMgr.h"
  30 #include "Region.h"
  31 #include "Disposer.h"
  32 #include "WindowsFlags.h"
  33 #include "awt_Component.h"
  34 #include "awt_Palette.h"
  35 #include "awt_Win32GraphicsDevice.h"
  36 #include "gdefs.h"
  37 #include "Trace.h"
  38 #include "Devices.h"
  39 
  40 #include "jni_util.h"
  41 
  42 static LockFunc GDIWinSD_Lock;
  43 static GetRasInfoFunc GDIWinSD_GetRasInfo;
  44 static UnlockFunc GDIWinSD_Unlock;
  45 static DisposeFunc GDIWinSD_Dispose;
  46 static SetupFunc GDIWinSD_Setup;
  47 static GetDCFunc GDIWinSD_GetDC;
  48 static ReleaseDCFunc GDIWinSD_ReleaseDC;
  49 static InvalidateSDFunc GDIWinSD_InvalidateSD;
  50 
  51 static HBRUSH   nullbrush;
  52 static HPEN     nullpen;
  53 
  54 static jclass xorCompClass;
  55 
  56 static jboolean beingShutdown = JNI_FALSE;
  57 static volatile LONG timeStamp = 0;
  58 extern CriticalSection windowMoveLock;
  59 
  60 extern "C"
  61 {
  62 GeneralDisposeFunc DisposeThreadGraphicsInfo;
  63 jobject JNI_GetCurrentThread(JNIEnv *env);
  64 int threadInfoIndex = TLS_OUT_OF_INDEXES;
  65 
  66 static jclass threadClass = NULL;
  67 static jmethodID currentThreadMethodID = NULL;
  68 
  69 void SetupThreadGraphicsInfo(JNIEnv *env, GDIWinSDOps *wsdo) {
  70     J2dTraceLn(J2D_TRACE_INFO, "SetupThreadGraphicsInfo");
  71 
  72     // REMIND: handle error when creation fails
  73     ThreadGraphicsInfo *info =
  74         (ThreadGraphicsInfo*)TlsGetValue(threadInfoIndex);
  75     if (info == NULL) {
  76         info = new ThreadGraphicsInfo;
  77         ZeroMemory(info, sizeof(ThreadGraphicsInfo));
  78         TlsSetValue(threadInfoIndex, (LPVOID)info);
  79         J2dTraceLn2(J2D_TRACE_VERBOSE,
  80                     "  current batch limit for thread 0x%x is %d",
  81                      GetCurrentThreadId(), ::GdiGetBatchLimit());
  82         J2dTraceLn(J2D_TRACE_VERBOSE, "  setting to the limit to 1");
  83         // Fix for bug 4374079
  84         ::GdiSetBatchLimit(1);
  85 
  86         Disposer_AddRecord(env, JNI_GetCurrentThread(env),
  87                            DisposeThreadGraphicsInfo,
  88                            ptr_to_jlong(info));
  89     }
  90 
  91     HDC oldhDC = info->hDC;
  92     // the hDC is NULL for offscreen surfaces - we don't store it
  93     // in TLS as it must be created new every time.
  94 
  95     if( ((oldhDC == NULL) && wsdo->window != NULL) ||
  96          (info->wsdo != wsdo) ||
  97          (info->wsdoTimeStamp != wsdo->timeStamp) )
  98     {
  99 
 100         // Init graphics state, either because this is our first time
 101         // using it in this thread or because this thread is now
 102         // dealing with a different window than it was last time.
 103 
 104         //check extra condition:
 105         //(info->wsdoTimeStamp != wsdo->timeStamp).
 106         //Checking memory addresses (info->wsdo != wsdo) will not detect
 107         //that wsdo points to a newly allocated structure in case
 108         //that structure just got allocated at a "recycled" memory location
 109         //which previously was pointed by info->wsdo
 110         //see bug# 6859086
 111 
 112         // Release cached DC. We use deferred DC releasing mechanism because
 113         // the DC is associated with cached wsdo and component peer,
 114         // which may've been disposed by this time, and we have
 115         // no means of checking against it.
 116         if (oldhDC != NULL) {
 117             MoveDCToPassiveList(oldhDC);
 118             info->hDC = NULL;
 119         }
 120 
 121         if (wsdo->window != NULL){
 122             HDC hDC;
 123             // This is a window surface
 124             // First, init the HDC object
 125             AwtComponent *comp = GDIWindowSurfaceData_GetComp(env, wsdo);
 126             if (comp == NULL) {
 127                 return;
 128             }
 129             hDC = comp->GetDCFromComponent();
 130             if (hDC != NULL) {
 131                 ::SelectObject(hDC, nullbrush);
 132                 ::SelectObject(hDC, nullpen);
 133                 ::SelectClipRgn(hDC, (HRGN) NULL);
 134                 ::SetROP2(hDC, R2_COPYPEN);
 135                 wsdo->device->SelectPalette(hDC);
 136                 // Note that on NT4 we don't need to do a realize here: the
 137                 // palette-sharing takes care of color issues for us.  But
 138                 // on win98 if we don't realize a DC's palette, that
 139                 // palette does not appear to have correct access to the
 140                 // logical->system mapping.
 141                 wsdo->device->RealizePalette(hDC);
 142 
 143                 // Second, init the rest of the graphics state
 144                 ::GetClientRect(wsdo->window, &info->bounds);
 145                 // Make window-relative from client-relative
 146                 ::OffsetRect(&info->bounds, wsdo->insets.left, wsdo->insets.top);
 147                 //Likewise, translate GDI calls from client-relative to window-relative
 148                 ::OffsetViewportOrgEx(hDC, -wsdo->insets.left, -wsdo->insets.top, NULL);
 149             }
 150 
 151             // Finally, set these new values in the info for this thread
 152             info->hDC = hDC;
 153         }
 154 
 155         // cached brush and pen are not associated with any DC, and can be
 156         // reused, but have to set type to 0 to indicate that no pen/brush
 157         // were set to the new hdc
 158         info->type = 0;
 159 
 160         if (info->clip != NULL) {
 161             env->DeleteWeakGlobalRef(info->clip);
 162         }
 163         info->clip = NULL;
 164 
 165         if (info->comp != NULL) {
 166             env->DeleteWeakGlobalRef(info->comp);
 167         }
 168         info->comp = NULL;
 169 
 170         info->xorcolor = 0;
 171         info->patrop = PATCOPY;
 172 
 173         //store the address and time stamp of newly allocated GDIWinSDOps structure
 174         info->wsdo = wsdo;
 175         info->wsdoTimeStamp = wsdo->timeStamp;
 176     }
 177 }
 178 
 179 /**
 180  * Releases native data stored in Thread local storage.
 181  * Called by the Disposer when the associated thread dies.
 182  */
 183 void DisposeThreadGraphicsInfo(JNIEnv *env, jlong tgi) {
 184     J2dTraceLn(J2D_TRACE_INFO, "DisposeThreadGraphicsInfo");
 185     ThreadGraphicsInfo *info = (ThreadGraphicsInfo*)jlong_to_ptr(tgi);
 186     if (info != NULL) {
 187         if (info->hDC != NULL) {
 188             // move the DC from the active dcs list to
 189             // the passive dc list to be released later
 190             MoveDCToPassiveList(info->hDC);
 191         }
 192 
 193         if (info->clip != NULL) {
 194             env->DeleteWeakGlobalRef(info->clip);
 195         }
 196         if (info->comp != NULL) {
 197             env->DeleteWeakGlobalRef(info->comp);
 198         }
 199 
 200         if (info->brush != NULL) {
 201             info->brush->Release();
 202         }
 203         if (info->pen != NULL) {
 204             info->pen->Release();
 205         }
 206 
 207         delete info;
 208     }
 209 }
 210 
 211 /**
 212  * Returns current Thread object.
 213  */
 214 jobject
 215 JNI_GetCurrentThread(JNIEnv *env) {
 216     return env->CallStaticObjectMethod(threadClass, currentThreadMethodID);
 217 } /* JNI_GetCurrentThread() */
 218 
 219 /**
 220  * Return the data associated with this thread.
 221  * NOTE: This function assumes that the SetupThreadGraphicsInfo()
 222  * function has already been called for this situation (thread,
 223  * window, etc.), so we can assume that the thread info contains
 224  * a valid hDC.  This should usually be the case since GDIWinSD_Setup
 225  * is called as part of the GetOps() process.
 226  */
 227 ThreadGraphicsInfo *GetThreadGraphicsInfo(JNIEnv *env,
 228                                           GDIWinSDOps *wsdo) {
 229     return (ThreadGraphicsInfo*)TlsGetValue(threadInfoIndex);
 230 }
 231 
 232 __inline HDC GetThreadDC(JNIEnv *env, GDIWinSDOps *wsdo) {
 233     ThreadGraphicsInfo *info =
 234         (ThreadGraphicsInfo *)GetThreadGraphicsInfo(env, wsdo);
 235     if (!info) {
 236         return (HDC) NULL;
 237     }
 238     return info->hDC;
 239 }
 240 
 241 } // extern "C"
 242 
 243 /**
 244  * This source file contains support code for loops using the
 245  * SurfaceData interface to talk to a Win32 drawable from native
 246  * code.
 247  */
 248 
 249 static BOOL GDIWinSD_CheckMonitorArea(GDIWinSDOps *wsdo,
 250                                      SurfaceDataBounds *bounds,
 251                                      HDC hDC)
 252 {
 253     HWND hW = wsdo->window;
 254     BOOL retCode = TRUE;
 255 
 256     J2dTraceLn(J2D_TRACE_INFO, "GDIWinSD_CheckMonitorArea");
 257     int numScreens;
 258     {
 259         Devices::InstanceAccess devices;
 260         numScreens = devices->GetNumDevices();
 261     }
 262     if( numScreens > 1 ) {
 263 
 264         LPMONITORINFO miInfo;
 265         RECT rSect ={0,0,0,0};
 266         RECT rView ={bounds->x1, bounds->y1, bounds->x2, bounds->y2};
 267         retCode = FALSE;
 268 
 269         miInfo = wsdo->device->GetMonitorInfo();
 270 
 271         POINT ptOrig = {0, 0};
 272         ::ClientToScreen(hW, &ptOrig);
 273         ::OffsetRect(&rView,
 274             (ptOrig.x), (ptOrig.y));
 275 
 276         ::IntersectRect(&rSect,&rView,&(miInfo->rcMonitor));
 277 
 278         if( FALSE == ::IsRectEmpty(&rSect) ) {
 279             if( TRUE == ::EqualRect(&rSect,&rView) ) {
 280                 retCode = TRUE;
 281             }
 282         }
 283     }
 284     return retCode;
 285 }
 286 
 287 extern "C" {
 288 
 289 void
 290 initThreadInfoIndex()
 291 {
 292     if (threadInfoIndex == TLS_OUT_OF_INDEXES) {
 293         threadInfoIndex = TlsAlloc();
 294     }
 295 }
 296 
 297 
 298 /**
 299  * Utility function to make sure that native and java-level
 300  * surface depths are matched.  They can be mismatched when display-depths
 301  * change, either between the creation of the Java surfaceData structure
 302  * and the native ddraw surface, or later when a surface is automatically
 303  * adjusted to be the new display depth (even if it was created in a different
 304  * depth to begin with)
 305  */
 306 BOOL SurfaceDepthsCompatible(int javaDepth, int nativeDepth)
 307 {
 308     if (nativeDepth != javaDepth) {
 309         switch (nativeDepth) {
 310         case 0: // Error condition: something is wrong with the surface
 311         case 8:
 312         case 24:
 313             // Java and native surface depths should match exactly for
 314             // these cases
 315             return FALSE;
 316             break;
 317         case 16:
 318             // Java surfaceData should be 15 or 16 bits
 319             if (javaDepth < 15 || javaDepth > 16) {
 320                 return FALSE;
 321             }
 322             break;
 323         case 32:
 324             // Could have this native depth for either 24- or 32-bit
 325             // Java surfaceData
 326             if (javaDepth != 24 && javaDepth != 32) {
 327                 return FALSE;
 328             }
 329             break;
 330         default:
 331             // should not get here, but if we do something is odd, so
 332             // just register a failure
 333             return FALSE;
 334         }
 335     }
 336     return TRUE;
 337 }
 338 
 339 
 340 /*
 341  * Class:     sun_java2d_windows_GDIWindowSurfaceData
 342  * Method:    initIDs
 343  * Signature: ()V
 344  */
 345 JNIEXPORT void JNICALL
 346 Java_sun_java2d_windows_GDIWindowSurfaceData_initIDs(JNIEnv *env, jclass wsd,
 347                                                  jclass XORComp)
 348 {
 349     jclass tc;
 350     J2dTraceLn(J2D_TRACE_INFO, "GDIWindowSurfaceData_initIDs");
 351     nullbrush = (HBRUSH) ::GetStockObject(NULL_BRUSH);
 352     nullpen = (HPEN) ::GetStockObject(NULL_PEN);
 353 
 354     initThreadInfoIndex();
 355 
 356     xorCompClass = (jclass)env->NewGlobalRef(XORComp);
 357     if (env->ExceptionCheck()) {
 358         return;
 359     }
 360 
 361     tc = env->FindClass("java/lang/Thread");
 362     DASSERT(tc != NULL);
 363     CHECK_NULL(tc);
 364 
 365     threadClass = (jclass)env->NewGlobalRef(tc);
 366     DASSERT(threadClass != NULL);
 367     CHECK_NULL(threadClass);
 368 
 369     currentThreadMethodID =
 370         env->GetStaticMethodID(threadClass,
 371                                "currentThread",  "()Ljava/lang/Thread;");
 372     DASSERT(currentThreadMethodID != NULL);
 373 }
 374 
 375 #undef ExceptionOccurred
 376 
 377 /*
 378  * Class:     sun_java2d_windows_GDIWindowSurfaceData
 379  * Method:    initOps
 380  * Signature: (Ljava/lang/Object;IIIIII)V
 381  */
 382 JNIEXPORT void JNICALL
 383 Java_sun_java2d_windows_GDIWindowSurfaceData_initOps(JNIEnv *env, jobject wsd,
 384                                                  jobject peer, jint depth,
 385                                                  jint redMask, jint greenMask,
 386                                                  jint blueMask, jint screen)
 387 {
 388     J2dTraceLn(J2D_TRACE_INFO, "GDIWindowSurfaceData_initOps");
 389     GDIWinSDOps *wsdo = (GDIWinSDOps *)SurfaceData_InitOps(env, wsd, sizeof(GDIWinSDOps));
 390     if (wsdo == NULL) {
 391         JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");
 392         return;
 393     }
 394     wsdo->timeStamp = InterlockedIncrement(&timeStamp); //creation time stamp
 395     wsdo->sdOps.Lock = GDIWinSD_Lock;
 396     wsdo->sdOps.GetRasInfo = GDIWinSD_GetRasInfo;
 397     wsdo->sdOps.Unlock = GDIWinSD_Unlock;
 398     wsdo->sdOps.Dispose = GDIWinSD_Dispose;
 399     wsdo->sdOps.Setup = GDIWinSD_Setup;
 400     wsdo->GetDC = GDIWinSD_GetDC;
 401     wsdo->ReleaseDC = GDIWinSD_ReleaseDC;
 402     wsdo->InvalidateSD = GDIWinSD_InvalidateSD;
 403     wsdo->invalid = JNI_FALSE;
 404     wsdo->lockType = WIN32SD_LOCK_UNLOCKED;
 405     wsdo->peer = env->NewWeakGlobalRef(peer);
 406     if (env->ExceptionOccurred()) {
 407         return;
 408     }
 409     wsdo->depth = depth;
 410     wsdo->pixelMasks[0] = redMask;
 411     wsdo->pixelMasks[1] = greenMask;
 412     wsdo->pixelMasks[2] = blueMask;
 413     // Init the DIB pixelStride and pixel masks according to
 414     // the pixel depth. In the 8-bit case, there are no
 415     // masks as a palette DIB is used instead. Likewise
 416     // in the 24-bit case, Windows doesn't expect the masks
 417     switch (depth) {
 418         case 8:
 419             wsdo->pixelStride = 1;
 420             break;
 421         case 15: //555
 422             wsdo->pixelStride = 2;
 423             break;
 424         case 16: //565
 425             wsdo->pixelStride = 2;
 426             break;
 427         case 24:
 428             wsdo->pixelStride = 3;
 429             break;
 430         case 32: //888
 431             wsdo->pixelStride = 4;
 432             break;
 433     }
 434     // GDIWindowSurfaceData_GetWindow will throw NullPointerException
 435     // if wsdo->window is NULL
 436     wsdo->window = GDIWindowSurfaceData_GetWindow(env, wsdo);
 437     J2dTraceLn2(J2D_TRACE_VERBOSE, "  wsdo=0x%x wsdo->window=0x%x",
 438                 wsdo, wsdo->window);
 439 
 440     {
 441         Devices::InstanceAccess devices;
 442         wsdo->device = devices->GetDeviceReference(screen, FALSE);
 443     }
 444     if (wsdo->device == NULL ||
 445         !SurfaceDepthsCompatible(depth, wsdo->device->GetBitDepth()))
 446     {
 447         if (wsdo->device != NULL) {
 448             J2dTraceLn2(J2D_TRACE_WARNING,
 449                         "GDIWindowSurfaceData_initOps: Surface depth mismatch: "\
 450                         "wsdo->depth=%d device depth=%d. Surface invalidated.",
 451                         wsdo->depth, wsdo->device->GetBitDepth());
 452         } else {
 453             J2dTraceLn1(J2D_TRACE_WARNING,
 454                         "GDIWindowSurfaceData_initOps: Incorrect "\
 455                         "screen number (screen=%d). Surface invalidated.",
 456                         screen);
 457         }
 458 
 459         wsdo->invalid = JNI_TRUE;
 460     }
 461     wsdo->surfaceLock = new CriticalSection();
 462     wsdo->bitmap = NULL;
 463     wsdo->bmdc = NULL;
 464     wsdo->bmCopyToScreen = FALSE;
 465 }
 466 
 467 JNIEXPORT GDIWinSDOps * JNICALL
 468 GDIWindowSurfaceData_GetOps(JNIEnv *env, jobject sData)
 469 {
 470     SurfaceDataOps *ops = SurfaceData_GetOps(env, sData);
 471     // REMIND: There was originally a condition check here to make sure
 472     // that we were really dealing with a GDIWindowSurfaceData object, but
 473     // it did not allow for the existence of other win32-accelerated
 474     // surface data objects (e.g., Win32OffScreenSurfaceData).  I've
 475     // removed the check for now, but we should replace it with another,
 476     // more general check against Win32-related surfaces.
 477     return (GDIWinSDOps *) ops;
 478 }
 479 
 480 JNIEXPORT GDIWinSDOps * JNICALL
 481 GDIWindowSurfaceData_GetOpsNoSetup(JNIEnv *env, jobject sData)
 482 {
 483     // use the 'no setup' version of GetOps
 484     SurfaceDataOps *ops = SurfaceData_GetOpsNoSetup(env, sData);
 485     return (GDIWinSDOps *) ops;
 486 }
 487 
 488 JNIEXPORT AwtComponent * JNICALL
 489 GDIWindowSurfaceData_GetComp(JNIEnv *env, GDIWinSDOps *wsdo)
 490 {
 491     PDATA pData;
 492     jobject localObj = env->NewLocalRef(wsdo->peer);
 493 
 494     if (localObj == NULL || (pData = JNI_GET_PDATA(localObj)) == NULL) {
 495         J2dTraceLn1(J2D_TRACE_WARNING,
 496                     "GDIWindowSurfaceData_GetComp: Null pData? pData=0x%x",
 497                     pData);
 498         if (beingShutdown == JNI_TRUE) {
 499             wsdo->invalid = JNI_TRUE;
 500             return (AwtComponent *) NULL;
 501         }
 502         try {
 503             AwtToolkit::GetInstance().VerifyActive();
 504         } catch (awt_toolkit_shutdown&) {
 505             beingShutdown = JNI_TRUE;
 506             wsdo->invalid = JNI_TRUE;
 507             return (AwtComponent *) NULL;
 508         }
 509         if (wsdo->invalid == JNI_TRUE) {
 510             SurfaceData_ThrowInvalidPipeException(env,
 511                 "GDIWindowSurfaceData: bounds changed");
 512         } else {
 513             JNU_ThrowNullPointerException(env, "component argument pData");
 514         }
 515         return (AwtComponent *) NULL;
 516     }
 517     return static_cast<AwtComponent*>(pData);
 518 }
 519 
 520 JNIEXPORT HWND JNICALL
 521 GDIWindowSurfaceData_GetWindow(JNIEnv *env, GDIWinSDOps *wsdo)
 522 {
 523     HWND window = wsdo->window;
 524 
 525     if (window == (HWND) NULL) {
 526         AwtComponent *comp = GDIWindowSurfaceData_GetComp(env, wsdo);
 527         if (comp == NULL) {
 528             J2dTraceLn(J2D_TRACE_WARNING,
 529                    "GDIWindowSurfaceData_GetWindow: null component");
 530             return (HWND) NULL;
 531         }
 532         comp->GetInsets(&wsdo->insets);
 533         window = comp->GetHWnd();
 534         if (::IsWindow(window) == FALSE) {
 535             J2dRlsTraceLn(J2D_TRACE_ERROR,
 536                           "GDIWindowSurfaceData_GetWindow: disposed component");
 537             JNU_ThrowNullPointerException(env, "disposed component");
 538             return (HWND) NULL;
 539         }
 540         wsdo->window = window;
 541     }
 542 
 543     return window;
 544 }
 545 
 546 } /* extern "C" */
 547 
 548 static jboolean GDIWinSD_SimpleClip(JNIEnv *env, GDIWinSDOps *wsdo,
 549                                    SurfaceDataBounds *bounds,
 550                                    HDC hDC)
 551 {
 552     RECT rClip;
 553 
 554     J2dTraceLn(J2D_TRACE_INFO, "GDIWinSD_SimpleClip");
 555     if (hDC == NULL) {
 556         return JNI_FALSE;
 557     }
 558 
 559     int nComplexity = ::GetClipBox(hDC, &rClip);
 560 
 561     switch (nComplexity) {
 562     case COMPLEXREGION:
 563         {
 564             J2dTraceLn(J2D_TRACE_VERBOSE,
 565                        "  complex clipping region");
 566             // if complex user/system clip, more detailed testing required
 567             // check to see if the view itself has a complex clip.
 568             // ::GetClipBox is only API which returns overlapped window status
 569             // so we set the rView as our clip, and then see if resulting
 570             // clip is complex.
 571             // Only other way to figure this out would be to walk the
 572             // overlapping windows (no API to get the actual visible clip
 573             // list).  Then we'd still have to merge that info with the
 574             // clip region for the dc (if it exists).
 575             // REMIND: we can cache the CreateRectRgnIndirect result,
 576             // and only override with ::SetRectRgn
 577 
 578             // First, create a region handle (need existing HRGN for
 579             // the following call).
 580             HRGN rgnSave = ::CreateRectRgn(0, 0, 0, 0);
 581             int  clipStatus = ::GetClipRgn(hDC, rgnSave);
 582             if (-1 == clipStatus) {
 583                 J2dTraceLn(J2D_TRACE_WARNING,
 584                            "GDIWinSD_SimpleClip: failed due to clip status");
 585                 ::DeleteObject(rgnSave);
 586                 return JNI_FALSE;
 587             }
 588             HRGN rgnBounds = ::CreateRectRgn(
 589                 bounds->x1 - wsdo->insets.left,
 590                 bounds->y1 - wsdo->insets.top,
 591                 bounds->x2 - wsdo->insets.left,
 592                 bounds->y2 - wsdo->insets.top);
 593             ::SelectClipRgn(hDC, rgnBounds);
 594             nComplexity = ::GetClipBox(hDC, &rClip);
 595             ::SelectClipRgn(hDC, clipStatus? rgnSave: NULL);
 596             ::DeleteObject(rgnSave);
 597             ::DeleteObject(rgnBounds);
 598 
 599             // Now, test the new clip box.  If it's still not a
 600             // SIMPLE region, then our bounds must intersect part of
 601             // the clipping article
 602             if (SIMPLEREGION != nComplexity) {
 603                 J2dTraceLn(J2D_TRACE_WARNING,
 604                            "GDIWinSD_SimpleClip: failed due to complexity");
 605                 return JNI_FALSE;
 606             }
 607         }
 608         // NOTE: No break here - we want to fall through into the
 609         // SIMPLE case, adjust our bounds by the new rClip rect
 610         // and make sure that our locking bounds are not empty.
 611     case SIMPLEREGION:
 612         J2dTraceLn(J2D_TRACE_VERBOSE, "  simple clipping region");
 613         // Constrain the bounds to the given clip box
 614         if (bounds->x1 < rClip.left) {
 615             bounds->x1 = rClip.left;
 616         }
 617         if (bounds->y1 < rClip.top) {
 618             bounds->y1 = rClip.top;
 619         }
 620         if (bounds->x2 > rClip.right) {
 621             bounds->x2 = rClip.right;
 622         }
 623         if (bounds->y2 > rClip.bottom) {
 624             bounds->y2 = rClip.bottom;
 625         }
 626         // If the bounds are 0 or negative, then the bounds have
 627         // been obscured by the clip box, so return FALSE
 628         if ((bounds->x2 <= bounds->x1) ||
 629             (bounds->y2 <= bounds->y1)) {
 630             // REMIND: We should probably do something different here
 631             // instead of simply returning FALSE.  Since the bounds are
 632             // empty we won't end up drawing anything, so why spend the
 633             // effort of returning false and having GDI do a LOCK_BY_DIB?
 634             // Perhaps we need a new lock code that will indicate that we
 635             // shouldn't bother drawing?
 636             J2dTraceLn(J2D_TRACE_WARNING,
 637                        "GDIWinSD_SimpleClip: failed due to empty bounds");
 638             return JNI_FALSE;
 639         }
 640         break;
 641     case NULLREGION:
 642     case ERROR:
 643     default:
 644         J2dTraceLn1(J2D_TRACE_ERROR,
 645                    "GDIWinSD_SimpleClip: failed due to incorrect complexity=%d",
 646                     nComplexity);
 647         return JNI_FALSE;
 648     }
 649 
 650     return JNI_TRUE;
 651 }
 652 
 653 static jint GDIWinSD_Lock(JNIEnv *env,
 654                          SurfaceDataOps *ops,
 655                          SurfaceDataRasInfo *pRasInfo,
 656                          jint lockflags)
 657 {
 658     GDIWinSDOps *wsdo = (GDIWinSDOps *) ops;
 659     int ret = SD_SUCCESS;
 660     HDC hDC;
 661     J2dTraceLn(J2D_TRACE_INFO, "GDIWinSD_Lock");
 662 
 663     /* This surfaceLock replaces an earlier implementation which used a
 664     monitor associated with the peer.  That implementation was prone
 665     to deadlock problems, so it was replaced by a lock that does not
 666     have dependencies outside of this thread or object.
 667     However, this lock doesn't necessarily do all that we want.
 668     For example, a user may issue a call which results in a DIB lock
 669     and another call which results in a DDraw Blt.  We can't guarantee
 670     what order these operations happen in (they are driver and
 671     video-card dependent), so locking around the issue of either of
 672     those calls won't necessarily guarantee a particular result.
 673     The real solution might be to move away from mixing our
 674     rendering API's.  That is, if we only used DDraw, then we could
 675     guarantee that all rendering operations would happen in a given
 676     order.  Similarly for GDI.  But by mixing them, we leave our
 677     code at the mercy of driver bugs.*/
 678     wsdo->surfaceLock->Enter();
 679     if (wsdo->invalid == JNI_TRUE) {
 680         J2dTraceLn(J2D_TRACE_WARNING, "GDIWinSD_Lock: surface is invalid");
 681         wsdo->surfaceLock->Leave();
 682         if (beingShutdown != JNI_TRUE) {
 683             SurfaceData_ThrowInvalidPipeException(env,
 684                 "GDIWindowSurfaceData: bounds changed");
 685         }
 686         return SD_FAILURE;
 687     }
 688     if (wsdo->lockType != WIN32SD_LOCK_UNLOCKED) {
 689         wsdo->surfaceLock->Leave();
 690         if (!safe_ExceptionOccurred(env)) {
 691             JNU_ThrowInternalError(env, "Win32 LockRasData cannot nest locks");
 692         }
 693         return SD_FAILURE;
 694     }
 695 
 696     hDC = wsdo->GetDC(env, wsdo, 0, NULL, NULL, NULL, 0);
 697     if (hDC == NULL) {
 698         wsdo->surfaceLock->Leave();
 699         if (beingShutdown != JNI_TRUE) {
 700             JNU_ThrowNullPointerException(env, "HDC for component");
 701         }
 702         return SD_FAILURE;
 703     }
 704 
 705     if (lockflags & SD_LOCK_RD_WR) {
 706         // Do an initial clip to the client region of the window
 707         RECT crect;
 708         ::GetClientRect(wsdo->window, &crect);
 709 
 710         // Translate to window coords
 711         crect.left += wsdo->insets.left;
 712         crect.top += wsdo->insets.top;
 713         crect.right += wsdo->insets.left;
 714         crect.bottom += wsdo->insets.top;
 715 
 716         SurfaceDataBounds *bounds = &pRasInfo->bounds;
 717 
 718         if (bounds->x1 < crect.left) {
 719             bounds->x1 = crect.left;
 720         }
 721         if (bounds->y1 < crect.top) {
 722             bounds->y1 = crect.top;
 723         }
 724         if (bounds->x2 > crect.right) {
 725             bounds->x2 = crect.right;
 726         }
 727         if (bounds->y2 > crect.bottom) {
 728             bounds->y2 = crect.bottom;
 729         }
 730 
 731         if (bounds->x2 > bounds->x1 && bounds->y2 > bounds->y1) {
 732             wsdo->lockType = WIN32SD_LOCK_BY_DIB;
 733             if (lockflags & SD_LOCK_FASTEST) {
 734                 ret = SD_SLOWLOCK;
 735             }
 736             J2dTraceLn(J2D_TRACE_VERBOSE, " locked by DIB");
 737         } else {
 738             wsdo->ReleaseDC(env, wsdo, hDC);
 739             wsdo->lockType = WIN32SD_LOCK_UNLOCKED;
 740             wsdo->surfaceLock->Leave();
 741             ret = SD_FAILURE;
 742             J2dTraceLn(J2D_TRACE_ERROR,
 743                        "GDIWinSD_Lock: error locking by DIB");
 744         }
 745     } else {
 746         J2dTraceLn(J2D_TRACE_VERBOSE, "GDIWinSD_Lock: surface wasn't locked");
 747         /* They didn't lock for anything - we won't give them anything */
 748         wsdo->ReleaseDC(env, wsdo, hDC);
 749         wsdo->lockType = WIN32SD_LOCK_UNLOCKED;
 750         wsdo->surfaceLock->Leave();
 751         ret = SD_FAILURE;
 752     }
 753 
 754     wsdo->lockFlags = lockflags;
 755     return ret;
 756 }
 757 
 758 static void GDIWinSD_GetRasInfo(JNIEnv *env,
 759                                SurfaceDataOps *ops,
 760                                SurfaceDataRasInfo *pRasInfo)
 761 {
 762     GDIWinSDOps *wsdo = (GDIWinSDOps *) ops;
 763     jint lockflags = wsdo->lockFlags;
 764     J2dTraceLn(J2D_TRACE_INFO, "GDIWinSD_GetRasInfo");
 765     HDC hDC = GetThreadDC(env, wsdo);
 766 
 767     if (wsdo->lockType == WIN32SD_LOCK_UNLOCKED) {
 768         memset(pRasInfo, 0, sizeof(*pRasInfo));
 769         return;
 770     }
 771 
 772     if (wsdo->lockType == WIN32SD_LOCK_BY_DIB) {
 773         int x, y, w, h;
 774         int pixelStride = wsdo->pixelStride;
 775         // do not subtract insets from x,y as we take care of it in SD_GetDC
 776         x = pRasInfo->bounds.x1;
 777         y = pRasInfo->bounds.y1;
 778         w = pRasInfo->bounds.x2 - x;
 779         h = pRasInfo->bounds.y2 - y;
 780 
 781         struct tagBitmapheader  {
 782             BITMAPINFOHEADER bmiHeader;
 783             union {
 784                 DWORD           dwMasks[3];
 785                 RGBQUAD         palette[256];
 786             } colors;
 787         } bmi;
 788 
 789         // Need to create bitmap if we don't have one already or
 790         // if the existing one is not large enough for this operation
 791         // or if we are in 8 bpp display mode (because we need to
 792         // make sure that the latest palette info gets loaded into
 793         // the bitmap)
 794         // REMIND: we should find some way to dynamically force bitmap
 795         // recreation only when the palette changes
 796         if (pixelStride == 1 || !wsdo->bitmap || (w > wsdo->bmWidth) ||
 797             (h > wsdo->bmHeight))
 798         {
 799             if (wsdo->bitmap) {
 800                 // delete old objects
 801                 J2dTraceLn(J2D_TRACE_VERBOSE,
 802                            "GDIWinSD_GetRasInfo: recreating GDI bitmap");
 803                 if (wsdo->bmdc) {   // should not be null
 804                     ::SelectObject(wsdo->bmdc, wsdo->oldmap);
 805                     ::DeleteDC(wsdo->bmdc);
 806                     wsdo->bmdc = 0;
 807                 }
 808                 ::DeleteObject(wsdo->bitmap);
 809                 wsdo->bitmap = 0;
 810             }
 811             bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
 812             bmi.bmiHeader.biWidth = w;
 813             bmi.bmiHeader.biHeight = -h;
 814             wsdo->bmWidth = w;
 815             wsdo->bmHeight = h;
 816             bmi.bmiHeader.biPlanes = 1;
 817             bmi.bmiHeader.biBitCount = pixelStride * 8;
 818             // 1,3 byte use BI_RGB, 2,4 byte use BI_BITFIELD...
 819             bmi.bmiHeader.biCompression =
 820                 (pixelStride & 1)
 821                     ? BI_RGB
 822                     : BI_BITFIELDS;
 823             bmi.bmiHeader.biSizeImage = 0;
 824             bmi.bmiHeader.biXPelsPerMeter = 0;
 825             bmi.bmiHeader.biYPelsPerMeter = 0;
 826             bmi.bmiHeader.biClrUsed = 0;
 827             bmi.bmiHeader.biClrImportant = 0;
 828             if (pixelStride == 1) {
 829                 // we can use systemEntries here because
 830                 // RGBQUAD is xRGB and systemEntries are stored as xRGB
 831                 memcpy(bmi.colors.palette, wsdo->device->GetSystemPaletteEntries(),
 832                        sizeof(bmi.colors.palette));
 833             } else {
 834                 // For non-index cases, init the masks for the pixel depth
 835                 for (int i = 0; i < 3; i++) {
 836                     bmi.colors.dwMasks[i] = wsdo->pixelMasks[i];
 837                 }
 838             }
 839 
 840             // REMIND: This would be better if moved to the Lock function
 841             // so that errors could be dealt with.
 842             wsdo->bitmap = ::CreateDIBSection(hDC, (BITMAPINFO *) &bmi,
 843                                               DIB_RGB_COLORS, &wsdo->bmBuffer, NULL, 0);
 844             if (wsdo->bitmap != 0) {
 845                 // scanStride is cached along with reuseable bitmap
 846                 // Round up to the next DWORD boundary
 847                 wsdo->bmScanStride = (wsdo->bmWidth * pixelStride + 3) & ~3;
 848                 wsdo->bmdc = ::CreateCompatibleDC(hDC);
 849                 if (wsdo->bmdc == 0) {
 850                     ::DeleteObject(wsdo->bitmap);
 851                     wsdo->bitmap = 0;
 852                 } else {
 853                     wsdo->oldmap = (HBITMAP) ::SelectObject(wsdo->bmdc,
 854                                                             wsdo->bitmap);
 855                 }
 856             }
 857         }
 858         if (wsdo->bitmap != 0) {
 859             if (lockflags & SD_LOCK_NEED_PIXELS) {
 860                 int ret = ::BitBlt(wsdo->bmdc, 0, 0, w, h,
 861                                    hDC, x, y, SRCCOPY);
 862                 ::GdiFlush();
 863             }
 864             wsdo->x = x;
 865             wsdo->y = y;
 866             wsdo->w = w;
 867             wsdo->h = h;
 868             pRasInfo->rasBase = (char *)wsdo->bmBuffer - (x*pixelStride +
 869                                 y*wsdo->bmScanStride);
 870             pRasInfo->pixelStride = pixelStride;
 871             pRasInfo->pixelBitOffset = 0;
 872             pRasInfo->scanStride = wsdo->bmScanStride;
 873             if (lockflags & SD_LOCK_WRITE) {
 874                 // If the user writes to the bitmap then we should
 875                 // copy the bitmap to the screen during Unlock
 876                 wsdo->bmCopyToScreen = TRUE;
 877             }
 878         } else {
 879             pRasInfo->rasBase = NULL;
 880             pRasInfo->pixelStride = 0;
 881             pRasInfo->pixelBitOffset = 0;
 882             pRasInfo->scanStride = 0;
 883         }
 884     } else {
 885         /* They didn't lock for anything - we won't give them anything */
 886         pRasInfo->rasBase = NULL;
 887         pRasInfo->pixelStride = 0;
 888         pRasInfo->pixelBitOffset = 0;
 889         pRasInfo->scanStride = 0;
 890     }
 891     if (wsdo->lockFlags & SD_LOCK_LUT) {
 892         pRasInfo->lutBase =
 893             (long *) wsdo->device->GetSystemPaletteEntries();
 894         pRasInfo->lutSize = 256;
 895     } else {
 896         pRasInfo->lutBase = NULL;
 897         pRasInfo->lutSize = 0;
 898     }
 899     if (wsdo->lockFlags & SD_LOCK_INVCOLOR) {
 900         pRasInfo->invColorTable = wsdo->device->GetSystemInverseLUT();
 901         ColorData *cData = wsdo->device->GetColorData();
 902         pRasInfo->redErrTable = cData->img_oda_red;
 903         pRasInfo->grnErrTable = cData->img_oda_green;
 904         pRasInfo->bluErrTable = cData->img_oda_blue;
 905     } else {
 906         pRasInfo->invColorTable = NULL;
 907         pRasInfo->redErrTable = NULL;
 908         pRasInfo->grnErrTable = NULL;
 909         pRasInfo->bluErrTable = NULL;
 910     }
 911     if (wsdo->lockFlags & SD_LOCK_INVGRAY) {
 912         pRasInfo->invGrayTable =
 913             wsdo->device->GetColorData()->pGrayInverseLutData;
 914     } else {
 915         pRasInfo->invGrayTable = NULL;
 916     }
 917 }
 918 
 919 static void GDIWinSD_Setup(JNIEnv *env,
 920                           SurfaceDataOps *ops)
 921 {
 922     // Call SetupTGI to ensure that this thread already has a DC that is
 923     // compatible with this window.  This means that we won't be calling
 924     // ::SendMessage(GETDC) in the middle of a lock procedure, which creates
 925     // a potential deadlock situation.
 926     // Note that calling SetupTGI here means that anybody needing a DC
 927     // later in this rendering process need only call GetTGI, which
 928     // assumes that the TGI structure is valid for this thread/window.
 929     SetupThreadGraphicsInfo(env, (GDIWinSDOps*)ops);
 930 }
 931 
 932 
 933 static void GDIWinSD_Unlock(JNIEnv *env,
 934                            SurfaceDataOps *ops,
 935                            SurfaceDataRasInfo *pRasInfo)
 936 {
 937     GDIWinSDOps *wsdo = (GDIWinSDOps *) ops;
 938     J2dTraceLn(J2D_TRACE_INFO, "GDIWinSD_Unlock");
 939     HDC hDC = GetThreadDC(env, wsdo);
 940 
 941     if (wsdo->lockType == WIN32SD_LOCK_UNLOCKED) {
 942         if (!safe_ExceptionOccurred(env)) {
 943             JNU_ThrowInternalError(env,
 944                                    "Unmatched unlock on Win32 SurfaceData");
 945         }
 946         return;
 947     }
 948 
 949     if (wsdo->lockType == WIN32SD_LOCK_BY_DIB) {
 950         if (wsdo->lockFlags & SD_LOCK_WRITE) {
 951             J2dTraceLn(J2D_TRACE_VERBOSE,
 952                        "GDIWinSD_Unlock: do Blt of the bitmap");
 953             if (wsdo->bmCopyToScreen && ::IsWindowVisible(wsdo->window)) {
 954                 // Don't bother copying to screen if our window has gone away
 955                 // or if the bitmap was not actually written to during this
 956                 // Lock/Unlock procedure.
 957                 ::BitBlt(hDC, wsdo->x, wsdo->y, wsdo->w, wsdo->h,
 958                     wsdo->bmdc, 0, 0, SRCCOPY);
 959                 ::GdiFlush();
 960             }
 961             wsdo->bmCopyToScreen = FALSE;
 962         }
 963         wsdo->lockType = WIN32SD_LOCK_UNLOCKED;
 964         wsdo->ReleaseDC(env, wsdo, hDC);
 965     }
 966     wsdo->surfaceLock->Leave();
 967 }
 968 
 969 /*
 970  * REMIND: This mechanism is just a prototype of a way to manage a
 971  * small cache of DC objects.  It is incomplete in the following ways:
 972  *
 973  * - It is not thread-safe!  It needs appropriate locking and release calls
 974  *   (perhaps the AutoDC mechanisms from Kestrel)
 975  * - It does hardly any error checking (What if GetDCEx returns NULL?)
 976  * - It cannot handle printer DCs and their resolution
 977  * - It should probably "live" in the native SurfaceData object to allow
 978  *   alternate implementations for printing and embedding
 979  * - It doesn't handle XOR
 980  * - It caches the client bounds to determine if clipping is really needed
 981  *   (no way to invalidate the cached bounds and there is probably a better
 982  *    way to manage clip validation in any case)
 983  */
 984 
 985 #define COLORFOR(c)     (PALETTERGB(((c)>>16)&0xff,((c)>>8)&0xff,((c)&0xff)))
 986 
 987 COLORREF CheckGrayColor(GDIWinSDOps *wsdo, int c) {
 988     if (wsdo->device->GetGrayness() != GS_NOTGRAY) {
 989         int g = (77 *(c & 0xFF) +
 990                  150*((c >> 8) & 0xFF) +
 991                  29 *((c >> 16) & 0xFF) + 128) / 256;
 992         c = g | (g << 8) | (g << 16);
 993     }
 994     return COLORFOR(c);
 995 }
 996 
 997 static HDC GDIWinSD_GetDC(JNIEnv *env, GDIWinSDOps *wsdo,
 998                          jint type, jint *patrop,
 999                          jobject clip, jobject comp, jint color)
1000 {
1001     J2dTraceLn(J2D_TRACE_INFO, "GDIWinSD_GetDC");
1002 
1003     if (wsdo->invalid == JNI_TRUE) {
1004         if (beingShutdown != JNI_TRUE) {
1005             SurfaceData_ThrowInvalidPipeException(env, "bounds changed");
1006         }
1007         return (HDC) NULL;
1008     }
1009 
1010     ThreadGraphicsInfo *info = GetThreadGraphicsInfo(env, wsdo);
1011     GDIWinSD_InitDC(env, wsdo, info, type, patrop, clip, comp, color);
1012     return env->ExceptionCheck() ? (HDC)NULL : info->hDC;
1013 }
1014 
1015 JNIEXPORT void JNICALL
1016 GDIWinSD_InitDC(JNIEnv *env, GDIWinSDOps *wsdo, ThreadGraphicsInfo *info,
1017                jint type, jint *patrop,
1018                jobject clip, jobject comp, jint color)
1019 {
1020     J2dTraceLn(J2D_TRACE_INFO, "GDIWinSD_InitDC");
1021 
1022     // init clip
1023     if (clip == NULL) {
1024         if (info->type & CLIP) {
1025             ::SelectClipRgn(info->hDC, (HRGN) NULL);
1026             info->type ^= CLIP;
1027         }
1028         if (info->clip != NULL) {
1029             env->DeleteWeakGlobalRef(info->clip);
1030             info->clip = NULL;
1031         }
1032     } else if (!env->IsSameObject(clip, info->clip)) {
1033         SurfaceDataBounds span;
1034         RegionData clipInfo;
1035         if (Region_GetInfo(env, clip, &clipInfo)) {
1036             // return; // REMIND: What to do here?
1037         }
1038 
1039         if (Region_IsEmpty(&clipInfo)) {
1040             HRGN hrgn = ::CreateRectRgn(0, 0, 0, 0);
1041             ::SelectClipRgn(info->hDC, hrgn);
1042             ::DeleteObject(hrgn);
1043             info->type |= CLIP;
1044         } else if (Region_IsRectangular(&clipInfo)) {
1045             if (clipInfo.bounds.x1 <= info->bounds.left &&
1046                 clipInfo.bounds.y1 <= info->bounds.top &&
1047                 clipInfo.bounds.x2 >= info->bounds.right &&
1048                 clipInfo.bounds.y2 >= info->bounds.bottom)
1049             {
1050                 if (info->type & CLIP) {
1051                     ::SelectClipRgn(info->hDC, (HRGN) NULL);
1052                     info->type ^= CLIP;
1053                 }
1054             } else {
1055                 // Make the window-relative rect a client-relative
1056                 // one for Windows
1057                 HRGN hrgn =
1058                     ::CreateRectRgn(clipInfo.bounds.x1 - wsdo->insets.left,
1059                                     clipInfo.bounds.y1 - wsdo->insets.top,
1060                                     clipInfo.bounds.x2 - wsdo->insets.left,
1061                                     clipInfo.bounds.y2 - wsdo->insets.top);
1062                 ::SelectClipRgn(info->hDC, hrgn);
1063                 ::DeleteObject(hrgn);
1064                 info->type |= CLIP;
1065             }
1066         } else {
1067             int leftInset = wsdo->insets.left;
1068             int topInset = wsdo->insets.top;
1069             Region_StartIteration(env, &clipInfo);
1070             jint numrects = Region_CountIterationRects(&clipInfo);
1071             RGNDATA *lpRgnData;
1072             try {
1073                 lpRgnData = (RGNDATA *) SAFE_SIZE_STRUCT_ALLOC(safe_Malloc,
1074                     sizeof(RGNDATAHEADER), numrects, sizeof(RECT));
1075             } catch (std::bad_alloc&) {
1076                 JNU_ThrowOutOfMemoryError(env, "Initialization of surface region data failed.");
1077                 return;
1078             }
1079             const DWORD nCount = sizeof(RGNDATAHEADER) + numrects * sizeof(RECT);
1080             lpRgnData->rdh.dwSize = sizeof(RGNDATAHEADER);
1081             lpRgnData->rdh.iType = RDH_RECTANGLES;
1082             lpRgnData->rdh.nCount = numrects;
1083             lpRgnData->rdh.nRgnSize = 0;
1084             lpRgnData->rdh.rcBound.left = clipInfo.bounds.x1 - leftInset;
1085             lpRgnData->rdh.rcBound.top = clipInfo.bounds.y1 - topInset;
1086             lpRgnData->rdh.rcBound.right = clipInfo.bounds.x2 - leftInset;
1087             lpRgnData->rdh.rcBound.bottom = clipInfo.bounds.y2 - topInset;
1088             RECT *pRect = (RECT *) &(((RGNDATA *)lpRgnData)->Buffer);
1089             while (Region_NextIteration(&clipInfo, &span)) {
1090                 pRect->left = span.x1 - leftInset;
1091                 pRect->top = span.y1 - topInset;
1092                 pRect->right = span.x2 - leftInset;
1093                 pRect->bottom = span.y2 - topInset;
1094                 pRect++;
1095             }
1096             Region_EndIteration(env, &clipInfo);
1097             HRGN hrgn = ::ExtCreateRegion(NULL, nCount, lpRgnData);
1098             free(lpRgnData);
1099             ::SelectClipRgn(info->hDC, hrgn);
1100             ::DeleteObject(hrgn);
1101             info->type |= CLIP;
1102         }
1103         if (info->clip != NULL) {
1104             env->DeleteWeakGlobalRef(info->clip);
1105         }
1106         info->clip = env->NewWeakGlobalRef(clip);
1107         if (env->ExceptionCheck()) {
1108             return;
1109         }
1110     }
1111 
1112     // init composite
1113     if ((comp == NULL) || !env->IsInstanceOf(comp, xorCompClass)) {
1114         if (info->comp != NULL) {
1115             env->DeleteWeakGlobalRef(info->comp);
1116             info->comp = NULL;
1117             info->patrop = PATCOPY;
1118             ::SetROP2(info->hDC, R2_COPYPEN);
1119         }
1120     } else {
1121         if (!env->IsSameObject(comp, info->comp)) {
1122             info->xorcolor = GrPrim_CompGetXorColor(env, comp);
1123             if (info->comp != NULL) {
1124                 env->DeleteWeakGlobalRef(info->comp);
1125             }
1126             info->comp = env->NewWeakGlobalRef(comp);
1127             info->patrop = PATINVERT;
1128             ::SetROP2(info->hDC, R2_XORPEN);
1129         }
1130         color ^= info->xorcolor;
1131     }
1132 
1133     if (patrop != NULL) {
1134         *patrop = info->patrop;
1135     }
1136 
1137     // init brush and pen
1138     if (type & BRUSH) {
1139         if (info->brushclr != color || (info->brush == NULL)) {
1140             if (info->type & BRUSH) {
1141                 ::SelectObject(info->hDC, nullbrush);
1142                 info->type ^= BRUSH;
1143             }
1144             if (info->brush != NULL) {
1145                 info->brush->Release();
1146             }
1147             info->brush = AwtBrush::Get(CheckGrayColor(wsdo, color));
1148             info->brushclr = color;
1149         }
1150         if ((info->type & BRUSH) == 0) {
1151             ::SelectObject(info->hDC, info->brush->GetHandle());
1152             info->type ^= BRUSH;
1153         }
1154     } else if (type & NOBRUSH) {
1155         if (info->type & BRUSH) {
1156             ::SelectObject(info->hDC, nullbrush);
1157             info->type ^= BRUSH;
1158         }
1159     }
1160     if (type & PEN) {
1161         if (info->penclr != color || (info->pen == NULL)) {
1162             if (info->type & PEN) {
1163                 ::SelectObject(info->hDC, nullpen);
1164                 info->type ^= PEN;
1165             }
1166             if (info->pen != NULL) {
1167                 info->pen->Release();
1168             }
1169             info->pen = AwtPen::Get(CheckGrayColor(wsdo, color));
1170             info->penclr = color;
1171         }
1172         if ((info->type & PEN) == 0) {
1173             ::SelectObject(info->hDC, info->pen->GetHandle());
1174             info->type ^= PEN;
1175         }
1176     } else if (type & NOPEN) {
1177         if (info->type & PEN) {
1178             ::SelectObject(info->hDC, nullpen);
1179             info->type ^= PEN;
1180         }
1181     }
1182 }
1183 
1184 static void GDIWinSD_ReleaseDC(JNIEnv *env, GDIWinSDOps *wsdo, HDC hDC)
1185 {
1186     J2dTraceLn(J2D_TRACE_INFO, "GDIWinSD_ReleaseDC");
1187     // Don't actually do anything here: every thread holds its own
1188     // wsdo-specific DC until the thread goes away or the wsdo
1189     // is disposed.
1190 }
1191 
1192 
1193 static void GDIWinSD_InvalidateSD(JNIEnv *env, GDIWinSDOps *wsdo)
1194 {
1195     J2dTraceLn(J2D_TRACE_INFO, "GDIWinSD_InvalidateSD");
1196     J2dTraceLn2(J2D_TRACE_VERBOSE, "  wsdo=0x%x wsdo->window=0x%x",
1197                 wsdo, wsdo->window);
1198 
1199     wsdo->invalid = JNI_TRUE;
1200 }
1201 
1202 
1203 
1204 /*
1205  * Method:    GDIWinSD_Dispose
1206  */
1207 static void
1208 GDIWinSD_Dispose(JNIEnv *env, SurfaceDataOps *ops)
1209 {
1210     J2dTraceLn(J2D_TRACE_INFO, "GDIWinSD_Dispose");
1211     // ops is assumed non-null as it is checked in SurfaceData_DisposeOps
1212     GDIWinSDOps *wsdo = (GDIWinSDOps*)ops;
1213     if (wsdo->bitmap) {
1214         // delete old objects
1215         J2dTraceLn(J2D_TRACE_VERBOSE, "  disposing the GDI bitmap");
1216         if (wsdo->bmdc) {   // should not be null
1217             ::SelectObject(wsdo->bmdc, wsdo->oldmap);
1218             ::DeleteDC(wsdo->bmdc);
1219             wsdo->bmdc = 0;
1220         }
1221         ::DeleteObject(wsdo->bitmap);
1222         wsdo->bitmap = 0;
1223     }
1224     env->DeleteWeakGlobalRef(wsdo->peer);
1225     if (wsdo->device != NULL) {
1226         wsdo->device->Release();
1227         wsdo->device = NULL;
1228     }
1229     delete wsdo->surfaceLock;
1230 }
1231 
1232 
1233 /*
1234  * Class:     sun_java2d_windows_GDIWindowSurfaceData
1235  * Method:    invalidateSD
1236  * Signature: ()V
1237  */
1238 JNIEXPORT void JNICALL
1239 Java_sun_java2d_windows_GDIWindowSurfaceData_invalidateSD(JNIEnv *env, jobject wsd)
1240 {
1241     J2dTraceLn(J2D_TRACE_INFO, "GDIWindowSurfaceData_invalidateSD");
1242     GDIWinSDOps *wsdo = GDIWindowSurfaceData_GetOpsNoSetup(env, wsd);
1243     if (wsdo != NULL) {
1244         wsdo->InvalidateSD(env, wsdo);
1245     }
1246 }