void SplashInitFrameShape(Splash * splash, int imageIndex) { RGNDATA *pRgnData; RGNDATAHEADER *pRgnHdr; ImageRect maskRect; if (!splash->maskRequired) return; /* reserving memory for the worst case */ if (!IS_SAFE_SIZE_MUL(splash->width / 2 + 1, splash->height)) { return; } pRgnData = (RGNDATA *) SAFE_SIZE_STRUCT_ALLOC(malloc, sizeof(RGNDATAHEADER), sizeof(RECT), (splash->width / 2 + 1) * splash->height); if (!pRgnData) { return; } pRgnHdr = (RGNDATAHEADER *) pRgnData; initRect(&maskRect, 0, 0, splash->width, splash->height, 1, splash->width * splash->imageFormat.depthBytes, splash->frames[imageIndex].bitmapBits, &splash->imageFormat); pRgnHdr->dwSize = sizeof(RGNDATAHEADER); pRgnHdr->iType = RDH_RECTANGLES; pRgnHdr->nRgnSize = 0; pRgnHdr->rcBound.top = 0; pRgnHdr->rcBound.left = 0; pRgnHdr->rcBound.bottom = splash->height; pRgnHdr->rcBound.right = splash->width; pRgnHdr->nCount = BitmapToYXBandedRectangles(&maskRect, (RECT *) (((BYTE *) pRgnData) + sizeof(RGNDATAHEADER))); splash->frames[imageIndex].hRgn = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + sizeof(RECT) * pRgnHdr->nCount, pRgnData); free(pRgnData); }
JNIEXPORT jlong JNICALL Java_sun_font_FileFontStrike__1getGlyphImageFromWindows (JNIEnv *env, jobject unused, jstring fontFamily, jint style, jint size, jint glyphCode, jboolean fm) { GLYPHMETRICS glyphMetrics; LOGFONTW lf; BITMAPINFO bmi; TEXTMETRIC textMetric; RECT rect; int bytesWidth, dibBytesWidth, extra, imageSize, dibImageSize; unsigned char* dibImage = NULL, *rowPtr, *pixelPtr, *dibPixPtr, *dibRowPtr; unsigned char r,g,b; unsigned char* igTable; GlyphInfo* glyphInfo = NULL; int nameLen; LPWSTR name; HFONT oldFont, hFont; MAT2 mat2; unsigned short width; unsigned short height; short advanceX; short advanceY; int topLeftX; int topLeftY; int err; int bmWidth, bmHeight; int x, y; HBITMAP hBitmap = NULL, hOrigBM; int gamma, orient; HWND hWnd = NULL; HDC hDesktopDC = NULL; HDC hMemoryDC = NULL; hWnd = GetDesktopWindow(); hDesktopDC = GetWindowDC(hWnd); if (hDesktopDC == NULL) { return (jlong)0; } if (GetDeviceCaps(hDesktopDC, BITSPIXEL) < 15) { FREE_AND_RETURN; } hMemoryDC = CreateCompatibleDC(hDesktopDC); if (hMemoryDC == NULL || fontFamily == NULL) { FREE_AND_RETURN; } err = SetMapMode(hMemoryDC, MM_TEXT); if (err == 0) { FREE_AND_RETURN; } memset(&lf, 0, sizeof(LOGFONTW)); lf.lfHeight = -size; lf.lfWeight = (style & 1) ? FW_BOLD : FW_NORMAL; lf.lfItalic = (style & 2) ? 0xff : 0; lf.lfCharSet = DEFAULT_CHARSET; lf.lfQuality = CLEARTYPE_QUALITY; lf.lfOutPrecision = OUT_TT_PRECIS; lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; lf.lfPitchAndFamily = DEFAULT_PITCH; nameLen = (*env)->GetStringLength(env, fontFamily); name = (LPWSTR)alloca((nameLen+1)*2); if (name == NULL) { FREE_AND_RETURN; } (*env)->GetStringRegion(env, fontFamily, 0, nameLen, name); name[nameLen] = '\0'; if (nameLen < (sizeof(lf.lfFaceName) / sizeof(lf.lfFaceName[0]))) { wcscpy(lf.lfFaceName, name); } else { FREE_AND_RETURN; } hFont = CreateFontIndirectW(&lf); if (hFont == NULL) { FREE_AND_RETURN; } oldFont = SelectObject(hMemoryDC, hFont); memset(&textMetric, 0, sizeof(TEXTMETRIC)); err = GetTextMetrics(hMemoryDC, &textMetric); if (err == 0) { FREE_AND_RETURN; } memset(&glyphMetrics, 0, sizeof(GLYPHMETRICS)); memset(&mat2, 0, sizeof(MAT2)); mat2.eM11.value = 1; mat2.eM22.value = 1; err = GetGlyphOutline(hMemoryDC, glyphCode, GGO_METRICS|GGO_GLYPH_INDEX, &glyphMetrics, 0, NULL, &mat2); if (err == GDI_ERROR) { /* Probably no such glyph - ie the font wasn't the one we expected. */ FREE_AND_RETURN; } width = (unsigned short)glyphMetrics.gmBlackBoxX; height = (unsigned short)glyphMetrics.gmBlackBoxY; /* Don't handle "invisible" glyphs in this code */ if (width <= 0 || height == 0) { FREE_AND_RETURN; } advanceX = glyphMetrics.gmCellIncX; advanceY = glyphMetrics.gmCellIncY; topLeftX = glyphMetrics.gmptGlyphOrigin.x; topLeftY = glyphMetrics.gmptGlyphOrigin.y; /* GetGlyphOutline pre-dates cleartype and I'm not sure that it will * account for all pixels touched by the rendering. Need to widen, * and also adjust by one the x position at which it is rendered. * The extra pixels of width are used as follows : * One extra pixel at the left and the right will be needed to absorb * the pixels that will be touched by filtering by GDI to compensate * for colour fringing. * However there seem to be some cases where GDI renders two extra * pixels to the right, so we add one additional pixel to the right, * and in the code that copies this to the image cache we test for * the (rare) cases when this is touched, and if its not reduce the * stated image width for the blitting loops. * For fractional metrics : * One extra pixel at each end to account for sub-pixel positioning used * when fractional metrics is on in LCD mode. * The pixel at the left is needed so the blitting loop can index into * that a byte at a time to more accurately position the glyph. * The pixel at the right is needed so that when such indexing happens, * the blitting still can use the same width. * Consequently the width that is specified for the glyph is one less * than that of the actual image. * Note that in the FM case as a consequence we need to adjust the * position at which GDI renders, and the declared width of the glyph * See the if (fm) {} cases in the code. * For the non-FM case, we not only save 3 bytes per row, but this * prevents apparent glyph overlapping which affects the rendering * performance of accelerated pipelines since it adds additional * read-back requirements. */ width+=3; if (fm) { width+=1; } /* DIB scanline must end on a DWORD boundary. We specify 3 bytes per pixel, * so must round up as needed to a multiple of 4 bytes. */ dibBytesWidth = bytesWidth = width*3; extra = dibBytesWidth % 4; if (extra != 0) { dibBytesWidth += (4-extra); } /* The glyph cache image must be a multiple of 3 bytes wide. */ extra = bytesWidth % 3; if (extra != 0) { bytesWidth += (3-extra); } bmWidth = width; bmHeight = height; /* Must use desktop DC to create a bitmap of that depth */ hBitmap = CreateCompatibleBitmap(hDesktopDC, bmWidth, bmHeight); if (hBitmap == NULL) { FREE_AND_RETURN; } hOrigBM = (HBITMAP)SelectObject(hMemoryDC, hBitmap); /* Fill in black */ rect.left = 0; rect.top = 0; rect.right = bmWidth; rect.bottom = bmHeight; FillRect(hMemoryDC, (LPRECT)&rect, GetStockObject(BLACK_BRUSH)); /* Set text color to white, background to black. */ SetBkColor(hMemoryDC, RGB(0,0,0)); SetTextColor(hMemoryDC, RGB(255,255,255)); /* adjust rendering position */ x = -topLeftX+1; if (fm) { x += 1; } y = topLeftY - textMetric.tmAscent; err = ExtTextOutW(hMemoryDC, x, y, ETO_GLYPH_INDEX|ETO_OPAQUE, (LPRECT)&rect, (LPCWSTR)&glyphCode, 1, NULL); if (err == 0) { FREE_AND_RETURN; } /* Now get the image into a DIB. * MS docs for GetDIBits says the compatible bitmap must not be * selected into a DC, so restore the original first. */ SelectObject(hMemoryDC, hOrigBM); SelectObject(hMemoryDC, oldFont); DeleteObject(hFont); memset(&bmi, 0, sizeof(BITMAPINFO)); bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); bmi.bmiHeader.biWidth = width; bmi.bmiHeader.biHeight = -height; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 24; bmi.bmiHeader.biCompression = BI_RGB; dibImage = SAFE_SIZE_ARRAY_ALLOC(malloc, dibBytesWidth, height); if (dibImage == NULL) { FREE_AND_RETURN; } dibImageSize = dibBytesWidth*height; memset(dibImage, 0, dibImageSize); err = GetDIBits(hMemoryDC, hBitmap, 0, height, dibImage, &bmi, DIB_RGB_COLORS); if (err == 0) { /* GetDIBits failed. */ FREE_AND_RETURN; } err = SystemParametersInfo(SPI_GETFONTSMOOTHINGORIENTATION, 0, &orient, 0); if (err == 0) { FREE_AND_RETURN; } err = SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &gamma, 0); if (err == 0) { FREE_AND_RETURN; } igTable = getIGTable(gamma/10); if (igTable == NULL) { FREE_AND_RETURN; } /* Now copy glyph image into a GlyphInfo structure and return it. * NB the xadvance calculated here may be overwritten by the caller. * 1 is subtracted from the bitmap width to get the glyph width, since * that extra "1" was added as padding, so the sub-pixel positioning of * fractional metrics could index into it. */ glyphInfo = (GlyphInfo*)SAFE_SIZE_STRUCT_ALLOC(malloc, sizeof(GlyphInfo), bytesWidth, height); if (glyphInfo == NULL) { FREE_AND_RETURN; } imageSize = bytesWidth*height; glyphInfo->cellInfo = NULL; glyphInfo->rowBytes = bytesWidth; glyphInfo->width = width; if (fm) { glyphInfo->width -= 1; // must subtract 1 } glyphInfo->height = height; glyphInfo->advanceX = advanceX; glyphInfo->advanceY = advanceY; glyphInfo->topLeftX = (float)(topLeftX-1); if (fm) { glyphInfo->topLeftX -= 1; } glyphInfo->topLeftY = (float)-topLeftY; glyphInfo->image = (unsigned char*)glyphInfo+sizeof(GlyphInfo); memset(glyphInfo->image, 0, imageSize); /* DIB 24bpp data is always stored in BGR order, but we usually * need this in RGB, so we can't just memcpy and need to swap B and R. * Also need to apply inverse gamma adjustment here. * We re-use the variable "extra" to see if the last pixel is touched * at all. If its not we can reduce the glyph image width. This comes * into play in some cases where GDI touches more pixels than accounted * for by increasing width by two pixels over the B&W image. Whilst * the bytes are in the cache, it doesn't affect rendering performance * of the hardware pipelines. */ extra = 0; if (fm) { extra = 1; // always need it. } dibRowPtr = dibImage; rowPtr = glyphInfo->image; for (y=0;y<height;y++) { pixelPtr = rowPtr; dibPixPtr = dibRowPtr; for (x=0;x<width;x++) { if (orient == FE_FONTSMOOTHINGORIENTATIONRGB) { b = *dibPixPtr++; g = *dibPixPtr++; r = *dibPixPtr++; } else { r = *dibPixPtr++; g = *dibPixPtr++; b = *dibPixPtr++; } *pixelPtr++ = igTable[r]; *pixelPtr++ = igTable[g]; *pixelPtr++ = igTable[b]; if (!fm && (x==(width-1)) && (r|g|b)) { extra = 1; } } dibRowPtr += dibBytesWidth; rowPtr += bytesWidth; } if (!extra) { glyphInfo->width -= 1; } free(dibImage); ReleaseDC(hWnd, hDesktopDC); DeleteObject(hMemoryDC); DeleteObject(hBitmap); return ptr_to_jlong(glyphInfo); }
void SplashPaint(Splash * splash, HDC hdc) { unsigned numColors = splash->screenFormat.colorMap ? splash->screenFormat.numColors : 0; BITMAPV4HEADER *pBmi; HPALETTE hOldPal = NULL; if (!splash->frames) return; if (splash->currentFrame < 0 || splash->currentFrame >= splash->frameCount) return; pBmi = (BITMAPV4HEADER *) SAFE_SIZE_STRUCT_ALLOC(alloca, sizeof(BITMAPV4HEADER), sizeof(RGBQUAD), numColors); if (!pBmi) { return; } memset(pBmi, 0, sizeof(BITMAPV4HEADER)); if (splash->screenFormat.colorMap) memcpy(((BYTE *) pBmi) + sizeof(BITMAPV4HEADER), splash->screenFormat.colorMap, sizeof(RGBQUAD) * numColors); pBmi->bV4Size = sizeof(BITMAPV4HEADER); pBmi->bV4Width = splash->width; pBmi->bV4Height = -splash->height; pBmi->bV4Planes = 1; pBmi->bV4BitCount = (WORD) (splash->screenFormat.depthBytes * 8); /* we're ALWAYS using BGRA in screenFormat */ pBmi->bV4V4Compression = BI_RGB; pBmi->bV4ClrUsed = numColors; pBmi->bV4ClrImportant = numColors; pBmi->bV4AlphaMask = splash->screenFormat.mask[3]; pBmi->bV4RedMask = splash->screenFormat.mask[2]; pBmi->bV4GreenMask = splash->screenFormat.mask[1]; pBmi->bV4BlueMask = splash->screenFormat.mask[0]; /* creating the palette in SplashInitPlatform does not work, so I'm creating it here on demand */ if (!splash->hPalette) { unsigned i; LOGPALETTE *pLogPal = (LOGPALETTE *) SAFE_SIZE_STRUCT_ALLOC(malloc, sizeof(LOGPALETTE), sizeof(PALETTEENTRY), numColors); if (!pLogPal) { return; } pLogPal->palVersion = 0x300; pLogPal->palNumEntries = (WORD) numColors; for (i = 0; i < numColors; i++) { pLogPal->palPalEntry[i].peRed = (BYTE) QUAD_RED(splash->colorMap[i]); pLogPal->palPalEntry[i].peGreen = (BYTE) QUAD_GREEN(splash->colorMap[i]); pLogPal->palPalEntry[i].peBlue = (BYTE) QUAD_BLUE(splash->colorMap[i]); pLogPal->palPalEntry[i].peFlags = PC_NOCOLLAPSE; } splash->hPalette = CreatePalette(pLogPal); free(pLogPal); } if (splash->hPalette) { hOldPal = SelectPalette(hdc, splash->hPalette, FALSE); RealizePalette(hdc); } StretchDIBits(hdc, 0, 0, splash->width, splash->height, 0, 0, splash->width, splash->height, splash->screenData, (BITMAPINFO *) pBmi, DIB_RGB_COLORS, SRCCOPY); if (hOldPal) SelectPalette(hdc, hOldPal, FALSE); }
/* * Class: sun_awt_windows_WDataTransferer * Method: imageDataToPlatformImageBytes * Signature: ([BIII)[B */ JNIEXPORT jbyteArray JNICALL Java_sun_awt_windows_WDataTransferer_imageDataToPlatformImageBytes(JNIEnv *env, jobject self, jbyteArray imageData, jint width, jint height, jlong format) { TRY; if (JNU_IsNull(env, imageData)) { return NULL; } UINT size = env->GetArrayLength(imageData); if (size == 0) { return NULL; } // In the passed imageData array all lines are padded with zeroes except for // the last one, so we have to add one pad size here. int mod = (width * 3) % 4; int pad = mod > 0 ? 4 - mod : 0; int nBytes = sizeof(BITMAPINFO) + size + pad; BITMAPINFO* pinfo = (BITMAPINFO*)safe_Calloc(1, nBytes); static const int BITS_PER_PIXEL = 24; // prepare BITMAPINFO for a 24-bit BGR bitmap pinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pinfo->bmiHeader.biWidth = width; pinfo->bmiHeader.biHeight = height; // positive height means a bottom-up DIB pinfo->bmiHeader.biPlanes = 1; pinfo->bmiHeader.biBitCount = BITS_PER_PIXEL; pinfo->bmiHeader.biCompression = BI_RGB; // NOTE: MSDN says that biSizeImage may be set to 0 for BI_RGB bitmaps, // but some programs (e.g. Imaging for Windows NT by Wang Laboratories) // don't handle such DIBs correctly, so we specify the size explicitly. pinfo->bmiHeader.biSizeImage = size + pad; jbyte *array = (jbyte*)((LPSTR)pinfo + sizeof(BITMAPINFOHEADER)); env->GetByteArrayRegion(imageData, 0, size, array); HRESULT hr = S_OK; jbyteArray bytes = NULL; switch (format) { case CF_DIB: bytes = env->NewByteArray(nBytes); if( NULL == bytes ) { hr = E_OUTOFMEMORY; } else { env->SetByteArrayRegion(bytes, 0, nBytes, (jbyte*)pinfo); } break; case CF_ENHMETAFILE: { HDC hdc = ::GetDC(NULL); if( NULL == hdc) { hr = HRESULT_FROM_WIN32(::GetLastError()); } else { POINT p = { width, height }; //We are trying to support context-independent metafile. //To implement it we have to select correct MM_HIMETRIC map mode. VERIFY(::SetMapMode(hdc, MM_HIMETRIC)); VERIFY(::DPtoLP(hdc, &p, 1)); //In accordance with CreateEnhMetaFile documentation the rectangle have to //be normal (left <= right, top <= bottom) RECT r = { min(0, p.x), min(0, p.y), max(0, p.x), max(0, p.y) }; //Due to inversed row order in source bitmap the destination //height have to be negative. HDC hemfdc = ::CreateEnhMetaFile(NULL, NULL, &r, NULL); if( NULL == hemfdc) { hr = HRESULT_FROM_WIN32(::GetLastError()); } else { int iMFHeight = r.bottom - r.top; int iMFWidth = r.right - r.left; VERIFY(::SetMapMode(hemfdc, MM_HIMETRIC)); if( GDI_ERROR == ::StretchDIBits(hemfdc, 0, iMFHeight, iMFWidth, -iMFHeight, 0, 0, width, height, (LPVOID)array, pinfo, DIB_RGB_COLORS, SRCCOPY)) { hr = HRESULT_FROM_WIN32(::GetLastError()); } HENHMETAFILE hemf = ::CloseEnhMetaFile(hemfdc); if( NULL == hemf) { hr = HRESULT_FROM_WIN32(::GetLastError()); } else { if(SUCCEEDED(hr)){ UINT uEmfSize = ::GetEnhMetaFileBits(hemf, 0, NULL); if( 0 == uEmfSize) { hr = HRESULT_FROM_WIN32(::GetLastError()); } else { LPBYTE lpbEmfBuffer = NULL; try { lpbEmfBuffer = (LPBYTE)safe_Malloc(uEmfSize); VERIFY(::GetEnhMetaFileBits(hemf, uEmfSize, lpbEmfBuffer) == uEmfSize); bytes = env->NewByteArray(uEmfSize); if(NULL == bytes) { hr = E_OUTOFMEMORY; } else { env->SetByteArrayRegion(bytes, 0, uEmfSize, (jbyte*)lpbEmfBuffer); } } catch (std::bad_alloc &) { hr = E_OUTOFMEMORY; } free(lpbEmfBuffer); } } VERIFY(::DeleteEnhMetaFile(hemf)); } } VERIFY(::ReleaseDC(NULL, hdc)); } break; } case CF_METAFILEPICT: { HDC hdc = ::GetDC(NULL); if( NULL == hdc) { hr = HRESULT_FROM_WIN32(::GetLastError()); } else { POINT p = { width, height }; VERIFY(::SetMapMode(hdc, MM_HIMETRIC)); VERIFY(::DPtoLP(hdc, &p, 1)); RECT r = { min(0, p.x), min(0, p.y), max(0, p.x), max(0, p.y) }; HDC hmfdc = ::CreateMetaFile(NULL); if( NULL == hmfdc) { hr = HRESULT_FROM_WIN32(::GetLastError()); } else { VERIFY(::SetMapMode(hmfdc, MM_HIMETRIC)); int iMFHeight = r.bottom - r.top; int iMFWidth = r.right - r.left; //The destination Y coordinate (3d parameter in StretchDIBits call) is different for //CF_ENHMETAFILE and CF_METAFILEPICT formats due to applying MM_ANISOTROPIC map mode //at very last moment. MM_ANISOTROPIC map mode changes the Y-axis direction and can be //selected just for metafile header. if( GDI_ERROR == ::StretchDIBits(hmfdc, 0, 0, iMFWidth, -iMFHeight, 0, 0, width, height, (LPVOID)array, pinfo, DIB_RGB_COLORS, SRCCOPY)) { hr = HRESULT_FROM_WIN32(::GetLastError()); } HMETAFILE hmf = ::CloseMetaFile(hmfdc); if( NULL == hmf) { hr = HRESULT_FROM_WIN32(::GetLastError()); } else { if(SUCCEEDED(hr)){ UINT uMfSize = ::GetMetaFileBitsEx(hmf, 0, NULL); if( 0 == uMfSize) { hr = HRESULT_FROM_WIN32(::GetLastError()); } else { LPBYTE lpbMfBuffer = NULL; try { lpbMfBuffer = (LPBYTE)SAFE_SIZE_STRUCT_ALLOC(safe_Malloc, sizeof(METAFILEPICT), uMfSize, 1); const UINT uMfSizeWithHead = uMfSize + sizeof(METAFILEPICT); VERIFY(::GetMetaFileBitsEx(hmf, uMfSize, lpbMfBuffer + sizeof(METAFILEPICT)) == uMfSize); bytes = env->NewByteArray(uMfSizeWithHead); if(NULL == bytes) { hr = E_OUTOFMEMORY; } else { LPMETAFILEPICT lpMfp = (LPMETAFILEPICT)lpbMfBuffer; lpMfp->mm = MM_ANISOTROPIC; // should use MM_ANISOTROPIC exactly (MSDN) lpMfp->xExt = iMFWidth; lpMfp->yExt = iMFHeight; env->SetByteArrayRegion(bytes, 0, uMfSizeWithHead, (jbyte*)lpbMfBuffer); } } catch (std::bad_alloc &) { hr = E_OUTOFMEMORY; } free(lpbMfBuffer); } } VERIFY(::DeleteMetaFile(hmf)); } } VERIFY(::ReleaseDC(NULL, hdc)); } break; } default: DASSERT(FALSE); // Other formats are not supported yet. hr = E_NOTIMPL; break; } free(pinfo); if(FAILED(hr)){ if(E_OUTOFMEMORY == hr) throw std::bad_alloc(); return NULL; } return bytes; CATCH_BAD_ALLOC_RET(NULL); }