Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/sun/font/lcdglyph.c
32287 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) {126127DWORD osVersion = GetVersion();128DWORD majorVersion = (DWORD)(LOBYTE(LOWORD(osVersion)));129DWORD minorVersion = (DWORD)(HIBYTE(LOWORD(osVersion)));130131/* Need at least XP which is 5.1 */132if (majorVersion < 5 || (majorVersion == 5 && minorVersion < 1)) {133return JNI_FALSE;134}135136memset(igLUTable, 0, LCDLUTCOUNT);137138return JNI_TRUE;139}140141#ifndef CLEARTYPE_QUALITY142#define CLEARTYPE_QUALITY 5143#endif144145#ifndef CLEARTYPE_NATURAL_QUALITY146#define CLEARTYPE_NATURAL_QUALITY 6147#endif148149#define FREE_AND_RETURN \150if (hDesktopDC != 0 && hWnd != 0) { \151ReleaseDC(hWnd, hDesktopDC); \152}\153if (hMemoryDC != 0) { \154DeleteObject(hMemoryDC); \155} \156if (hBitmap != 0) { \157DeleteObject(hBitmap); \158} \159if (tmpBitmap != 0) { \160DeleteObject(tmpBitmap); \161} \162if (dibImage != NULL) { \163free(dibImage); \164} \165if (glyphInfo != NULL) { \166free(glyphInfo); \167} \168return (jlong)0;169/* end define */170171JNIEXPORT jlong JNICALL172Java_sun_font_FileFontStrike__1getGlyphImageFromWindows173(JNIEnv *env, jobject unused,174jstring fontFamily, jint style, jint size, jint glyphCode, jboolean fm,175jint fontDataSize) {176177GLYPHMETRICS glyphMetrics;178LOGFONTW lf;179BITMAPINFO bmi;180TEXTMETRIC textMetric;181RECT rect;182int bytesWidth, dibBytesWidth, extra, imageSize, dibImageSize;183unsigned char* dibImage = NULL, *rowPtr, *pixelPtr, *dibPixPtr, *dibRowPtr;184unsigned char r,g,b;185unsigned char* igTable;186GlyphInfo* glyphInfo = NULL;187int nameLen;188LPWSTR name;189HFONT oldFont, hFont;190MAT2 mat2;191DWORD actualFontDataSize;192193unsigned short width;194unsigned short height;195short advanceX;196short advanceY;197int topLeftX;198int topLeftY;199int err;200int bmWidth, bmHeight;201int x, y;202HBITMAP hBitmap = NULL, hOrigBM;203HBITMAP tmpBitmap = NULL;204int gamma, orient;205206HWND hWnd = NULL;207HDC hDesktopDC = NULL;208HDC hMemoryDC = NULL;209210hWnd = GetDesktopWindow();211hDesktopDC = GetWindowDC(hWnd);212if (hDesktopDC == NULL) {213return (jlong)0;214}215if (GetDeviceCaps(hDesktopDC, BITSPIXEL) < 15) {216FREE_AND_RETURN;217}218219hMemoryDC = CreateCompatibleDC(hDesktopDC);220if (hMemoryDC == NULL || fontFamily == NULL) {221FREE_AND_RETURN;222}223err = SetMapMode(hMemoryDC, MM_TEXT);224if (err == 0) {225FREE_AND_RETURN;226}227228memset(&lf, 0, sizeof(LOGFONTW));229lf.lfHeight = -size;230lf.lfWeight = (style & 1) ? FW_BOLD : FW_NORMAL;231lf.lfItalic = (style & 2) ? 0xff : 0;232lf.lfCharSet = DEFAULT_CHARSET;233lf.lfQuality = CLEARTYPE_QUALITY;234lf.lfOutPrecision = OUT_TT_PRECIS;235lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;236lf.lfPitchAndFamily = DEFAULT_PITCH;237238nameLen = (*env)->GetStringLength(env, fontFamily);239name = (LPWSTR)alloca((nameLen+1)*2);240if (name == NULL) {241FREE_AND_RETURN;242}243(*env)->GetStringRegion(env, fontFamily, 0, nameLen, name);244name[nameLen] = '\0';245246if (nameLen < (sizeof(lf.lfFaceName) / sizeof(lf.lfFaceName[0]))) {247wcscpy(lf.lfFaceName, name);248} else {249FREE_AND_RETURN;250}251252hFont = CreateFontIndirectW(&lf);253if (hFont == NULL) {254FREE_AND_RETURN;255}256oldFont = SelectObject(hMemoryDC, hFont);257258if (fontDataSize > 0) {259// GDI doesn't allow to select a specific font file for drawing, we can260// only check that it picks the file we need by validating font size.261// If it doesn't match, we cannot proceed, as the same glyph code can262// correspond to a completely different glyph in the selected font.263actualFontDataSize = GetFontData(hMemoryDC, 0, 0, NULL, 0);264if (actualFontDataSize != fontDataSize) {265FREE_AND_RETURN;266}267}268269tmpBitmap = CreateCompatibleBitmap(hDesktopDC, 1, 1);270if (tmpBitmap == NULL) {271FREE_AND_RETURN;272}273hOrigBM = (HBITMAP)SelectObject(hMemoryDC, tmpBitmap);274275memset(&textMetric, 0, sizeof(TEXTMETRIC));276err = GetTextMetrics(hMemoryDC, &textMetric);277if (err == 0) {278FREE_AND_RETURN;279}280memset(&glyphMetrics, 0, sizeof(GLYPHMETRICS));281memset(&mat2, 0, sizeof(MAT2));282mat2.eM11.value = 1; mat2.eM22.value = 1;283err = GetGlyphOutline(hMemoryDC, glyphCode,284GGO_METRICS|GGO_GLYPH_INDEX,285&glyphMetrics,2860, NULL, &mat2);287if (err == GDI_ERROR) {288/* Probably no such glyph - ie the font wasn't the one we expected. */289FREE_AND_RETURN;290}291292width = (unsigned short)glyphMetrics.gmBlackBoxX;293height = (unsigned short)glyphMetrics.gmBlackBoxY;294295/* Don't handle "invisible" glyphs in this code */296if (width <= 0 || height == 0) {297FREE_AND_RETURN;298}299300advanceX = glyphMetrics.gmCellIncX;301advanceY = glyphMetrics.gmCellIncY;302topLeftX = glyphMetrics.gmptGlyphOrigin.x;303topLeftY = glyphMetrics.gmptGlyphOrigin.y;304305/* GetGlyphOutline pre-dates cleartype and I'm not sure that it will306* account for all pixels touched by the rendering. Need to widen,307* and also adjust by one the x position at which it is rendered.308* The extra pixels of width are used as follows :309* One extra pixel at the left and the right will be needed to absorb310* the pixels that will be touched by filtering by GDI to compensate311* for colour fringing.312* However there seem to be some cases where GDI renders two extra313* pixels to the right, so we add one additional pixel to the right,314* and in the code that copies this to the image cache we test for315* the (rare) cases when this is touched, and if its not reduce the316* stated image width for the blitting loops.317* For fractional metrics :318* One extra pixel at each end to account for sub-pixel positioning used319* when fractional metrics is on in LCD mode.320* The pixel at the left is needed so the blitting loop can index into321* that a byte at a time to more accurately position the glyph.322* The pixel at the right is needed so that when such indexing happens,323* the blitting still can use the same width.324* Consequently the width that is specified for the glyph is one less325* than that of the actual image.326* Note that in the FM case as a consequence we need to adjust the327* position at which GDI renders, and the declared width of the glyph328* See the if (fm) {} cases in the code.329* For the non-FM case, we not only save 3 bytes per row, but this330* prevents apparent glyph overlapping which affects the rendering331* performance of accelerated pipelines since it adds additional332* read-back requirements.333*/334width+=3;335if (fm) {336width+=1;337}338/* DIB scanline must end on a DWORD boundary. We specify 3 bytes per pixel,339* so must round up as needed to a multiple of 4 bytes.340*/341dibBytesWidth = bytesWidth = width*3;342extra = dibBytesWidth % 4;343if (extra != 0) {344dibBytesWidth += (4-extra);345}346/* The glyph cache image must be a multiple of 3 bytes wide. */347extra = bytesWidth % 3;348if (extra != 0) {349bytesWidth += (3-extra);350}351bmWidth = width;352bmHeight = height;353354/* Must use desktop DC to create a bitmap of that depth */355hBitmap = CreateCompatibleBitmap(hDesktopDC, bmWidth, bmHeight);356if (hBitmap == NULL) {357FREE_AND_RETURN;358}359SelectObject(hMemoryDC, hBitmap);360361/* Fill in black */362rect.left = 0;363rect.top = 0;364rect.right = bmWidth;365rect.bottom = bmHeight;366FillRect(hMemoryDC, (LPRECT)&rect, GetStockObject(BLACK_BRUSH));367368/* Set text color to white, background to black. */369SetBkColor(hMemoryDC, RGB(0,0,0));370SetTextColor(hMemoryDC, RGB(255,255,255));371372/* adjust rendering position */373x = -topLeftX+1;374if (fm) {375x += 1;376}377y = topLeftY - textMetric.tmAscent;378err = ExtTextOutW(hMemoryDC, x, y, ETO_GLYPH_INDEX|ETO_OPAQUE,379(LPRECT)&rect, (LPCWSTR)&glyphCode, 1, NULL);380if (err == 0) {381FREE_AND_RETURN;382}383384/* Now get the image into a DIB.385* MS docs for GetDIBits says the compatible bitmap must not be386* selected into a DC, so restore the original first.387*/388SelectObject(hMemoryDC, hOrigBM);389SelectObject(hMemoryDC, oldFont);390DeleteObject(hFont);391392memset(&bmi, 0, sizeof(BITMAPINFO));393bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);394bmi.bmiHeader.biWidth = width;395bmi.bmiHeader.biHeight = -height;396bmi.bmiHeader.biPlanes = 1;397bmi.bmiHeader.biBitCount = 24;398bmi.bmiHeader.biCompression = BI_RGB;399400dibImage = SAFE_SIZE_ARRAY_ALLOC(malloc, dibBytesWidth, height);401if (dibImage == NULL) {402FREE_AND_RETURN;403}404dibImageSize = dibBytesWidth*height;405memset(dibImage, 0, dibImageSize);406407err = GetDIBits(hMemoryDC, hBitmap, 0, height, dibImage,408&bmi, DIB_RGB_COLORS);409410if (err == 0) { /* GetDIBits failed. */411FREE_AND_RETURN;412}413414err = SystemParametersInfo(SPI_GETFONTSMOOTHINGORIENTATION, 0, &orient, 0);415if (err == 0) {416FREE_AND_RETURN;417}418err = SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &gamma, 0);419if (err == 0) {420FREE_AND_RETURN;421}422igTable = getIGTable(gamma/10);423if (igTable == NULL) {424FREE_AND_RETURN;425}426427/* Now copy glyph image into a GlyphInfo structure and return it.428* NB the xadvance calculated here may be overwritten by the caller.429* 1 is subtracted from the bitmap width to get the glyph width, since430* that extra "1" was added as padding, so the sub-pixel positioning of431* fractional metrics could index into it.432*/433glyphInfo = (GlyphInfo*)SAFE_SIZE_STRUCT_ALLOC(malloc, sizeof(GlyphInfo),434bytesWidth, height);435if (glyphInfo == NULL) {436FREE_AND_RETURN;437}438imageSize = bytesWidth*height;439glyphInfo->cellInfo = NULL;440glyphInfo->rowBytes = bytesWidth;441glyphInfo->width = width;442if (fm) {443glyphInfo->width -= 1; // must subtract 1444}445glyphInfo->height = height;446glyphInfo->advanceX = advanceX;447glyphInfo->advanceY = advanceY;448glyphInfo->topLeftX = (float)(topLeftX-1);449if (fm) {450glyphInfo->topLeftX -= 1;451}452glyphInfo->topLeftY = (float)-topLeftY;453glyphInfo->image = (unsigned char*)glyphInfo+sizeof(GlyphInfo);454memset(glyphInfo->image, 0, imageSize);455456/* DIB 24bpp data is always stored in BGR order, but we usually457* need this in RGB, so we can't just memcpy and need to swap B and R.458* Also need to apply inverse gamma adjustment here.459* We re-use the variable "extra" to see if the last pixel is touched460* at all. If its not we can reduce the glyph image width. This comes461* into play in some cases where GDI touches more pixels than accounted462* for by increasing width by two pixels over the B&W image. Whilst463* the bytes are in the cache, it doesn't affect rendering performance464* of the hardware pipelines.465*/466extra = 0;467if (fm) {468extra = 1; // always need it.469}470dibRowPtr = dibImage;471rowPtr = glyphInfo->image;472for (y=0;y<height;y++) {473pixelPtr = rowPtr;474dibPixPtr = dibRowPtr;475for (x=0;x<width;x++) {476if (orient == FE_FONTSMOOTHINGORIENTATIONRGB) {477b = *dibPixPtr++;478g = *dibPixPtr++;479r = *dibPixPtr++;480} else {481r = *dibPixPtr++;482g = *dibPixPtr++;483b = *dibPixPtr++;484}485*pixelPtr++ = igTable[r];486*pixelPtr++ = igTable[g];487*pixelPtr++ = igTable[b];488if (!fm && (x==(width-1)) && (r|g|b)) {489extra = 1;490}491}492dibRowPtr += dibBytesWidth;493rowPtr += bytesWidth;494}495if (!extra) {496glyphInfo->width -= 1;497}498499free(dibImage);500ReleaseDC(hWnd, hDesktopDC);501DeleteObject(hMemoryDC);502DeleteObject(hBitmap);503DeleteObject(tmpBitmap);504505return ptr_to_jlong(glyphInfo);506}507508509