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