jdk/src/windows/native/sun/java2d/windows/DDBlitLoops.cpp
changeset 1024 2253d6d6cf2c
parent 1023 9a1c25552b10
parent 945 6838c1a3296a
child 1025 a9ba5ea0f1f7
equal deleted inserted replaced
1023:9a1c25552b10 1024:2253d6d6cf2c
     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 }