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 }