301N/A/*
2362N/A * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
301N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
301N/A *
301N/A * This code is free software; you can redistribute it and/or modify it
301N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
301N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
301N/A *
301N/A * This code is distributed in the hope that it will be useful, but WITHOUT
301N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
301N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
301N/A * version 2 for more details (a copy is included in the LICENSE file that
301N/A * accompanied this code).
301N/A *
301N/A * You should have received a copy of the GNU General Public License version
301N/A * 2 along with this work; if not, write to the Free Software Foundation,
301N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
301N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
301N/A */
301N/A
301N/A/*
301N/A * The function here is used to get a GDI rasterized LCD glyph and place it
301N/A * into the JDK glyph cache. The benefit is rendering fidelity for the
301N/A * most common cases, with no impact on the 2D rendering pipelines.
301N/A *
301N/A * Requires that the font and graphics are unrotated, and the scale is
301N/A * a simple one, and the font is a TT font registered with windows.
301N/A * Those conditions are established by the calling code.
301N/A *
301N/A * This code
301N/A * - Receives the family name, style, and size of the font
301N/A * and creates a Font object.
301N/A * - Create a surface from which we can get a DC : must be 16 bit or more.
301N/A * Ideally we'd be able to specify the depth of this, but in practice we
301N/A * have to accept it will be the same as the default screen.
301N/A * - Selects the GDI font on to the device
301N/A * - Uses GetGlyphOutline to estimate the bounds.
301N/A * - Creates a DIB on to which to blit the image.
301N/A * - Creates a GlyphInfo structure and copies the GDI glyph and offsets
301N/A * into the glyph which is returned.
301N/A */
301N/A
301N/A#include <stdio.h>
301N/A#include <malloc.h>
301N/A#include <math.h>
301N/A#include <windows.h>
301N/A#include <winuser.h>
301N/A
301N/A#include <jni.h>
301N/A#include <jni_util.h>
301N/A#include <jlong_md.h>
6295N/A#include <sizecalc.h>
301N/A#include <sun_font_FileFontStrike.h>
301N/A
301N/A#include "fontscalerdefs.h"
301N/A
301N/A/* Some of these are also defined in awtmsg.h but I don't want a dependency
301N/A * on that here. They are needed here - and in awtmsg.h - until we
301N/A * move up our build to define WIN32_WINNT >= 0x501 (ie XP), since MS
301N/A * headers will not define them otherwise.
301N/A */
301N/A#ifndef SPI_GETFONTSMOOTHINGTYPE
301N/A#define SPI_GETFONTSMOOTHINGTYPE 0x200A
301N/A#endif //SPI_GETFONTSMOOTHINGTYPE
301N/A
301N/A#ifndef SPI_GETFONTSMOOTHINGCONTRAST
301N/A#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C
301N/A#endif //SPI_GETFONTSMOOTHINGCONTRAST
301N/A
301N/A#ifndef SPI_GETFONTSMOOTHINGORIENTATION
301N/A#define SPI_GETFONTSMOOTHINGORIENTATION 0x2012
301N/A#endif //SPI_GETFONTSMOOTHINGORIENTATION
301N/A
301N/A#ifndef FE_FONTSMOOTHINGORIENTATIONBGR
301N/A#define FE_FONTSMOOTHINGORIENTATIONBGR 0x0000
301N/A#endif //FE_FONTSMOOTHINGORIENTATIONBGR
301N/A
301N/A#ifndef FE_FONTSMOOTHINGORIENTATIONRGB
301N/A#define FE_FONTSMOOTHINGORIENTATIONRGB 0x0001
301N/A#endif //FE_FONTSMOOTHINGORIENTATIONRGB
301N/A
301N/A#define MIN_GAMMA 100
301N/A#define MAX_GAMMA 220
301N/A#define LCDLUTCOUNT (MAX_GAMMA-MIN_GAMMA+1)
301N/A
301N/Astatic unsigned char* igLUTable[LCDLUTCOUNT];
301N/A
301N/Astatic unsigned char* getIGTable(int gamma) {
301N/A int i, index;
301N/A double ig;
301N/A char *igTable;
301N/A
301N/A if (gamma < MIN_GAMMA) {
301N/A gamma = MIN_GAMMA;
301N/A } else if (gamma > MAX_GAMMA) {
301N/A gamma = MAX_GAMMA;
301N/A }
301N/A
301N/A index = gamma - MIN_GAMMA;
301N/A
301N/A if (igLUTable[index] != NULL) {
301N/A return igLUTable[index];
301N/A }
301N/A igTable = (unsigned char*)malloc(256);
301N/A if (igTable == NULL) {
301N/A return NULL;
301N/A }
301N/A igTable[0] = 0;
301N/A igTable[255] = 255;
301N/A ig = ((double)gamma)/100.0;
301N/A
301N/A for (i=1;i<255;i++) {
301N/A igTable[i] = (unsigned char)(pow(((double)i)/255.0, ig)*255);
301N/A }
301N/A igLUTable[index] = igTable;
301N/A return igTable;
301N/A}
301N/A
301N/A
301N/AJNIEXPORT jboolean JNICALL
301N/A Java_sun_font_FileFontStrike_initNative(JNIEnv *env, jclass unused) {
301N/A
301N/A DWORD osVersion = GetVersion();
301N/A DWORD majorVersion = (DWORD)(LOBYTE(LOWORD(osVersion)));
301N/A DWORD minorVersion = (DWORD)(HIBYTE(LOWORD(osVersion)));
301N/A
301N/A /* Need at least XP which is 5.1 */
301N/A if (majorVersion < 5 || (majorVersion == 5 && minorVersion < 1)) {
301N/A return JNI_FALSE;
301N/A }
301N/A
301N/A memset(igLUTable, 0, LCDLUTCOUNT);
301N/A
301N/A return JNI_TRUE;
301N/A}
301N/A
301N/A#ifndef CLEARTYPE_QUALITY
301N/A#define CLEARTYPE_QUALITY 5
301N/A#endif
301N/A
301N/A#ifndef CLEARTYPE_NATURAL_QUALITY
301N/A#define CLEARTYPE_NATURAL_QUALITY 6
301N/A#endif
301N/A
301N/A#define FREE_AND_RETURN \
301N/A if (hDesktopDC != 0 && hWnd != 0) { \
301N/A ReleaseDC(hWnd, hDesktopDC); \
301N/A }\
301N/A if (hMemoryDC != 0) { \
301N/A DeleteObject(hMemoryDC); \
301N/A } \
301N/A if (hBitmap != 0) { \
301N/A DeleteObject(hBitmap); \
301N/A } \
301N/A if (dibImage != NULL) { \
301N/A free(dibImage); \
301N/A } \
301N/A if (glyphInfo != NULL) { \
301N/A free(glyphInfo); \
301N/A } \
301N/A return (jlong)0;
301N/A/* end define */
301N/A
301N/AJNIEXPORT jlong JNICALL
301N/AJava_sun_font_FileFontStrike__1getGlyphImageFromWindows
301N/A(JNIEnv *env, jobject unused,
301N/A jstring fontFamily, jint style, jint size, jint glyphCode, jboolean fm) {
301N/A
301N/A GLYPHMETRICS glyphMetrics;
301N/A LOGFONTW lf;
301N/A BITMAPINFO bmi;
301N/A TEXTMETRIC textMetric;
301N/A RECT rect;
301N/A int bytesWidth, dibBytesWidth, extra, imageSize, dibImageSize;
301N/A unsigned char* dibImage = NULL, *rowPtr, *pixelPtr, *dibPixPtr, *dibRowPtr;
301N/A unsigned char r,g,b;
301N/A unsigned char* igTable;
301N/A GlyphInfo* glyphInfo = NULL;
301N/A int nameLen;
301N/A LPWSTR name;
301N/A HFONT oldFont, hFont;
301N/A MAT2 mat2;
301N/A
301N/A unsigned short width;
301N/A unsigned short height;
301N/A short advanceX;
301N/A short advanceY;
301N/A int topLeftX;
301N/A int topLeftY;
301N/A int err;
301N/A int bmWidth, bmHeight;
301N/A int x, y;
301N/A HBITMAP hBitmap = NULL, hOrigBM;
301N/A int gamma, orient;
301N/A
301N/A HWND hWnd = NULL;
301N/A HDC hDesktopDC = NULL;
301N/A HDC hMemoryDC = NULL;
301N/A
301N/A hWnd = GetDesktopWindow();
301N/A hDesktopDC = GetWindowDC(hWnd);
301N/A if (hDesktopDC == NULL) {
301N/A return (jlong)0;
301N/A }
301N/A if (GetDeviceCaps(hDesktopDC, BITSPIXEL) < 15) {
301N/A FREE_AND_RETURN;
301N/A }
301N/A
301N/A hMemoryDC = CreateCompatibleDC(hDesktopDC);
301N/A if (hMemoryDC == NULL || fontFamily == NULL) {
301N/A FREE_AND_RETURN;
301N/A }
301N/A err = SetMapMode(hMemoryDC, MM_TEXT);
301N/A if (err == 0) {
301N/A FREE_AND_RETURN;
301N/A }
301N/A
301N/A memset(&lf, 0, sizeof(LOGFONTW));
301N/A lf.lfHeight = -size;
301N/A lf.lfWeight = (style & 1) ? FW_BOLD : FW_NORMAL;
301N/A lf.lfItalic = (style & 2) ? 0xff : 0;
301N/A lf.lfCharSet = DEFAULT_CHARSET;
301N/A lf.lfQuality = CLEARTYPE_QUALITY;
301N/A lf.lfOutPrecision = OUT_TT_PRECIS;
301N/A lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
301N/A lf.lfPitchAndFamily = DEFAULT_PITCH;
301N/A
301N/A nameLen = (*env)->GetStringLength(env, fontFamily);
301N/A name = (LPWSTR)alloca((nameLen+1)*2);
301N/A if (name == NULL) {
301N/A FREE_AND_RETURN;
301N/A }
301N/A (*env)->GetStringRegion(env, fontFamily, 0, nameLen, name);
301N/A name[nameLen] = '\0';
301N/A
301N/A if (nameLen < (sizeof(lf.lfFaceName) / sizeof(lf.lfFaceName[0]))) {
301N/A wcscpy(lf.lfFaceName, name);
301N/A } else {
301N/A FREE_AND_RETURN;
301N/A }
301N/A
301N/A hFont = CreateFontIndirectW(&lf);
301N/A if (hFont == NULL) {
301N/A FREE_AND_RETURN;
301N/A }
301N/A oldFont = SelectObject(hMemoryDC, hFont);
301N/A
301N/A memset(&textMetric, 0, sizeof(TEXTMETRIC));
301N/A err = GetTextMetrics(hMemoryDC, &textMetric);
301N/A if (err == 0) {
301N/A FREE_AND_RETURN;
301N/A }
301N/A memset(&glyphMetrics, 0, sizeof(GLYPHMETRICS));
301N/A memset(&mat2, 0, sizeof(MAT2));
301N/A mat2.eM11.value = 1; mat2.eM22.value = 1;
301N/A err = GetGlyphOutline(hMemoryDC, glyphCode,
301N/A GGO_METRICS|GGO_GLYPH_INDEX,
301N/A &glyphMetrics,
301N/A 0, NULL, &mat2);
301N/A if (err == GDI_ERROR) {
301N/A /* Probably no such glyph - ie the font wasn't the one we expected. */
301N/A FREE_AND_RETURN;
301N/A }
301N/A
301N/A width = (unsigned short)glyphMetrics.gmBlackBoxX;
301N/A height = (unsigned short)glyphMetrics.gmBlackBoxY;
301N/A
301N/A /* Don't handle "invisible" glyphs in this code */
301N/A if (width <= 0 || height == 0) {
301N/A FREE_AND_RETURN;
301N/A }
301N/A
301N/A advanceX = glyphMetrics.gmCellIncX;
301N/A advanceY = glyphMetrics.gmCellIncY;
301N/A topLeftX = glyphMetrics.gmptGlyphOrigin.x;
301N/A topLeftY = glyphMetrics.gmptGlyphOrigin.y;
301N/A
301N/A /* GetGlyphOutline pre-dates cleartype and I'm not sure that it will
301N/A * account for all pixels touched by the rendering. Need to widen,
301N/A * and also adjust by one the x position at which it is rendered.
301N/A * The extra pixels of width are used as follows :
301N/A * One extra pixel at the left and the right will be needed to absorb
301N/A * the pixels that will be touched by filtering by GDI to compensate
301N/A * for colour fringing.
301N/A * However there seem to be some cases where GDI renders two extra
301N/A * pixels to the right, so we add one additional pixel to the right,
301N/A * and in the code that copies this to the image cache we test for
301N/A * the (rare) cases when this is touched, and if its not reduce the
301N/A * stated image width for the blitting loops.
301N/A * For fractional metrics :
301N/A * One extra pixel at each end to account for sub-pixel positioning used
301N/A * when fractional metrics is on in LCD mode.
301N/A * The pixel at the left is needed so the blitting loop can index into
301N/A * that a byte at a time to more accurately position the glyph.
301N/A * The pixel at the right is needed so that when such indexing happens,
301N/A * the blitting still can use the same width.
301N/A * Consequently the width that is specified for the glyph is one less
301N/A * than that of the actual image.
301N/A * Note that in the FM case as a consequence we need to adjust the
301N/A * position at which GDI renders, and the declared width of the glyph
301N/A * See the if (fm) {} cases in the code.
301N/A * For the non-FM case, we not only save 3 bytes per row, but this
301N/A * prevents apparent glyph overlapping which affects the rendering
301N/A * performance of accelerated pipelines since it adds additional
301N/A * read-back requirements.
301N/A */
301N/A width+=3;
301N/A if (fm) {
301N/A width+=1;
301N/A }
301N/A /* DIB scanline must end on a DWORD boundary. We specify 3 bytes per pixel,
301N/A * so must round up as needed to a multiple of 4 bytes.
301N/A */
301N/A dibBytesWidth = bytesWidth = width*3;
301N/A extra = dibBytesWidth % 4;
301N/A if (extra != 0) {
301N/A dibBytesWidth += (4-extra);
301N/A }
301N/A /* The glyph cache image must be a multiple of 3 bytes wide. */
301N/A extra = bytesWidth % 3;
301N/A if (extra != 0) {
301N/A bytesWidth += (3-extra);
301N/A }
301N/A bmWidth = width;
301N/A bmHeight = height;
301N/A
301N/A /* Must use desktop DC to create a bitmap of that depth */
301N/A hBitmap = CreateCompatibleBitmap(hDesktopDC, bmWidth, bmHeight);
301N/A if (hBitmap == NULL) {
301N/A FREE_AND_RETURN;
301N/A }
301N/A hOrigBM = (HBITMAP)SelectObject(hMemoryDC, hBitmap);
301N/A
301N/A /* Fill in black */
301N/A rect.left = 0;
301N/A rect.top = 0;
301N/A rect.right = bmWidth;
301N/A rect.bottom = bmHeight;
301N/A FillRect(hMemoryDC, (LPRECT)&rect, GetStockObject(BLACK_BRUSH));
301N/A
301N/A /* Set text color to white, background to black. */
301N/A SetBkColor(hMemoryDC, RGB(0,0,0));
301N/A SetTextColor(hMemoryDC, RGB(255,255,255));
301N/A
301N/A /* adjust rendering position */
301N/A x = -topLeftX+1;
301N/A if (fm) {
301N/A x += 1;
301N/A }
301N/A y = topLeftY - textMetric.tmAscent;
301N/A err = ExtTextOutW(hMemoryDC, x, y, ETO_GLYPH_INDEX|ETO_OPAQUE,
301N/A (LPRECT)&rect, (LPCWSTR)&glyphCode, 1, NULL);
301N/A if (err == 0) {
301N/A FREE_AND_RETURN;
301N/A }
301N/A
301N/A /* Now get the image into a DIB.
301N/A * MS docs for GetDIBits says the compatible bitmap must not be
301N/A * selected into a DC, so restore the original first.
301N/A */
301N/A SelectObject(hMemoryDC, hOrigBM);
301N/A SelectObject(hMemoryDC, oldFont);
301N/A DeleteObject(hFont);
301N/A
301N/A memset(&bmi, 0, sizeof(BITMAPINFO));
301N/A bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
301N/A bmi.bmiHeader.biWidth = width;
301N/A bmi.bmiHeader.biHeight = -height;
301N/A bmi.bmiHeader.biPlanes = 1;
301N/A bmi.bmiHeader.biBitCount = 24;
301N/A bmi.bmiHeader.biCompression = BI_RGB;
301N/A
6295N/A dibImage = SAFE_SIZE_ARRAY_ALLOC(malloc, dibBytesWidth, height);
301N/A if (dibImage == NULL) {
301N/A FREE_AND_RETURN;
301N/A }
6295N/A dibImageSize = dibBytesWidth*height;
301N/A memset(dibImage, 0, dibImageSize);
301N/A
301N/A err = GetDIBits(hMemoryDC, hBitmap, 0, height, dibImage,
301N/A &bmi, DIB_RGB_COLORS);
301N/A
301N/A if (err == 0) { /* GetDIBits failed. */
301N/A FREE_AND_RETURN;
301N/A }
301N/A
301N/A err = SystemParametersInfo(SPI_GETFONTSMOOTHINGORIENTATION, 0, &orient, 0);
301N/A if (err == 0) {
301N/A FREE_AND_RETURN;
301N/A }
301N/A err = SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &gamma, 0);
301N/A if (err == 0) {
301N/A FREE_AND_RETURN;
301N/A }
301N/A igTable = getIGTable(gamma/10);
301N/A if (igTable == NULL) {
301N/A FREE_AND_RETURN;
301N/A }
301N/A
301N/A /* Now copy glyph image into a GlyphInfo structure and return it.
301N/A * NB the xadvance calculated here may be overwritten by the caller.
301N/A * 1 is subtracted from the bitmap width to get the glyph width, since
301N/A * that extra "1" was added as padding, so the sub-pixel positioning of
301N/A * fractional metrics could index into it.
301N/A */
6295N/A glyphInfo = (GlyphInfo*)SAFE_SIZE_STRUCT_ALLOC(malloc, sizeof(GlyphInfo),
6295N/A bytesWidth, height);
301N/A if (malloc == NULL) {
301N/A FREE_AND_RETURN;
301N/A }
6295N/A imageSize = bytesWidth*height;
301N/A glyphInfo->cellInfo = NULL;
301N/A glyphInfo->rowBytes = bytesWidth;
301N/A glyphInfo->width = width;
301N/A if (fm) {
301N/A glyphInfo->width -= 1; // must subtract 1
301N/A }
301N/A glyphInfo->height = height;
301N/A glyphInfo->advanceX = advanceX;
301N/A glyphInfo->advanceY = advanceY;
301N/A glyphInfo->topLeftX = (float)(topLeftX-1);
301N/A if (fm) {
301N/A glyphInfo->topLeftX -= 1;
301N/A }
301N/A glyphInfo->topLeftY = (float)-topLeftY;
301N/A glyphInfo->image = (unsigned char*)glyphInfo+sizeof(GlyphInfo);
301N/A memset(glyphInfo->image, 0, imageSize);
301N/A
301N/A /* DIB 24bpp data is always stored in BGR order, but we usually
301N/A * need this in RGB, so we can't just memcpy and need to swap B and R.
301N/A * Also need to apply inverse gamma adjustment here.
301N/A * We re-use the variable "extra" to see if the last pixel is touched
301N/A * at all. If its not we can reduce the glyph image width. This comes
301N/A * into play in some cases where GDI touches more pixels than accounted
301N/A * for by increasing width by two pixels over the B&W image. Whilst
301N/A * the bytes are in the cache, it doesn't affect rendering performance
301N/A * of the hardware pipelines.
301N/A */
301N/A extra = 0;
301N/A if (fm) {
301N/A extra = 1; // always need it.
301N/A }
301N/A dibRowPtr = dibImage;
301N/A rowPtr = glyphInfo->image;
301N/A for (y=0;y<height;y++) {
301N/A pixelPtr = rowPtr;
301N/A dibPixPtr = dibRowPtr;
301N/A for (x=0;x<width;x++) {
301N/A if (orient == FE_FONTSMOOTHINGORIENTATIONRGB) {
301N/A b = *dibPixPtr++;
301N/A g = *dibPixPtr++;
301N/A r = *dibPixPtr++;
301N/A } else {
301N/A r = *dibPixPtr++;
301N/A g = *dibPixPtr++;
301N/A b = *dibPixPtr++;
301N/A }
301N/A *pixelPtr++ = igTable[r];
301N/A *pixelPtr++ = igTable[g];
301N/A *pixelPtr++ = igTable[b];
301N/A if (!fm && (x==(width-1)) && (r|g|b)) {
301N/A extra = 1;
301N/A }
301N/A }
301N/A dibRowPtr += dibBytesWidth;
301N/A rowPtr += bytesWidth;
301N/A }
301N/A if (!extra) {
301N/A glyphInfo->width -= 1;
301N/A }
301N/A
301N/A free(dibImage);
301N/A ReleaseDC(hWnd, hDesktopDC);
301N/A DeleteObject(hMemoryDC);
301N/A DeleteObject(hBitmap);
301N/A
301N/A return ptr_to_jlong(glyphInfo);
301N/A}