Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/windows/native/libfontmanager/lcdglyph.c
41152 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
memset(igLUTable, 0, LCDLUTCOUNT);
129
130
return JNI_TRUE;
131
}
132
133
#ifndef CLEARTYPE_QUALITY
134
#define CLEARTYPE_QUALITY 5
135
#endif
136
137
#ifndef CLEARTYPE_NATURAL_QUALITY
138
#define CLEARTYPE_NATURAL_QUALITY 6
139
#endif
140
141
#define FREE_AND_RETURN \
142
if (hDesktopDC != 0 && hWnd != 0) { \
143
ReleaseDC(hWnd, hDesktopDC); \
144
}\
145
if (hMemoryDC != 0) { \
146
DeleteObject(hMemoryDC); \
147
} \
148
if (hBitmap != 0) { \
149
DeleteObject(hBitmap); \
150
} \
151
if (tmpBitmap != 0) { \
152
DeleteObject(tmpBitmap); \
153
} \
154
if (dibImage != NULL) { \
155
free(dibImage); \
156
} \
157
if (glyphInfo != NULL) { \
158
free(glyphInfo); \
159
} \
160
return (jlong)0;
161
/* end define */
162
163
JNIEXPORT jlong JNICALL
164
Java_sun_font_FileFontStrike__1getGlyphImageFromWindows
165
(JNIEnv *env, jobject unused,
166
jstring fontFamily, jint style, jint size, jint glyphCode, jboolean fm,
167
jint fontDataSize) {
168
169
GLYPHMETRICS glyphMetrics;
170
LOGFONTW lf;
171
BITMAPINFO bmi;
172
TEXTMETRIC textMetric;
173
RECT rect;
174
int bytesWidth, dibBytesWidth, extra, imageSize, dibImageSize;
175
unsigned char* dibImage = NULL, *rowPtr, *pixelPtr, *dibPixPtr, *dibRowPtr;
176
unsigned char r,g,b;
177
unsigned char* igTable;
178
GlyphInfo* glyphInfo = NULL;
179
int nameLen;
180
LPWSTR name;
181
HFONT oldFont, hFont;
182
MAT2 mat2;
183
DWORD actualFontDataSize;
184
185
unsigned short width;
186
unsigned short height;
187
short advanceX;
188
short advanceY;
189
int topLeftX;
190
int topLeftY;
191
int err;
192
int bmWidth, bmHeight;
193
int x, y;
194
HBITMAP hBitmap = NULL, hOrigBM;
195
HBITMAP tmpBitmap = NULL;
196
int gamma, orient;
197
198
HWND hWnd = NULL;
199
HDC hDesktopDC = NULL;
200
HDC hMemoryDC = NULL;
201
202
hWnd = GetDesktopWindow();
203
hDesktopDC = GetWindowDC(hWnd);
204
if (hDesktopDC == NULL) {
205
return (jlong)0;
206
}
207
if (GetDeviceCaps(hDesktopDC, BITSPIXEL) < 15) {
208
FREE_AND_RETURN;
209
}
210
211
hMemoryDC = CreateCompatibleDC(hDesktopDC);
212
if (hMemoryDC == NULL || fontFamily == NULL) {
213
FREE_AND_RETURN;
214
}
215
err = SetMapMode(hMemoryDC, MM_TEXT);
216
if (err == 0) {
217
FREE_AND_RETURN;
218
}
219
220
memset(&lf, 0, sizeof(LOGFONTW));
221
lf.lfHeight = -size;
222
lf.lfWeight = (style & 1) ? FW_BOLD : FW_NORMAL;
223
lf.lfItalic = (style & 2) ? 0xff : 0;
224
lf.lfCharSet = DEFAULT_CHARSET;
225
lf.lfQuality = CLEARTYPE_QUALITY;
226
lf.lfOutPrecision = OUT_TT_PRECIS;
227
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
228
lf.lfPitchAndFamily = DEFAULT_PITCH;
229
230
nameLen = (*env)->GetStringLength(env, fontFamily);
231
name = (LPWSTR)alloca((nameLen+1)*2);
232
if (name == NULL) {
233
FREE_AND_RETURN;
234
}
235
(*env)->GetStringRegion(env, fontFamily, 0, nameLen, name);
236
name[nameLen] = '\0';
237
238
if (nameLen < (sizeof(lf.lfFaceName) / sizeof(lf.lfFaceName[0]))) {
239
wcscpy(lf.lfFaceName, name);
240
} else {
241
FREE_AND_RETURN;
242
}
243
244
hFont = CreateFontIndirectW(&lf);
245
if (hFont == NULL) {
246
FREE_AND_RETURN;
247
}
248
oldFont = SelectObject(hMemoryDC, hFont);
249
250
if (fontDataSize > 0) {
251
// GDI doesn't allow to select a specific font file for drawing, we can
252
// only check that it picks the file we need by validating font size.
253
// If it doesn't match, we cannot proceed, as the same glyph code can
254
// correspond to a completely different glyph in the selected font.
255
actualFontDataSize = GetFontData(hMemoryDC, 0, 0, NULL, 0);
256
if (actualFontDataSize != fontDataSize) {
257
FREE_AND_RETURN;
258
}
259
}
260
261
tmpBitmap = CreateCompatibleBitmap(hDesktopDC, 1, 1);
262
if (tmpBitmap == NULL) {
263
FREE_AND_RETURN;
264
}
265
hOrigBM = (HBITMAP)SelectObject(hMemoryDC, tmpBitmap);
266
267
memset(&textMetric, 0, sizeof(TEXTMETRIC));
268
err = GetTextMetrics(hMemoryDC, &textMetric);
269
if (err == 0) {
270
FREE_AND_RETURN;
271
}
272
memset(&glyphMetrics, 0, sizeof(GLYPHMETRICS));
273
memset(&mat2, 0, sizeof(MAT2));
274
mat2.eM11.value = 1; mat2.eM22.value = 1;
275
err = GetGlyphOutline(hMemoryDC, glyphCode,
276
GGO_METRICS|GGO_GLYPH_INDEX,
277
&glyphMetrics,
278
0, NULL, &mat2);
279
if (err == GDI_ERROR) {
280
/* Probably no such glyph - ie the font wasn't the one we expected. */
281
FREE_AND_RETURN;
282
}
283
284
width = (unsigned short)glyphMetrics.gmBlackBoxX;
285
height = (unsigned short)glyphMetrics.gmBlackBoxY;
286
287
/* Don't handle "invisible" glyphs in this code */
288
if (width <= 0 || height == 0) {
289
FREE_AND_RETURN;
290
}
291
292
advanceX = glyphMetrics.gmCellIncX;
293
advanceY = glyphMetrics.gmCellIncY;
294
topLeftX = glyphMetrics.gmptGlyphOrigin.x;
295
topLeftY = glyphMetrics.gmptGlyphOrigin.y;
296
297
/* GetGlyphOutline pre-dates cleartype and I'm not sure that it will
298
* account for all pixels touched by the rendering. Need to widen,
299
* and also adjust by one the x position at which it is rendered.
300
* The extra pixels of width are used as follows :
301
* One extra pixel at the left and the right will be needed to absorb
302
* the pixels that will be touched by filtering by GDI to compensate
303
* for colour fringing.
304
* However there seem to be some cases where GDI renders two extra
305
* pixels to the right, so we add one additional pixel to the right,
306
* and in the code that copies this to the image cache we test for
307
* the (rare) cases when this is touched, and if its not reduce the
308
* stated image width for the blitting loops.
309
* For fractional metrics :
310
* One extra pixel at each end to account for sub-pixel positioning used
311
* when fractional metrics is on in LCD mode.
312
* The pixel at the left is needed so the blitting loop can index into
313
* that a byte at a time to more accurately position the glyph.
314
* The pixel at the right is needed so that when such indexing happens,
315
* the blitting still can use the same width.
316
* Consequently the width that is specified for the glyph is one less
317
* than that of the actual image.
318
* Note that in the FM case as a consequence we need to adjust the
319
* position at which GDI renders, and the declared width of the glyph
320
* See the if (fm) {} cases in the code.
321
* For the non-FM case, we not only save 3 bytes per row, but this
322
* prevents apparent glyph overlapping which affects the rendering
323
* performance of accelerated pipelines since it adds additional
324
* read-back requirements.
325
*/
326
width+=3;
327
if (fm) {
328
width+=1;
329
}
330
/* DIB scanline must end on a DWORD boundary. We specify 3 bytes per pixel,
331
* so must round up as needed to a multiple of 4 bytes.
332
*/
333
dibBytesWidth = bytesWidth = width*3;
334
extra = dibBytesWidth % 4;
335
if (extra != 0) {
336
dibBytesWidth += (4-extra);
337
}
338
/* The glyph cache image must be a multiple of 3 bytes wide. */
339
extra = bytesWidth % 3;
340
if (extra != 0) {
341
bytesWidth += (3-extra);
342
}
343
bmWidth = width;
344
bmHeight = height;
345
346
/* Must use desktop DC to create a bitmap of that depth */
347
hBitmap = CreateCompatibleBitmap(hDesktopDC, bmWidth, bmHeight);
348
if (hBitmap == NULL) {
349
FREE_AND_RETURN;
350
}
351
SelectObject(hMemoryDC, hBitmap);
352
353
/* Fill in black */
354
rect.left = 0;
355
rect.top = 0;
356
rect.right = bmWidth;
357
rect.bottom = bmHeight;
358
FillRect(hMemoryDC, (LPRECT)&rect, GetStockObject(BLACK_BRUSH));
359
360
/* Set text color to white, background to black. */
361
SetBkColor(hMemoryDC, RGB(0,0,0));
362
SetTextColor(hMemoryDC, RGB(255,255,255));
363
364
/* adjust rendering position */
365
x = -topLeftX+1;
366
if (fm) {
367
x += 1;
368
}
369
y = topLeftY - textMetric.tmAscent;
370
err = ExtTextOutW(hMemoryDC, x, y, ETO_GLYPH_INDEX|ETO_OPAQUE,
371
(LPRECT)&rect, (LPCWSTR)&glyphCode, 1, NULL);
372
if (err == 0) {
373
FREE_AND_RETURN;
374
}
375
376
/* Now get the image into a DIB.
377
* MS docs for GetDIBits says the compatible bitmap must not be
378
* selected into a DC, so restore the original first.
379
*/
380
SelectObject(hMemoryDC, hOrigBM);
381
SelectObject(hMemoryDC, oldFont);
382
DeleteObject(hFont);
383
384
memset(&bmi, 0, sizeof(BITMAPINFO));
385
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
386
bmi.bmiHeader.biWidth = width;
387
bmi.bmiHeader.biHeight = -height;
388
bmi.bmiHeader.biPlanes = 1;
389
bmi.bmiHeader.biBitCount = 24;
390
bmi.bmiHeader.biCompression = BI_RGB;
391
392
dibImage = SAFE_SIZE_ARRAY_ALLOC(malloc, dibBytesWidth, height);
393
if (dibImage == NULL) {
394
FREE_AND_RETURN;
395
}
396
dibImageSize = dibBytesWidth*height;
397
memset(dibImage, 0, dibImageSize);
398
399
err = GetDIBits(hMemoryDC, hBitmap, 0, height, dibImage,
400
&bmi, DIB_RGB_COLORS);
401
402
if (err == 0) { /* GetDIBits failed. */
403
FREE_AND_RETURN;
404
}
405
406
err = SystemParametersInfo(SPI_GETFONTSMOOTHINGORIENTATION, 0, &orient, 0);
407
if (err == 0) {
408
FREE_AND_RETURN;
409
}
410
err = SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &gamma, 0);
411
if (err == 0) {
412
FREE_AND_RETURN;
413
}
414
igTable = getIGTable(gamma/10);
415
if (igTable == NULL) {
416
FREE_AND_RETURN;
417
}
418
419
/* Now copy glyph image into a GlyphInfo structure and return it.
420
* NB the xadvance calculated here may be overwritten by the caller.
421
* 1 is subtracted from the bitmap width to get the glyph width, since
422
* that extra "1" was added as padding, so the sub-pixel positioning of
423
* fractional metrics could index into it.
424
*/
425
glyphInfo = (GlyphInfo*)SAFE_SIZE_STRUCT_ALLOC(malloc, sizeof(GlyphInfo),
426
bytesWidth, height);
427
if (glyphInfo == NULL) {
428
FREE_AND_RETURN;
429
}
430
imageSize = bytesWidth*height;
431
glyphInfo->cellInfo = NULL;
432
glyphInfo->rowBytes = bytesWidth;
433
glyphInfo->width = width;
434
if (fm) {
435
glyphInfo->width -= 1; // must subtract 1
436
}
437
glyphInfo->height = height;
438
glyphInfo->advanceX = advanceX;
439
glyphInfo->advanceY = advanceY;
440
glyphInfo->topLeftX = (float)(topLeftX-1);
441
if (fm) {
442
glyphInfo->topLeftX -= 1;
443
}
444
glyphInfo->topLeftY = (float)-topLeftY;
445
glyphInfo->image = (unsigned char*)glyphInfo+sizeof(GlyphInfo);
446
memset(glyphInfo->image, 0, imageSize);
447
448
/* DIB 24bpp data is always stored in BGR order, but we usually
449
* need this in RGB, so we can't just memcpy and need to swap B and R.
450
* Also need to apply inverse gamma adjustment here.
451
* We re-use the variable "extra" to see if the last pixel is touched
452
* at all. If its not we can reduce the glyph image width. This comes
453
* into play in some cases where GDI touches more pixels than accounted
454
* for by increasing width by two pixels over the B&W image. Whilst
455
* the bytes are in the cache, it doesn't affect rendering performance
456
* of the hardware pipelines.
457
*/
458
extra = 0;
459
if (fm) {
460
extra = 1; // always need it.
461
}
462
dibRowPtr = dibImage;
463
rowPtr = glyphInfo->image;
464
for (y=0;y<height;y++) {
465
pixelPtr = rowPtr;
466
dibPixPtr = dibRowPtr;
467
for (x=0;x<width;x++) {
468
if (orient == FE_FONTSMOOTHINGORIENTATIONRGB) {
469
b = *dibPixPtr++;
470
g = *dibPixPtr++;
471
r = *dibPixPtr++;
472
} else {
473
r = *dibPixPtr++;
474
g = *dibPixPtr++;
475
b = *dibPixPtr++;
476
}
477
*pixelPtr++ = igTable[r];
478
*pixelPtr++ = igTable[g];
479
*pixelPtr++ = igTable[b];
480
if (!fm && (x==(width-1)) && (r|g|b)) {
481
extra = 1;
482
}
483
}
484
dibRowPtr += dibBytesWidth;
485
rowPtr += bytesWidth;
486
}
487
if (!extra) {
488
glyphInfo->width -= 1;
489
}
490
491
free(dibImage);
492
ReleaseDC(hWnd, hDesktopDC);
493
DeleteObject(hMemoryDC);
494
DeleteObject(hBitmap);
495
DeleteObject(tmpBitmap);
496
497
return ptr_to_jlong(glyphInfo);
498
}
499
500