Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/sun/font/lcdglyph.c
32287 views
1
/*
2
* Copyright (c) 2008, 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
/*
27
* The function here is used to get a GDI rasterized LCD glyph and place it
28
* into the JDK glyph cache. The benefit is rendering fidelity for the
29
* most common cases, with no impact on the 2D rendering pipelines.
30
*
31
* Requires that the font and graphics are unrotated, and the scale is
32
* a simple one, and the font is a TT font registered with windows.
33
* Those conditions are established by the calling code.
34
*
35
* This code
36
* - Receives the family name, style, and size of the font
37
* and creates a Font object.
38
* - Create a surface from which we can get a DC : must be 16 bit or more.
39
* Ideally we'd be able to specify the depth of this, but in practice we
40
* have to accept it will be the same as the default screen.
41
* - Selects the GDI font on to the device
42
* - Uses GetGlyphOutline to estimate the bounds.
43
* - Creates a DIB on to which to blit the image.
44
* - Creates a GlyphInfo structure and copies the GDI glyph and offsets
45
* into the glyph which is returned.
46
*/
47
48
#include <stdio.h>
49
#include <malloc.h>
50
#include <math.h>
51
#include <windows.h>
52
#include <winuser.h>
53
54
#include <jni.h>
55
#include <jni_util.h>
56
#include <jlong_md.h>
57
#include <sizecalc.h>
58
#include <sun_font_FileFontStrike.h>
59
60
#include "fontscalerdefs.h"
61
62
/* Some of these are also defined in awtmsg.h but I don't want a dependency
63
* on that here. They are needed here - and in awtmsg.h - until we
64
* move up our build to define WIN32_WINNT >= 0x501 (ie XP), since MS
65
* headers will not define them otherwise.
66
*/
67
#ifndef SPI_GETFONTSMOOTHINGTYPE
68
#define SPI_GETFONTSMOOTHINGTYPE 0x200A
69
#endif //SPI_GETFONTSMOOTHINGTYPE
70
71
#ifndef SPI_GETFONTSMOOTHINGCONTRAST
72
#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C
73
#endif //SPI_GETFONTSMOOTHINGCONTRAST
74
75
#ifndef SPI_GETFONTSMOOTHINGORIENTATION
76
#define SPI_GETFONTSMOOTHINGORIENTATION 0x2012
77
#endif //SPI_GETFONTSMOOTHINGORIENTATION
78
79
#ifndef FE_FONTSMOOTHINGORIENTATIONBGR
80
#define FE_FONTSMOOTHINGORIENTATIONBGR 0x0000
81
#endif //FE_FONTSMOOTHINGORIENTATIONBGR
82
83
#ifndef FE_FONTSMOOTHINGORIENTATIONRGB
84
#define FE_FONTSMOOTHINGORIENTATIONRGB 0x0001
85
#endif //FE_FONTSMOOTHINGORIENTATIONRGB
86
87
#define MIN_GAMMA 100
88
#define MAX_GAMMA 220
89
#define LCDLUTCOUNT (MAX_GAMMA-MIN_GAMMA+1)
90
91
static unsigned char* igLUTable[LCDLUTCOUNT];
92
93
static unsigned char* getIGTable(int gamma) {
94
int i, index;
95
double ig;
96
char *igTable;
97
98
if (gamma < MIN_GAMMA) {
99
gamma = MIN_GAMMA;
100
} else if (gamma > MAX_GAMMA) {
101
gamma = MAX_GAMMA;
102
}
103
104
index = gamma - MIN_GAMMA;
105
106
if (igLUTable[index] != NULL) {
107
return igLUTable[index];
108
}
109
igTable = (unsigned char*)malloc(256);
110
if (igTable == NULL) {
111
return NULL;
112
}
113
igTable[0] = 0;
114
igTable[255] = 255;
115
ig = ((double)gamma)/100.0;
116
117
for (i=1;i<255;i++) {
118
igTable[i] = (unsigned char)(pow(((double)i)/255.0, ig)*255);
119
}
120
igLUTable[index] = igTable;
121
return igTable;
122
}
123
124
125
JNIEXPORT jboolean JNICALL
126
Java_sun_font_FileFontStrike_initNative(JNIEnv *env, jclass unused) {
127
128
DWORD osVersion = GetVersion();
129
DWORD majorVersion = (DWORD)(LOBYTE(LOWORD(osVersion)));
130
DWORD minorVersion = (DWORD)(HIBYTE(LOWORD(osVersion)));
131
132
/* Need at least XP which is 5.1 */
133
if (majorVersion < 5 || (majorVersion == 5 && minorVersion < 1)) {
134
return JNI_FALSE;
135
}
136
137
memset(igLUTable, 0, LCDLUTCOUNT);
138
139
return JNI_TRUE;
140
}
141
142
#ifndef CLEARTYPE_QUALITY
143
#define CLEARTYPE_QUALITY 5
144
#endif
145
146
#ifndef CLEARTYPE_NATURAL_QUALITY
147
#define CLEARTYPE_NATURAL_QUALITY 6
148
#endif
149
150
#define FREE_AND_RETURN \
151
if (hDesktopDC != 0 && hWnd != 0) { \
152
ReleaseDC(hWnd, hDesktopDC); \
153
}\
154
if (hMemoryDC != 0) { \
155
DeleteObject(hMemoryDC); \
156
} \
157
if (hBitmap != 0) { \
158
DeleteObject(hBitmap); \
159
} \
160
if (tmpBitmap != 0) { \
161
DeleteObject(tmpBitmap); \
162
} \
163
if (dibImage != NULL) { \
164
free(dibImage); \
165
} \
166
if (glyphInfo != NULL) { \
167
free(glyphInfo); \
168
} \
169
return (jlong)0;
170
/* end define */
171
172
JNIEXPORT jlong JNICALL
173
Java_sun_font_FileFontStrike__1getGlyphImageFromWindows
174
(JNIEnv *env, jobject unused,
175
jstring fontFamily, jint style, jint size, jint glyphCode, jboolean fm,
176
jint fontDataSize) {
177
178
GLYPHMETRICS glyphMetrics;
179
LOGFONTW lf;
180
BITMAPINFO bmi;
181
TEXTMETRIC textMetric;
182
RECT rect;
183
int bytesWidth, dibBytesWidth, extra, imageSize, dibImageSize;
184
unsigned char* dibImage = NULL, *rowPtr, *pixelPtr, *dibPixPtr, *dibRowPtr;
185
unsigned char r,g,b;
186
unsigned char* igTable;
187
GlyphInfo* glyphInfo = NULL;
188
int nameLen;
189
LPWSTR name;
190
HFONT oldFont, hFont;
191
MAT2 mat2;
192
DWORD actualFontDataSize;
193
194
unsigned short width;
195
unsigned short height;
196
short advanceX;
197
short advanceY;
198
int topLeftX;
199
int topLeftY;
200
int err;
201
int bmWidth, bmHeight;
202
int x, y;
203
HBITMAP hBitmap = NULL, hOrigBM;
204
HBITMAP tmpBitmap = NULL;
205
int gamma, orient;
206
207
HWND hWnd = NULL;
208
HDC hDesktopDC = NULL;
209
HDC hMemoryDC = NULL;
210
211
hWnd = GetDesktopWindow();
212
hDesktopDC = GetWindowDC(hWnd);
213
if (hDesktopDC == NULL) {
214
return (jlong)0;
215
}
216
if (GetDeviceCaps(hDesktopDC, BITSPIXEL) < 15) {
217
FREE_AND_RETURN;
218
}
219
220
hMemoryDC = CreateCompatibleDC(hDesktopDC);
221
if (hMemoryDC == NULL || fontFamily == NULL) {
222
FREE_AND_RETURN;
223
}
224
err = SetMapMode(hMemoryDC, MM_TEXT);
225
if (err == 0) {
226
FREE_AND_RETURN;
227
}
228
229
memset(&lf, 0, sizeof(LOGFONTW));
230
lf.lfHeight = -size;
231
lf.lfWeight = (style & 1) ? FW_BOLD : FW_NORMAL;
232
lf.lfItalic = (style & 2) ? 0xff : 0;
233
lf.lfCharSet = DEFAULT_CHARSET;
234
lf.lfQuality = CLEARTYPE_QUALITY;
235
lf.lfOutPrecision = OUT_TT_PRECIS;
236
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
237
lf.lfPitchAndFamily = DEFAULT_PITCH;
238
239
nameLen = (*env)->GetStringLength(env, fontFamily);
240
name = (LPWSTR)alloca((nameLen+1)*2);
241
if (name == NULL) {
242
FREE_AND_RETURN;
243
}
244
(*env)->GetStringRegion(env, fontFamily, 0, nameLen, name);
245
name[nameLen] = '\0';
246
247
if (nameLen < (sizeof(lf.lfFaceName) / sizeof(lf.lfFaceName[0]))) {
248
wcscpy(lf.lfFaceName, name);
249
} else {
250
FREE_AND_RETURN;
251
}
252
253
hFont = CreateFontIndirectW(&lf);
254
if (hFont == NULL) {
255
FREE_AND_RETURN;
256
}
257
oldFont = SelectObject(hMemoryDC, hFont);
258
259
if (fontDataSize > 0) {
260
// GDI doesn't allow to select a specific font file for drawing, we can
261
// only check that it picks the file we need by validating font size.
262
// If it doesn't match, we cannot proceed, as the same glyph code can
263
// correspond to a completely different glyph in the selected font.
264
actualFontDataSize = GetFontData(hMemoryDC, 0, 0, NULL, 0);
265
if (actualFontDataSize != fontDataSize) {
266
FREE_AND_RETURN;
267
}
268
}
269
270
tmpBitmap = CreateCompatibleBitmap(hDesktopDC, 1, 1);
271
if (tmpBitmap == NULL) {
272
FREE_AND_RETURN;
273
}
274
hOrigBM = (HBITMAP)SelectObject(hMemoryDC, tmpBitmap);
275
276
memset(&textMetric, 0, sizeof(TEXTMETRIC));
277
err = GetTextMetrics(hMemoryDC, &textMetric);
278
if (err == 0) {
279
FREE_AND_RETURN;
280
}
281
memset(&glyphMetrics, 0, sizeof(GLYPHMETRICS));
282
memset(&mat2, 0, sizeof(MAT2));
283
mat2.eM11.value = 1; mat2.eM22.value = 1;
284
err = GetGlyphOutline(hMemoryDC, glyphCode,
285
GGO_METRICS|GGO_GLYPH_INDEX,
286
&glyphMetrics,
287
0, NULL, &mat2);
288
if (err == GDI_ERROR) {
289
/* Probably no such glyph - ie the font wasn't the one we expected. */
290
FREE_AND_RETURN;
291
}
292
293
width = (unsigned short)glyphMetrics.gmBlackBoxX;
294
height = (unsigned short)glyphMetrics.gmBlackBoxY;
295
296
/* Don't handle "invisible" glyphs in this code */
297
if (width <= 0 || height == 0) {
298
FREE_AND_RETURN;
299
}
300
301
advanceX = glyphMetrics.gmCellIncX;
302
advanceY = glyphMetrics.gmCellIncY;
303
topLeftX = glyphMetrics.gmptGlyphOrigin.x;
304
topLeftY = glyphMetrics.gmptGlyphOrigin.y;
305
306
/* GetGlyphOutline pre-dates cleartype and I'm not sure that it will
307
* account for all pixels touched by the rendering. Need to widen,
308
* and also adjust by one the x position at which it is rendered.
309
* The extra pixels of width are used as follows :
310
* One extra pixel at the left and the right will be needed to absorb
311
* the pixels that will be touched by filtering by GDI to compensate
312
* for colour fringing.
313
* However there seem to be some cases where GDI renders two extra
314
* pixels to the right, so we add one additional pixel to the right,
315
* and in the code that copies this to the image cache we test for
316
* the (rare) cases when this is touched, and if its not reduce the
317
* stated image width for the blitting loops.
318
* For fractional metrics :
319
* One extra pixel at each end to account for sub-pixel positioning used
320
* when fractional metrics is on in LCD mode.
321
* The pixel at the left is needed so the blitting loop can index into
322
* that a byte at a time to more accurately position the glyph.
323
* The pixel at the right is needed so that when such indexing happens,
324
* the blitting still can use the same width.
325
* Consequently the width that is specified for the glyph is one less
326
* than that of the actual image.
327
* Note that in the FM case as a consequence we need to adjust the
328
* position at which GDI renders, and the declared width of the glyph
329
* See the if (fm) {} cases in the code.
330
* For the non-FM case, we not only save 3 bytes per row, but this
331
* prevents apparent glyph overlapping which affects the rendering
332
* performance of accelerated pipelines since it adds additional
333
* read-back requirements.
334
*/
335
width+=3;
336
if (fm) {
337
width+=1;
338
}
339
/* DIB scanline must end on a DWORD boundary. We specify 3 bytes per pixel,
340
* so must round up as needed to a multiple of 4 bytes.
341
*/
342
dibBytesWidth = bytesWidth = width*3;
343
extra = dibBytesWidth % 4;
344
if (extra != 0) {
345
dibBytesWidth += (4-extra);
346
}
347
/* The glyph cache image must be a multiple of 3 bytes wide. */
348
extra = bytesWidth % 3;
349
if (extra != 0) {
350
bytesWidth += (3-extra);
351
}
352
bmWidth = width;
353
bmHeight = height;
354
355
/* Must use desktop DC to create a bitmap of that depth */
356
hBitmap = CreateCompatibleBitmap(hDesktopDC, bmWidth, bmHeight);
357
if (hBitmap == NULL) {
358
FREE_AND_RETURN;
359
}
360
SelectObject(hMemoryDC, hBitmap);
361
362
/* Fill in black */
363
rect.left = 0;
364
rect.top = 0;
365
rect.right = bmWidth;
366
rect.bottom = bmHeight;
367
FillRect(hMemoryDC, (LPRECT)&rect, GetStockObject(BLACK_BRUSH));
368
369
/* Set text color to white, background to black. */
370
SetBkColor(hMemoryDC, RGB(0,0,0));
371
SetTextColor(hMemoryDC, RGB(255,255,255));
372
373
/* adjust rendering position */
374
x = -topLeftX+1;
375
if (fm) {
376
x += 1;
377
}
378
y = topLeftY - textMetric.tmAscent;
379
err = ExtTextOutW(hMemoryDC, x, y, ETO_GLYPH_INDEX|ETO_OPAQUE,
380
(LPRECT)&rect, (LPCWSTR)&glyphCode, 1, NULL);
381
if (err == 0) {
382
FREE_AND_RETURN;
383
}
384
385
/* Now get the image into a DIB.
386
* MS docs for GetDIBits says the compatible bitmap must not be
387
* selected into a DC, so restore the original first.
388
*/
389
SelectObject(hMemoryDC, hOrigBM);
390
SelectObject(hMemoryDC, oldFont);
391
DeleteObject(hFont);
392
393
memset(&bmi, 0, sizeof(BITMAPINFO));
394
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
395
bmi.bmiHeader.biWidth = width;
396
bmi.bmiHeader.biHeight = -height;
397
bmi.bmiHeader.biPlanes = 1;
398
bmi.bmiHeader.biBitCount = 24;
399
bmi.bmiHeader.biCompression = BI_RGB;
400
401
dibImage = SAFE_SIZE_ARRAY_ALLOC(malloc, dibBytesWidth, height);
402
if (dibImage == NULL) {
403
FREE_AND_RETURN;
404
}
405
dibImageSize = dibBytesWidth*height;
406
memset(dibImage, 0, dibImageSize);
407
408
err = GetDIBits(hMemoryDC, hBitmap, 0, height, dibImage,
409
&bmi, DIB_RGB_COLORS);
410
411
if (err == 0) { /* GetDIBits failed. */
412
FREE_AND_RETURN;
413
}
414
415
err = SystemParametersInfo(SPI_GETFONTSMOOTHINGORIENTATION, 0, &orient, 0);
416
if (err == 0) {
417
FREE_AND_RETURN;
418
}
419
err = SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &gamma, 0);
420
if (err == 0) {
421
FREE_AND_RETURN;
422
}
423
igTable = getIGTable(gamma/10);
424
if (igTable == NULL) {
425
FREE_AND_RETURN;
426
}
427
428
/* Now copy glyph image into a GlyphInfo structure and return it.
429
* NB the xadvance calculated here may be overwritten by the caller.
430
* 1 is subtracted from the bitmap width to get the glyph width, since
431
* that extra "1" was added as padding, so the sub-pixel positioning of
432
* fractional metrics could index into it.
433
*/
434
glyphInfo = (GlyphInfo*)SAFE_SIZE_STRUCT_ALLOC(malloc, sizeof(GlyphInfo),
435
bytesWidth, height);
436
if (glyphInfo == NULL) {
437
FREE_AND_RETURN;
438
}
439
imageSize = bytesWidth*height;
440
glyphInfo->cellInfo = NULL;
441
glyphInfo->rowBytes = bytesWidth;
442
glyphInfo->width = width;
443
if (fm) {
444
glyphInfo->width -= 1; // must subtract 1
445
}
446
glyphInfo->height = height;
447
glyphInfo->advanceX = advanceX;
448
glyphInfo->advanceY = advanceY;
449
glyphInfo->topLeftX = (float)(topLeftX-1);
450
if (fm) {
451
glyphInfo->topLeftX -= 1;
452
}
453
glyphInfo->topLeftY = (float)-topLeftY;
454
glyphInfo->image = (unsigned char*)glyphInfo+sizeof(GlyphInfo);
455
memset(glyphInfo->image, 0, imageSize);
456
457
/* DIB 24bpp data is always stored in BGR order, but we usually
458
* need this in RGB, so we can't just memcpy and need to swap B and R.
459
* Also need to apply inverse gamma adjustment here.
460
* We re-use the variable "extra" to see if the last pixel is touched
461
* at all. If its not we can reduce the glyph image width. This comes
462
* into play in some cases where GDI touches more pixels than accounted
463
* for by increasing width by two pixels over the B&W image. Whilst
464
* the bytes are in the cache, it doesn't affect rendering performance
465
* of the hardware pipelines.
466
*/
467
extra = 0;
468
if (fm) {
469
extra = 1; // always need it.
470
}
471
dibRowPtr = dibImage;
472
rowPtr = glyphInfo->image;
473
for (y=0;y<height;y++) {
474
pixelPtr = rowPtr;
475
dibPixPtr = dibRowPtr;
476
for (x=0;x<width;x++) {
477
if (orient == FE_FONTSMOOTHINGORIENTATIONRGB) {
478
b = *dibPixPtr++;
479
g = *dibPixPtr++;
480
r = *dibPixPtr++;
481
} else {
482
r = *dibPixPtr++;
483
g = *dibPixPtr++;
484
b = *dibPixPtr++;
485
}
486
*pixelPtr++ = igTable[r];
487
*pixelPtr++ = igTable[g];
488
*pixelPtr++ = igTable[b];
489
if (!fm && (x==(width-1)) && (r|g|b)) {
490
extra = 1;
491
}
492
}
493
dibRowPtr += dibBytesWidth;
494
rowPtr += bytesWidth;
495
}
496
if (!extra) {
497
glyphInfo->width -= 1;
498
}
499
500
free(dibImage);
501
ReleaseDC(hWnd, hDesktopDC);
502
DeleteObject(hMemoryDC);
503
DeleteObject(hBitmap);
504
DeleteObject(tmpBitmap);
505
506
return ptr_to_jlong(glyphInfo);
507
}
508
509