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) { 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 }