1 /* 2 * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "awt.h" 27 #include <sun_java2d_windows_GDIBlitLoops.h> 28 #include "gdefs.h" 29 #include "Trace.h" 30 #include "GDIWindowSurfaceData.h" 31 32 static RGBQUAD *byteGrayPalette = NULL; 33 34 extern "C" { 35 36 typedef struct tagBitmapheader { 37 BITMAPINFOHEADER bmiHeader; 38 union { 39 DWORD dwMasks[3]; 40 RGBQUAD palette[256]; 41 } colors; 42 } BmiType; 43 44 /* 45 * Class: sun_java2d_windows_GDIBlitLoops 46 * Method: nativeBlit 47 * Signature: (Lsun/java2d/SurfaceData;Lsun/java2d/SurfaceData;IIIIIIZ)V 48 */ 49 JNIEXPORT void JNICALL 50 Java_sun_java2d_windows_GDIBlitLoops_nativeBlit 51 (JNIEnv *env, jobject joSelf, 52 jobject srcData, jobject dstData, 53 jobject clip, 54 jint srcx, jint srcy, 55 jint dstx, jint dsty, 56 jint width, jint height, 57 jint rmask, jint gmask, jint bmask, 58 jboolean needLut) 59 { 60 J2dTraceLn(J2D_TRACE_INFO, "GDIBlitLoops_nativeBlit"); 61 62 SurfaceDataRasInfo srcInfo; 63 SurfaceDataOps *srcOps = SurfaceData_GetOps(env, srcData); 64 GDIWinSDOps *dstOps = GDIWindowSurfaceData_GetOps(env, dstData); 65 jint lockFlags; 66 67 srcInfo.bounds.x1 = srcx; 68 srcInfo.bounds.y1 = srcy; 69 srcInfo.bounds.x2 = srcx + width; 70 srcInfo.bounds.y2 = srcy + height; 71 if (needLut) { 72 lockFlags = (SD_LOCK_READ | SD_LOCK_LUT); 73 } else { 74 lockFlags = SD_LOCK_READ; 75 } 76 // This method is used among other things for on-screen copyArea, in which 77 // case the source and destination surfaces are the same. It is important 78 // to first lock the source and then get the hDC for the destination 79 // surface because the same per-thread hDC will be used for both 80 // and we need to have the correct clip set to the hDC 81 // used with the SetDIBitsToDevice call. 82 if (srcOps->Lock(env, srcOps, &srcInfo, lockFlags) != SD_SUCCESS) { 83 return; 84 } 85 86 SurfaceDataBounds dstBounds = {dstx, dsty, dstx + width, dsty + height}; 87 // Intersect the source and dest rects. Note that the source blit bounds 88 // will be adjusted to the surfaces's bounds if needed. 89 SurfaceData_IntersectBlitBounds(&(srcInfo.bounds), &dstBounds, 90 dstx - srcx, dsty - srcy); 91 92 srcx = srcInfo.bounds.x1; 93 srcy = srcInfo.bounds.y1; 94 dstx = dstBounds.x1; 95 dsty = dstBounds.y1; 96 width = srcInfo.bounds.x2 - srcInfo.bounds.x1; 97 height = srcInfo.bounds.y2 - srcInfo.bounds.y1; 98 99 if (width > 0 && height > 0) 100 { 101 BmiType bmi; 102 // REMIND: A performance tweak here would be to make some of this 103 // data static. For example, we could have one structure that is 104 // always used for ByteGray copies and we only change dynamic data 105 // in the structure with every new copy. Also, we could store 106 // structures with Ops or with the Java objects so that surfaces 107 // could retain their own DIB info and we would not need to 108 // recreate it every time. 109 110 // GetRasInfo implicitly calls GetPrimitiveArrayCritical 111 // and since GetDC uses JNI it needs to be called first. 112 HDC hDC = dstOps->GetDC(env, dstOps, 0, NULL, clip, NULL, 0); 113 if (hDC == NULL) { 114 SurfaceData_InvokeUnlock(env, srcOps, &srcInfo); 115 return; 116 } 117 srcOps->GetRasInfo(env, srcOps, &srcInfo); 118 if (srcInfo.rasBase == NULL) { 119 dstOps->ReleaseDC(env, dstOps, hDC); 120 SurfaceData_InvokeUnlock(env, srcOps, &srcInfo); 121 return; 122 } 123 void *rasBase = ((char *)srcInfo.rasBase) + srcInfo.scanStride * srcy + 124 srcInfo.pixelStride * srcx; 125 126 // If scanlines are DWORD-aligned (scanStride is a multiple of 4), 127 // then we can do the work much faster. This is due to a constraint 128 // in the way DIBs are structured and parsed by GDI 129 jboolean fastBlt = ((srcInfo.scanStride & 0x03) == 0); 130 131 bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); 132 bmi.bmiHeader.biWidth = srcInfo.scanStride/srcInfo.pixelStride; 133 // fastBlt copies whole image in one call; else copy line-by-line 134 LONG dwHeight = srcInfo.bounds.y2 - srcInfo.bounds.y1; 135 bmi.bmiHeader.biHeight = (fastBlt) ? -dwHeight : -1; 136 bmi.bmiHeader.biPlanes = 1; 137 bmi.bmiHeader.biBitCount = (WORD)srcInfo.pixelStride * 8; 138 // 1,3,4 byte use BI_RGB, 2 byte use BI_BITFIELD... 139 // 4 byte _can_ use BI_BITFIELD, but this seems to cause a performance 140 // penalty. Since we only ever have one format (xrgb) for 32-bit 141 // images that enter this function, just use BI_RGB. 142 // Could do BI_RGB for 2-byte 555 format, but no perceived 143 // performance benefit. 144 bmi.bmiHeader.biCompression = (srcInfo.pixelStride != 2) 145 ? BI_RGB : BI_BITFIELDS; 146 bmi.bmiHeader.biSizeImage = (bmi.bmiHeader.biWidth * dwHeight * 147 srcInfo.pixelStride); 148 bmi.bmiHeader.biXPelsPerMeter = 0; 149 bmi.bmiHeader.biYPelsPerMeter = 0; 150 bmi.bmiHeader.biClrUsed = 0; 151 bmi.bmiHeader.biClrImportant = 0; 152 if (srcInfo.pixelStride == 1) { 153 // Copy palette info into bitmap for 8-bit image 154 if (needLut) { 155 memcpy(bmi.colors.palette, srcInfo.lutBase, srcInfo.lutSize * sizeof(RGBQUAD)); 156 if (srcInfo.lutSize != 256) { 157 bmi.bmiHeader.biClrUsed = srcInfo.lutSize; 158 } 159 } else { 160 // If no LUT needed, must be ByteGray src. If we have not 161 // yet created the byteGrayPalette, create it now and copy 162 // it into our temporary bmi structure. 163 // REMIND: byteGrayPalette is a leak since we do not have 164 // a mechanism to free it up. This should be fine, since it 165 // is only 256 bytes for any process and only gets malloc'd 166 // when using ByteGray surfaces. Eventually, we should use 167 // the new Disposer mechanism to delete this native memory. 168 if (byteGrayPalette == NULL) { 169 // assert (256 * sizeof(RGBQUAD)) <= SIZE_MAX 170 byteGrayPalette = (RGBQUAD *)safe_Malloc(256 * sizeof(RGBQUAD)); 171 for (int i = 0; i < 256; ++i) { 172 byteGrayPalette[i].rgbRed = i; 173 byteGrayPalette[i].rgbGreen = i; 174 byteGrayPalette[i].rgbBlue = i; 175 } 176 } 177 memcpy(bmi.colors.palette, byteGrayPalette, 256 * sizeof(RGBQUAD)); 178 } 179 } else if (srcInfo.pixelStride == 2) { 180 // For 16-bit case, init the masks for the pixel depth 181 bmi.colors.dwMasks[0] = rmask; 182 bmi.colors.dwMasks[1] = gmask; 183 bmi.colors.dwMasks[2] = bmask; 184 } 185 186 if (fastBlt) { 187 // Window could go away at any time, leaving bits on the screen 188 // from this GDI call, so make sure window still exists 189 if (::IsWindowVisible(dstOps->window)) { 190 // Could also call StretchDIBits. Testing showed slight 191 // performance advantage of SetDIBits instead, so since we 192 // have no need of scaling, might as well use SetDIBits. 193 SetDIBitsToDevice(hDC, dstx, dsty, width, height, 194 0, 0, 0, height, rasBase, 195 (BITMAPINFO*)&bmi, DIB_RGB_COLORS); 196 } 197 } else { 198 // Source scanlines not DWORD-aligned - copy each scanline individually 199 for (int i = 0; i < height; i += 1) { 200 if (::IsWindowVisible(dstOps->window)) { 201 SetDIBitsToDevice(hDC, dstx, dsty+i, width, 1, 202 0, 0, 0, 1, rasBase, 203 (BITMAPINFO*)&bmi, DIB_RGB_COLORS); 204 rasBase = (void*)((char*)rasBase + srcInfo.scanStride); 205 } else { 206 break; 207 } 208 } 209 } 210 dstOps->ReleaseDC(env, dstOps, hDC); 211 SurfaceData_InvokeRelease(env, srcOps, &srcInfo); 212 } 213 SurfaceData_InvokeUnlock(env, srcOps, &srcInfo); 214 215 return; 216 } 217 218 } // extern "C"