rev 50304 : 8204085: avoid printing uninitialized pointer in java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.cpp
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 = NULL;
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 }
--- EOF ---