Path: blob/master/src/java.desktop/windows/native/libfontmanager/lcdglyph.c
41152 views
/*1* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* The function here is used to get a GDI rasterized LCD glyph and place it27* into the JDK glyph cache. The benefit is rendering fidelity for the28* most common cases, with no impact on the 2D rendering pipelines.29*30* Requires that the font and graphics are unrotated, and the scale is31* a simple one, and the font is a TT font registered with windows.32* Those conditions are established by the calling code.33*34* This code35* - Receives the family name, style, and size of the font36* and creates a Font object.37* - Create a surface from which we can get a DC : must be 16 bit or more.38* Ideally we'd be able to specify the depth of this, but in practice we39* have to accept it will be the same as the default screen.40* - Selects the GDI font on to the device41* - Uses GetGlyphOutline to estimate the bounds.42* - Creates a DIB on to which to blit the image.43* - Creates a GlyphInfo structure and copies the GDI glyph and offsets44* into the glyph which is returned.45*/4647#include <stdio.h>48#include <malloc.h>49#include <math.h>50#include <windows.h>51#include <winuser.h>5253#include <jni.h>54#include <jni_util.h>55#include <jlong_md.h>56#include <sizecalc.h>57#include <sun_font_FileFontStrike.h>5859#include "fontscalerdefs.h"6061/* Some of these are also defined in awtmsg.h but I don't want a dependency62* on that here. They are needed here - and in awtmsg.h - until we63* move up our build to define WIN32_WINNT >= 0x501 (ie XP), since MS64* headers will not define them otherwise.65*/66#ifndef SPI_GETFONTSMOOTHINGTYPE67#define SPI_GETFONTSMOOTHINGTYPE 0x200A68#endif //SPI_GETFONTSMOOTHINGTYPE6970#ifndef SPI_GETFONTSMOOTHINGCONTRAST71#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C72#endif //SPI_GETFONTSMOOTHINGCONTRAST7374#ifndef SPI_GETFONTSMOOTHINGORIENTATION75#define SPI_GETFONTSMOOTHINGORIENTATION 0x201276#endif //SPI_GETFONTSMOOTHINGORIENTATION7778#ifndef FE_FONTSMOOTHINGORIENTATIONBGR79#define FE_FONTSMOOTHINGORIENTATIONBGR 0x000080#endif //FE_FONTSMOOTHINGORIENTATIONBGR8182#ifndef FE_FONTSMOOTHINGORIENTATIONRGB83#define FE_FONTSMOOTHINGORIENTATIONRGB 0x000184#endif //FE_FONTSMOOTHINGORIENTATIONRGB8586#define MIN_GAMMA 10087#define MAX_GAMMA 22088#define LCDLUTCOUNT (MAX_GAMMA-MIN_GAMMA+1)8990static unsigned char* igLUTable[LCDLUTCOUNT];9192static unsigned char* getIGTable(int gamma) {93int i, index;94double ig;95char *igTable;9697if (gamma < MIN_GAMMA) {98gamma = MIN_GAMMA;99} else if (gamma > MAX_GAMMA) {100gamma = MAX_GAMMA;101}102103index = gamma - MIN_GAMMA;104105if (igLUTable[index] != NULL) {106return igLUTable[index];107}108igTable = (unsigned char*)malloc(256);109if (igTable == NULL) {110return NULL;111}112igTable[0] = 0;113igTable[255] = 255;114ig = ((double)gamma)/100.0;115116for (i=1;i<255;i++) {117igTable[i] = (unsigned char)(pow(((double)i)/255.0, ig)*255);118}119igLUTable[index] = igTable;120return igTable;121}122123124JNIEXPORT jboolean JNICALL125Java_sun_font_FileFontStrike_initNative(JNIEnv *env, jclass unused) {126127memset(igLUTable, 0, LCDLUTCOUNT);128129return JNI_TRUE;130}131132#ifndef CLEARTYPE_QUALITY133#define CLEARTYPE_QUALITY 5134#endif135136#ifndef CLEARTYPE_NATURAL_QUALITY137#define CLEARTYPE_NATURAL_QUALITY 6138#endif139140#define FREE_AND_RETURN \141if (hDesktopDC != 0 && hWnd != 0) { \142ReleaseDC(hWnd, hDesktopDC); \143}\144if (hMemoryDC != 0) { \145DeleteObject(hMemoryDC); \146} \147if (hBitmap != 0) { \148DeleteObject(hBitmap); \149} \150if (tmpBitmap != 0) { \151DeleteObject(tmpBitmap); \152} \153if (dibImage != NULL) { \154free(dibImage); \155} \156if (glyphInfo != NULL) { \157free(glyphInfo); \158} \159return (jlong)0;160/* end define */161162JNIEXPORT jlong JNICALL163Java_sun_font_FileFontStrike__1getGlyphImageFromWindows164(JNIEnv *env, jobject unused,165jstring fontFamily, jint style, jint size, jint glyphCode, jboolean fm,166jint fontDataSize) {167168GLYPHMETRICS glyphMetrics;169LOGFONTW lf;170BITMAPINFO bmi;171TEXTMETRIC textMetric;172RECT rect;173int bytesWidth, dibBytesWidth, extra, imageSize, dibImageSize;174unsigned char* dibImage = NULL, *rowPtr, *pixelPtr, *dibPixPtr, *dibRowPtr;175unsigned char r,g,b;176unsigned char* igTable;177GlyphInfo* glyphInfo = NULL;178int nameLen;179LPWSTR name;180HFONT oldFont, hFont;181MAT2 mat2;182DWORD actualFontDataSize;183184unsigned short width;185unsigned short height;186short advanceX;187short advanceY;188int topLeftX;189int topLeftY;190int err;191int bmWidth, bmHeight;192int x, y;193HBITMAP hBitmap = NULL, hOrigBM;194HBITMAP tmpBitmap = NULL;195int gamma, orient;196197HWND hWnd = NULL;198HDC hDesktopDC = NULL;199HDC hMemoryDC = NULL;200201hWnd = GetDesktopWindow();202hDesktopDC = GetWindowDC(hWnd);203if (hDesktopDC == NULL) {204return (jlong)0;205}206if (GetDeviceCaps(hDesktopDC, BITSPIXEL) < 15) {207FREE_AND_RETURN;208}209210hMemoryDC = CreateCompatibleDC(hDesktopDC);211if (hMemoryDC == NULL || fontFamily == NULL) {212FREE_AND_RETURN;213}214err = SetMapMode(hMemoryDC, MM_TEXT);215if (err == 0) {216FREE_AND_RETURN;217}218219memset(&lf, 0, sizeof(LOGFONTW));220lf.lfHeight = -size;221lf.lfWeight = (style & 1) ? FW_BOLD : FW_NORMAL;222lf.lfItalic = (style & 2) ? 0xff : 0;223lf.lfCharSet = DEFAULT_CHARSET;224lf.lfQuality = CLEARTYPE_QUALITY;225lf.lfOutPrecision = OUT_TT_PRECIS;226lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;227lf.lfPitchAndFamily = DEFAULT_PITCH;228229nameLen = (*env)->GetStringLength(env, fontFamily);230name = (LPWSTR)alloca((nameLen+1)*2);231if (name == NULL) {232FREE_AND_RETURN;233}234(*env)->GetStringRegion(env, fontFamily, 0, nameLen, name);235name[nameLen] = '\0';236237if (nameLen < (sizeof(lf.lfFaceName) / sizeof(lf.lfFaceName[0]))) {238wcscpy(lf.lfFaceName, name);239} else {240FREE_AND_RETURN;241}242243hFont = CreateFontIndirectW(&lf);244if (hFont == NULL) {245FREE_AND_RETURN;246}247oldFont = SelectObject(hMemoryDC, hFont);248249if (fontDataSize > 0) {250// GDI doesn't allow to select a specific font file for drawing, we can251// only check that it picks the file we need by validating font size.252// If it doesn't match, we cannot proceed, as the same glyph code can253// correspond to a completely different glyph in the selected font.254actualFontDataSize = GetFontData(hMemoryDC, 0, 0, NULL, 0);255if (actualFontDataSize != fontDataSize) {256FREE_AND_RETURN;257}258}259260tmpBitmap = CreateCompatibleBitmap(hDesktopDC, 1, 1);261if (tmpBitmap == NULL) {262FREE_AND_RETURN;263}264hOrigBM = (HBITMAP)SelectObject(hMemoryDC, tmpBitmap);265266memset(&textMetric, 0, sizeof(TEXTMETRIC));267err = GetTextMetrics(hMemoryDC, &textMetric);268if (err == 0) {269FREE_AND_RETURN;270}271memset(&glyphMetrics, 0, sizeof(GLYPHMETRICS));272memset(&mat2, 0, sizeof(MAT2));273mat2.eM11.value = 1; mat2.eM22.value = 1;274err = GetGlyphOutline(hMemoryDC, glyphCode,275GGO_METRICS|GGO_GLYPH_INDEX,276&glyphMetrics,2770, NULL, &mat2);278if (err == GDI_ERROR) {279/* Probably no such glyph - ie the font wasn't the one we expected. */280FREE_AND_RETURN;281}282283width = (unsigned short)glyphMetrics.gmBlackBoxX;284height = (unsigned short)glyphMetrics.gmBlackBoxY;285286/* Don't handle "invisible" glyphs in this code */287if (width <= 0 || height == 0) {288FREE_AND_RETURN;289}290291advanceX = glyphMetrics.gmCellIncX;292advanceY = glyphMetrics.gmCellIncY;293topLeftX = glyphMetrics.gmptGlyphOrigin.x;294topLeftY = glyphMetrics.gmptGlyphOrigin.y;295296/* GetGlyphOutline pre-dates cleartype and I'm not sure that it will297* account for all pixels touched by the rendering. Need to widen,298* and also adjust by one the x position at which it is rendered.299* The extra pixels of width are used as follows :300* One extra pixel at the left and the right will be needed to absorb301* the pixels that will be touched by filtering by GDI to compensate302* for colour fringing.303* However there seem to be some cases where GDI renders two extra304* pixels to the right, so we add one additional pixel to the right,305* and in the code that copies this to the image cache we test for306* the (rare) cases when this is touched, and if its not reduce the307* stated image width for the blitting loops.308* For fractional metrics :309* One extra pixel at each end to account for sub-pixel positioning used310* when fractional metrics is on in LCD mode.311* The pixel at the left is needed so the blitting loop can index into312* that a byte at a time to more accurately position the glyph.313* The pixel at the right is needed so that when such indexing happens,314* the blitting still can use the same width.315* Consequently the width that is specified for the glyph is one less316* than that of the actual image.317* Note that in the FM case as a consequence we need to adjust the318* position at which GDI renders, and the declared width of the glyph319* See the if (fm) {} cases in the code.320* For the non-FM case, we not only save 3 bytes per row, but this321* prevents apparent glyph overlapping which affects the rendering322* performance of accelerated pipelines since it adds additional323* read-back requirements.324*/325width+=3;326if (fm) {327width+=1;328}329/* DIB scanline must end on a DWORD boundary. We specify 3 bytes per pixel,330* so must round up as needed to a multiple of 4 bytes.331*/332dibBytesWidth = bytesWidth = width*3;333extra = dibBytesWidth % 4;334if (extra != 0) {335dibBytesWidth += (4-extra);336}337/* The glyph cache image must be a multiple of 3 bytes wide. */338extra = bytesWidth % 3;339if (extra != 0) {340bytesWidth += (3-extra);341}342bmWidth = width;343bmHeight = height;344345/* Must use desktop DC to create a bitmap of that depth */346hBitmap = CreateCompatibleBitmap(hDesktopDC, bmWidth, bmHeight);347if (hBitmap == NULL) {348FREE_AND_RETURN;349}350SelectObject(hMemoryDC, hBitmap);351352/* Fill in black */353rect.left = 0;354rect.top = 0;355rect.right = bmWidth;356rect.bottom = bmHeight;357FillRect(hMemoryDC, (LPRECT)&rect, GetStockObject(BLACK_BRUSH));358359/* Set text color to white, background to black. */360SetBkColor(hMemoryDC, RGB(0,0,0));361SetTextColor(hMemoryDC, RGB(255,255,255));362363/* adjust rendering position */364x = -topLeftX+1;365if (fm) {366x += 1;367}368y = topLeftY - textMetric.tmAscent;369err = ExtTextOutW(hMemoryDC, x, y, ETO_GLYPH_INDEX|ETO_OPAQUE,370(LPRECT)&rect, (LPCWSTR)&glyphCode, 1, NULL);371if (err == 0) {372FREE_AND_RETURN;373}374375/* Now get the image into a DIB.376* MS docs for GetDIBits says the compatible bitmap must not be377* selected into a DC, so restore the original first.378*/379SelectObject(hMemoryDC, hOrigBM);380SelectObject(hMemoryDC, oldFont);381DeleteObject(hFont);382383memset(&bmi, 0, sizeof(BITMAPINFO));384bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);385bmi.bmiHeader.biWidth = width;386bmi.bmiHeader.biHeight = -height;387bmi.bmiHeader.biPlanes = 1;388bmi.bmiHeader.biBitCount = 24;389bmi.bmiHeader.biCompression = BI_RGB;390391dibImage = SAFE_SIZE_ARRAY_ALLOC(malloc, dibBytesWidth, height);392if (dibImage == NULL) {393FREE_AND_RETURN;394}395dibImageSize = dibBytesWidth*height;396memset(dibImage, 0, dibImageSize);397398err = GetDIBits(hMemoryDC, hBitmap, 0, height, dibImage,399&bmi, DIB_RGB_COLORS);400401if (err == 0) { /* GetDIBits failed. */402FREE_AND_RETURN;403}404405err = SystemParametersInfo(SPI_GETFONTSMOOTHINGORIENTATION, 0, &orient, 0);406if (err == 0) {407FREE_AND_RETURN;408}409err = SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &gamma, 0);410if (err == 0) {411FREE_AND_RETURN;412}413igTable = getIGTable(gamma/10);414if (igTable == NULL) {415FREE_AND_RETURN;416}417418/* Now copy glyph image into a GlyphInfo structure and return it.419* NB the xadvance calculated here may be overwritten by the caller.420* 1 is subtracted from the bitmap width to get the glyph width, since421* that extra "1" was added as padding, so the sub-pixel positioning of422* fractional metrics could index into it.423*/424glyphInfo = (GlyphInfo*)SAFE_SIZE_STRUCT_ALLOC(malloc, sizeof(GlyphInfo),425bytesWidth, height);426if (glyphInfo == NULL) {427FREE_AND_RETURN;428}429imageSize = bytesWidth*height;430glyphInfo->cellInfo = NULL;431glyphInfo->rowBytes = bytesWidth;432glyphInfo->width = width;433if (fm) {434glyphInfo->width -= 1; // must subtract 1435}436glyphInfo->height = height;437glyphInfo->advanceX = advanceX;438glyphInfo->advanceY = advanceY;439glyphInfo->topLeftX = (float)(topLeftX-1);440if (fm) {441glyphInfo->topLeftX -= 1;442}443glyphInfo->topLeftY = (float)-topLeftY;444glyphInfo->image = (unsigned char*)glyphInfo+sizeof(GlyphInfo);445memset(glyphInfo->image, 0, imageSize);446447/* DIB 24bpp data is always stored in BGR order, but we usually448* need this in RGB, so we can't just memcpy and need to swap B and R.449* Also need to apply inverse gamma adjustment here.450* We re-use the variable "extra" to see if the last pixel is touched451* at all. If its not we can reduce the glyph image width. This comes452* into play in some cases where GDI touches more pixels than accounted453* for by increasing width by two pixels over the B&W image. Whilst454* the bytes are in the cache, it doesn't affect rendering performance455* of the hardware pipelines.456*/457extra = 0;458if (fm) {459extra = 1; // always need it.460}461dibRowPtr = dibImage;462rowPtr = glyphInfo->image;463for (y=0;y<height;y++) {464pixelPtr = rowPtr;465dibPixPtr = dibRowPtr;466for (x=0;x<width;x++) {467if (orient == FE_FONTSMOOTHINGORIENTATIONRGB) {468b = *dibPixPtr++;469g = *dibPixPtr++;470r = *dibPixPtr++;471} else {472r = *dibPixPtr++;473g = *dibPixPtr++;474b = *dibPixPtr++;475}476*pixelPtr++ = igTable[r];477*pixelPtr++ = igTable[g];478*pixelPtr++ = igTable[b];479if (!fm && (x==(width-1)) && (r|g|b)) {480extra = 1;481}482}483dibRowPtr += dibBytesWidth;484rowPtr += bytesWidth;485}486if (!extra) {487glyphInfo->width -= 1;488}489490free(dibImage);491ReleaseDC(hWnd, hDesktopDC);492DeleteObject(hMemoryDC);493DeleteObject(hBitmap);494DeleteObject(tmpBitmap);495496return ptr_to_jlong(glyphInfo);497}498499500