1 /* |
|
2 * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 #include <stdlib.h> |
|
27 #include <jni.h> |
|
28 #include <sun_java2d_windows_DDBlitLoops.h> |
|
29 #include <sun_java2d_windows_DDScaleLoops.h> |
|
30 #include "ddrawUtils.h" |
|
31 #include "GraphicsPrimitiveMgr.h" |
|
32 #include "Region.h" |
|
33 #include "Trace.h" |
|
34 |
|
35 extern int currNumDevices; |
|
36 extern CriticalSection windowMoveLock; |
|
37 |
|
38 extern "C" { |
|
39 |
|
40 /** |
|
41 * Return TRUE if rCheck is contained within rContainer |
|
42 */ |
|
43 INLINE BOOL RectInRect(RECT *rCheck, RECT *rContainer) |
|
44 { |
|
45 // Assumption: left <= right, top <= bottom |
|
46 if (rCheck->left >= rContainer->left && |
|
47 rCheck->right <= rContainer->right && |
|
48 rCheck->top >= rContainer->top && |
|
49 rCheck->bottom <= rContainer->bottom) |
|
50 { |
|
51 return TRUE; |
|
52 } else { |
|
53 return FALSE; |
|
54 } |
|
55 } |
|
56 |
|
57 /** |
|
58 * Returns whether the given rectangle (in screen-relative |
|
59 * coords) is within the rectangle of the given device. |
|
60 * NOTE: A side-effect of this function is offsetting the |
|
61 * rectangle by the left/top of the monitor rectangle. |
|
62 */ |
|
63 INLINE BOOL RectInDevice(RECT *rect, AwtWin32GraphicsDevice *device) |
|
64 { |
|
65 MONITOR_INFO *mi = device->GetMonitorInfo(); |
|
66 ::OffsetRect(rect, mi->rMonitor.left, mi->rMonitor.top); |
|
67 if (!RectInRect(rect, &mi->rMonitor)) { |
|
68 return TRUE; |
|
69 } |
|
70 return FALSE; |
|
71 } |
|
72 |
|
73 /** |
|
74 * Need to handle Blt to other devices iff: |
|
75 * - there are >1 devices on the system |
|
76 * - at least one of src/dest is an onscreen window |
|
77 * - the onscreen window overlaps with |
|
78 * a monitor which is not the monitor associated with the window |
|
79 */ |
|
80 void MultimonBlt(JNIEnv *env, Win32SDOps *wsdoSrc, Win32SDOps *wsdoDst, |
|
81 jobject clip, |
|
82 jint srcx, jint srcy, |
|
83 jint dstx, jint dsty, |
|
84 RECT *rSrc, RECT *rDst) |
|
85 { |
|
86 J2dTraceLn(J2D_TRACE_INFO, "MultimonBlt"); |
|
87 J2dTraceLn4(J2D_TRACE_VERBOSE, |
|
88 " srcx=%-4d srcy=%-4d dstx=%-4d dsty=%-4d", |
|
89 srcx, srcy, dstx, dsty); |
|
90 if (rSrc == NULL) { |
|
91 J2dTraceLn(J2D_TRACE_ERROR, "MultimonBlt: null rSrc"); |
|
92 return; |
|
93 } |
|
94 J2dTraceLn4(J2D_TRACE_VERBOSE, |
|
95 " rSrc: l=%-4d t=%-4d r=%-4d b=%-4d", |
|
96 rSrc->left, rSrc->top, rSrc->right, rSrc->bottom); |
|
97 if (rDst == NULL) { |
|
98 J2dTraceLn(J2D_TRACE_ERROR, "MultimonBlt: null rDst"); |
|
99 return; |
|
100 } |
|
101 J2dTraceLn4(J2D_TRACE_VERBOSE, |
|
102 " rDst: l=%-4d t=%-4d r=%-4d b=%-4d", |
|
103 rDst->left, rDst->top, rDst->right, rDst->bottom); |
|
104 int currentDevice = -1; |
|
105 RECT rectToIntersect; |
|
106 |
|
107 if (!(wsdoSrc->window || wsdoDst->window)) |
|
108 { |
|
109 // Neither surface is onscreen: nothing to do |
|
110 return; |
|
111 } |
|
112 BOOL doGdiBlt = FALSE; |
|
113 if (wsdoSrc->window) { |
|
114 doGdiBlt = RectInDevice(rSrc, wsdoSrc->device); |
|
115 if (doGdiBlt) { |
|
116 currentDevice = wsdoSrc->device->GetDeviceIndex(); |
|
117 rectToIntersect = *rSrc; |
|
118 } |
|
119 } else if (wsdoDst->window) { |
|
120 doGdiBlt = RectInDevice(rDst, wsdoDst->device); |
|
121 if (doGdiBlt) { |
|
122 currentDevice = wsdoDst->device->GetDeviceIndex(); |
|
123 rectToIntersect = *rDst; |
|
124 } |
|
125 } |
|
126 if (doGdiBlt) { |
|
127 // Need to invoke Setup functions to setup HDCs because we used |
|
128 // the NoSetup versions of GetOps for performance reasons |
|
129 SurfaceData_InvokeSetup(env, (SurfaceDataOps*)wsdoSrc); |
|
130 SurfaceData_InvokeSetup(env, (SurfaceDataOps*)wsdoDst); |
|
131 HDC hdcSrc = wsdoSrc->GetDC(env, wsdoSrc, 0, NULL, NULL, NULL, 0); |
|
132 if (!hdcSrc) { |
|
133 J2dTraceLn(J2D_TRACE_WARNING, |
|
134 "MultimonBlt: Null src HDC in MultimonBlt"); |
|
135 return; |
|
136 } |
|
137 HDC hdcDst = wsdoDst->GetDC(env, wsdoDst, 0, NULL, clip, NULL, 0); |
|
138 if (!hdcDst) { |
|
139 J2dTraceLn(J2D_TRACE_WARNING, |
|
140 "MultimonBlt: Null dst HDC in MultimonBlt"); |
|
141 wsdoSrc->ReleaseDC(env, wsdoSrc, hdcSrc); |
|
142 return; |
|
143 } |
|
144 for (int i = 0; i < currNumDevices; ++i) { |
|
145 // Assumption: can't end up here for copies between two |
|
146 // different windows; it must be a copy between offscreen |
|
147 // surfaces or a window and an offscreen surface. We've |
|
148 // already handled the Blt to window on the window's native |
|
149 // GraphicsDevice, so skip that device now. |
|
150 if (i == currentDevice) { |
|
151 continue; |
|
152 } |
|
153 MONITOR_INFO *mi = AwtWin32GraphicsDevice::GetMonitorInfo(i); |
|
154 RECT rIntersect; |
|
155 ::IntersectRect(&rIntersect, &rectToIntersect, &mi->rMonitor); |
|
156 if (!::IsRectEmpty(&rIntersect)) { |
|
157 int newSrcX = srcx + (rIntersect.left - rectToIntersect.left); |
|
158 int newSrcY = srcy + (rIntersect.top - rectToIntersect.top); |
|
159 int newDstX = dstx + (rIntersect.left - rectToIntersect.left); |
|
160 int newDstY = dsty + (rIntersect.top - rectToIntersect.top); |
|
161 int newW = rIntersect.right - rIntersect.left; |
|
162 int newH = rIntersect.bottom - rIntersect.top; |
|
163 ::BitBlt(hdcDst, newDstX, newDstY, newW, newH, hdcSrc, |
|
164 newSrcX, newSrcY, SRCCOPY); |
|
165 } |
|
166 } |
|
167 wsdoSrc->ReleaseDC(env, wsdoSrc, hdcSrc); |
|
168 wsdoDst->ReleaseDC(env, wsdoDst, hdcDst); |
|
169 } |
|
170 } |
|
171 |
|
172 JNIEXPORT void JNICALL |
|
173 Java_sun_java2d_windows_DDBlitLoops_Blit |
|
174 (JNIEnv *env, jobject joSelf, |
|
175 jobject srcData, jobject dstData, |
|
176 jobject composite, jobject clip, |
|
177 jint srcx, jint srcy, |
|
178 jint dstx, jint dsty, |
|
179 jint width, jint height) |
|
180 { |
|
181 J2dTraceLn(J2D_TRACE_INFO, "DDBlitLoops_Blit"); |
|
182 J2dTraceLn4(J2D_TRACE_VERBOSE, |
|
183 " srcx=%-4d srcy=%-4d dstx=%-4d dsty=%-4d", |
|
184 srcx, srcy, dstx, dsty); |
|
185 J2dTraceLn2(J2D_TRACE_VERBOSE, " width=%-4d height=%-4d", width, height); |
|
186 POINT ptDst = {0, 0}; |
|
187 POINT ptSrc = {0, 0}; |
|
188 Win32SDOps *wsdoSrc = Win32SurfaceData_GetOpsNoSetup(env, srcData); |
|
189 Win32SDOps *wsdoDst = Win32SurfaceData_GetOpsNoSetup(env, dstData); |
|
190 RegionData clipInfo; |
|
191 |
|
192 if (!wsdoSrc->ddInstance || !wsdoDst->ddInstance) { |
|
193 // Some situations can cause us to fail on primary |
|
194 // creation, resulting in null lpSurface and null ddInstance |
|
195 // for a Win32Surface object.. Just noop this call in that case. |
|
196 return; |
|
197 } |
|
198 |
|
199 if (wsdoSrc->invalid || wsdoDst->invalid) { |
|
200 SurfaceData_ThrowInvalidPipeException(env, |
|
201 "DDBlitLoops_Blit: invalid surface data"); |
|
202 return; |
|
203 } |
|
204 |
|
205 RECT rSrc = {srcx, srcy, srcx + width, srcy + height}; |
|
206 RECT rDst = {dstx, dsty, dstx + width, dsty + height}; |
|
207 if (Region_GetInfo(env, clip, &clipInfo)) { |
|
208 return; |
|
209 } |
|
210 |
|
211 /* If dst and/or src are offscreen surfaces, need to make sure |
|
212 that Blt is within the boundaries of those surfaces. If not, |
|
213 clip the surface in question and also clip the other |
|
214 surface by the same amount. |
|
215 */ |
|
216 if (!wsdoDst->window) { |
|
217 CLIP2RECTS(rDst, 0, 0, wsdoDst->w, wsdoDst->h, rSrc); |
|
218 } |
|
219 CLIP2RECTS(rDst, |
|
220 clipInfo.bounds.x1, clipInfo.bounds.y1, |
|
221 clipInfo.bounds.x2, clipInfo.bounds.y2, |
|
222 rSrc); |
|
223 if (!wsdoSrc->window) { |
|
224 CLIP2RECTS(rSrc, 0, 0, wsdoSrc->w, wsdoSrc->h, rDst); |
|
225 } |
|
226 Region_IntersectBoundsXYXY(&clipInfo, |
|
227 rDst.left, rDst.top, |
|
228 rDst.right, rDst.bottom); |
|
229 if (Region_IsEmpty(&clipInfo)) { |
|
230 return; |
|
231 } |
|
232 if (wsdoDst->window || wsdoSrc->window) { |
|
233 if ((wsdoDst->window && !::IsWindowVisible(wsdoDst->window)) || |
|
234 (wsdoSrc->window && !::IsWindowVisible(wsdoSrc->window))) |
|
235 { |
|
236 return; |
|
237 } |
|
238 // The windowMoveLock CriticalSection ensures that a window cannot |
|
239 // move while we are in the middle of copying pixels into it. See |
|
240 // the WM_WINDOWPOSCHANGING code in awt_Component.cpp for more |
|
241 // information. |
|
242 windowMoveLock.Enter(); |
|
243 if (wsdoDst->window) { |
|
244 ::ClientToScreen(wsdoDst->window, &ptDst); |
|
245 MONITOR_INFO *mi = wsdoDst->device->GetMonitorInfo(); |
|
246 ptDst.x -= wsdoDst->insets.left; |
|
247 ptDst.y -= wsdoDst->insets.top; |
|
248 ptDst.x -= mi->rMonitor.left; |
|
249 ptDst.y -= mi->rMonitor.top; |
|
250 ::OffsetRect(&rDst, ptDst.x, ptDst.y); |
|
251 } |
|
252 if (wsdoSrc->window) { |
|
253 MONITOR_INFO *mi = wsdoDst->device->GetMonitorInfo(); |
|
254 ::ClientToScreen(wsdoSrc->window, &ptSrc); |
|
255 ptSrc.x -= wsdoSrc->insets.left; |
|
256 ptSrc.y -= wsdoSrc->insets.top; |
|
257 ptSrc.x -= mi->rMonitor.left; |
|
258 ptSrc.y -= mi->rMonitor.top; |
|
259 ::OffsetRect(&rSrc, ptSrc.x, ptSrc.y); |
|
260 } |
|
261 } |
|
262 if (Region_IsRectangular(&clipInfo)) { |
|
263 DDBlt(env, wsdoSrc, wsdoDst, &rDst, &rSrc); |
|
264 } else { |
|
265 SurfaceDataBounds span; |
|
266 RECT rSrcSpan, rDstSpan; |
|
267 ptSrc.x += srcx - dstx; |
|
268 ptSrc.y += srcy - dsty; |
|
269 Region_StartIteration(env, &clipInfo); |
|
270 while (Region_NextIteration(&clipInfo, &span)) { |
|
271 ::SetRect(&rDstSpan, span.x1, span.y1, span.x2, span.y2); |
|
272 ::CopyRect(&rSrcSpan, &rDstSpan); |
|
273 ::OffsetRect(&rDstSpan, ptDst.x, ptDst.y); |
|
274 ::OffsetRect(&rSrcSpan, ptSrc.x, ptSrc.y); |
|
275 DDBlt(env, wsdoSrc, wsdoDst, &rDstSpan, &rSrcSpan); |
|
276 } |
|
277 Region_EndIteration(env, &clipInfo); |
|
278 } |
|
279 if (wsdoDst->window || wsdoSrc->window) { |
|
280 windowMoveLock.Leave(); |
|
281 } |
|
282 |
|
283 if (currNumDevices > 1) { |
|
284 // Also need to handle Blit in multimon case, where part of the |
|
285 // source or dest lies on a different device |
|
286 MultimonBlt(env, wsdoSrc, wsdoDst, clip, srcx, srcy, dstx, dsty, |
|
287 &rSrc, &rDst); |
|
288 } |
|
289 } |
|
290 |
|
291 |
|
292 JNIEXPORT void JNICALL |
|
293 Java_sun_java2d_windows_DDScaleLoops_Scale |
|
294 (JNIEnv *env, jobject joSelf, |
|
295 jobject srcData, jobject dstData, |
|
296 jobject composite, |
|
297 jint srcx, jint srcy, |
|
298 jint dstx, jint dsty, |
|
299 jint srcWidth, jint srcHeight, |
|
300 jint dstWidth, jint dstHeight) |
|
301 { |
|
302 J2dTraceLn(J2D_TRACE_INFO, "DDScaleLoops_Scale"); |
|
303 J2dTraceLn4(J2D_TRACE_VERBOSE, |
|
304 " srcx=%-4d srcy=%-4d dstx=%-4d dsty=%-4d", |
|
305 srcx, srcy, dstx, dsty); |
|
306 J2dTraceLn4(J2D_TRACE_VERBOSE, |
|
307 " srcWidth=%-4d srcHeight=%-4d dstWidth=%-4d dstHeight=%-4d", |
|
308 srcWidth, srcHeight, dstWidth, dstHeight); |
|
309 POINT ptDst = {0, 0}; |
|
310 POINT ptSrc = {0, 0}; |
|
311 Win32SDOps *wsdoSrc = Win32SurfaceData_GetOpsNoSetup(env, srcData); |
|
312 Win32SDOps *wsdoDst = Win32SurfaceData_GetOpsNoSetup(env, dstData); |
|
313 |
|
314 if (!wsdoSrc->ddInstance || !wsdoDst->ddInstance) { |
|
315 // Some situations can cause us to fail on primary |
|
316 // creation, resulting in null lpSurface and null ddInstance |
|
317 // for a Win32Surface object.. Just noop this call in that case. |
|
318 return; |
|
319 } |
|
320 |
|
321 if (wsdoSrc->invalid || wsdoDst->invalid) { |
|
322 SurfaceData_ThrowInvalidPipeException(env, |
|
323 "DDBlitLoops_Scale: invalid surface data"); |
|
324 return; |
|
325 } |
|
326 |
|
327 RECT rSrc = {srcx, srcy, srcx + srcWidth, srcy + srcHeight}; |
|
328 RECT rDst = {dstx, dsty, dstx + dstWidth, dsty + dstHeight}; |
|
329 |
|
330 /* If dst and/or src are offscreen surfaces, need to make sure |
|
331 that Blt is within the boundaries of those surfaces. If not, |
|
332 clip the surface in question and also rescale the other |
|
333 surface according to the new scaling rectangle. |
|
334 */ |
|
335 if (!wsdoDst->window && |
|
336 (dstx < 0 || dsty < 0 || |
|
337 rDst.right > wsdoDst->w || rDst.bottom > wsdoDst->h)) |
|
338 { |
|
339 RECT newRDst; |
|
340 newRDst.left = max(0, rDst.left); |
|
341 newRDst.top = max(0, rDst.top); |
|
342 newRDst.right = min(wsdoDst->w, rDst.right); |
|
343 newRDst.bottom = min(wsdoDst->h, rDst.bottom); |
|
344 double srcDstScaleW = (double)srcWidth/(double)dstWidth; |
|
345 double srcDstScaleH = (double)srcHeight/(double)dstHeight; |
|
346 rSrc.left += (int)(srcDstScaleW * (newRDst.left - rDst.left)); |
|
347 rSrc.top += (int)(srcDstScaleH * (newRDst.top - rDst.top)); |
|
348 rSrc.right += (int)(srcDstScaleW * (newRDst.right - rDst.right)); |
|
349 rSrc.bottom += (int)(srcDstScaleH * (newRDst.bottom - rDst.bottom)); |
|
350 rDst = newRDst; |
|
351 } |
|
352 if (!wsdoSrc->window && |
|
353 (srcx < 0 || srcy < 0 || |
|
354 rSrc.right > wsdoSrc->w || rSrc.bottom > wsdoSrc->h)) |
|
355 { |
|
356 RECT newRSrc; |
|
357 newRSrc.left = max(0, rSrc.left); |
|
358 newRSrc.top = max(0, rSrc.top); |
|
359 newRSrc.right = min(wsdoSrc->w, rSrc.right); |
|
360 newRSrc.bottom = min(wsdoSrc->h, rSrc.bottom); |
|
361 double dstSrcScaleW = (double)dstWidth/(double)srcWidth; |
|
362 double dstSrcScaleH = (double)dstHeight/(double)srcHeight; |
|
363 rDst.left += (int)(dstSrcScaleW * (newRSrc.left - rSrc.left)); |
|
364 rDst.top += (int)(dstSrcScaleH * (newRSrc.top - rSrc.top)); |
|
365 rDst.right += (int)(dstSrcScaleW * (newRSrc.right - rSrc.right)); |
|
366 rDst.bottom += (int)(dstSrcScaleH * (newRSrc.bottom - rSrc.bottom)); |
|
367 rSrc = newRSrc; |
|
368 } |
|
369 if (wsdoDst->window || wsdoSrc->window) { |
|
370 if ((wsdoDst->window && !::IsWindowVisible(wsdoDst->window)) || |
|
371 (wsdoSrc->window && !::IsWindowVisible(wsdoSrc->window))) |
|
372 { |
|
373 return; |
|
374 } |
|
375 // The windowMoveLock CriticalSection ensures that a window cannot |
|
376 // move while we are in the middle of copying pixels into it. See |
|
377 // the WM_WINDOWPOSCHANGING code in awt_Component.cpp for more |
|
378 // information. |
|
379 windowMoveLock.Enter(); |
|
380 if (wsdoDst->window) { |
|
381 ::ClientToScreen(wsdoDst->window, &ptDst); |
|
382 MONITOR_INFO *mi = wsdoDst->device->GetMonitorInfo(); |
|
383 ptDst.x -= wsdoDst->insets.left; |
|
384 ptDst.y -= wsdoDst->insets.top; |
|
385 ptDst.x -= mi->rMonitor.left; |
|
386 ptDst.y -= mi->rMonitor.top; |
|
387 ::OffsetRect(&rDst, ptDst.x, ptDst.y); |
|
388 } |
|
389 if (wsdoSrc->window) { |
|
390 MONITOR_INFO *mi = wsdoDst->device->GetMonitorInfo(); |
|
391 ::ClientToScreen(wsdoSrc->window, &ptSrc); |
|
392 ptSrc.x -= wsdoSrc->insets.left; |
|
393 ptSrc.y -= wsdoSrc->insets.top; |
|
394 ptSrc.x -= mi->rMonitor.left; |
|
395 ptSrc.y -= mi->rMonitor.top; |
|
396 ::OffsetRect(&rSrc, ptSrc.x, ptSrc.y); |
|
397 } |
|
398 } |
|
399 DDBlt(env, wsdoSrc, wsdoDst, &rDst, &rSrc); |
|
400 if (wsdoDst->window || wsdoSrc->window) { |
|
401 windowMoveLock.Leave(); |
|
402 } |
|
403 |
|
404 if (currNumDevices > 1) { |
|
405 // Also need to handle Blit in multimon case, where part of the |
|
406 // source or dest lies on a different device |
|
407 MultimonBlt(env, wsdoSrc, wsdoDst, NULL, srcx, srcy, dstx, dsty, |
|
408 &rSrc, &rDst); |
|
409 } |
|
410 } |
|
411 |
|
412 |
|
413 } |
|