Skip to content
This repository was archived by the owner on Jul 17, 2024. It is now read-only.
/ jfx22u Public archive

Commit 75fdcfb

Browse files
author
Lukasz Kostyra
committedOct 31, 2023
8313040: Enhanced Font handling
Reviewed-by: rhalade, prr, kcr
1 parent e7a3e79 commit 75fdcfb

File tree

6 files changed

+189
-48
lines changed

6 files changed

+189
-48
lines changed
 

‎modules/javafx.graphics/src/main/java/com/sun/javafx/font/PrismFontFactory.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -954,15 +954,14 @@ private String findFile(String name) {
954954
private static String sysFontDir = null;
955955
private static String userFontDir = null;
956956

957-
private static native byte[] getFontPath();
957+
private static native String getFontPath();
958958

959959
private static void getPlatformFontDirs() {
960960

961961
if (userFontDir != null || sysFontDir != null) {
962962
return;
963963
}
964-
byte [] pathBytes = getFontPath();
965-
String path = new String(pathBytes);
964+
String path = getFontPath();
966965

967966
int scIdx = path.indexOf(';');
968967
if (scIdx < 0) {

‎modules/javafx.graphics/src/main/native-font/coretext.c

+7-1
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,13 @@ JNIEXPORT jlong JNICALL OS_NATIVE(CFStringCreateWithCharacters__J_3CJJ)
672672
{
673673
jchar *lparg1=NULL;
674674
jlong rc = 0;
675-
if (arg1) if ((lparg1 = (*env)->GetPrimitiveArrayCritical(env, arg1, NULL)) == NULL) goto fail;
675+
if (!arg1) goto fail;
676+
if ((lparg1 = (*env)->GetPrimitiveArrayCritical(env, arg1, NULL)) == NULL) goto fail;
677+
if (arg2 < 0) goto fail;
678+
if (arg3 < 0) goto fail;
679+
if (arg2 > LONG_MAX - arg3) goto fail;
680+
if (arg2 + arg3 > (*env)->GetArrayLength(env, arg1)) goto fail;
681+
676682
UniChar* str = lparg1 + arg2;
677683
rc = (jlong)CFStringCreateWithCharacters((CFAllocatorRef)arg0, str, (CFIndex)arg3);
678684
fail:

‎modules/javafx.graphics/src/main/native-font/directwrite.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -1517,6 +1517,8 @@ JNIEXPORT jint JNICALL OS_NATIVE(JFXTextRendererGetGlyphIndices)
15171517
if (!arg1) return 0;
15181518
jint* data = env->GetIntArrayElements(arg1, NULL);
15191519
if (!data) return 0;
1520+
if (start < 0) return 0;
1521+
if (slot < 0) return 0;
15201522

15211523
JFXTextRenderer* renderer = (JFXTextRenderer*)arg0;
15221524
// Type cast unsigned int to int. It is safe to assume that GetGlyphCount will never exceed max of jint
@@ -1538,6 +1540,7 @@ JNIEXPORT jint JNICALL OS_NATIVE(JFXTextRendererGetGlyphAdvances)
15381540
if (!arg1) return 0;
15391541
jfloat* data = env->GetFloatArrayElements(arg1, NULL);
15401542
if (!data) return 0;
1543+
if (start < 0) return 0;
15411544

15421545
JFXTextRenderer* renderer = (JFXTextRenderer*)arg0;
15431546
// Type cast unsigned int to int. It is safe to assume that GetGlyphCount will never exceed max of jint
@@ -1559,12 +1562,14 @@ JNIEXPORT jint JNICALL OS_NATIVE(JFXTextRendererGetGlyphOffsets)
15591562
if (!arg1) return 0;
15601563
jfloat* data = env->GetFloatArrayElements(arg1, NULL);
15611564
if (!data) return 0;
1565+
if (start < 0) return 0;
15621566

15631567
JFXTextRenderer* renderer = (JFXTextRenderer*)arg0;
15641568
// Type cast unsigned int to int. It is safe to assume the result will never exceed max of jint
15651569
jint offsetCount = (jint) renderer->GetGlyphCount() * 2;
15661570
jint length = env->GetArrayLength(arg1);
15671571
jint copiedCount = length - start > offsetCount ? offsetCount : length - start;
1572+
if (copiedCount % 2 != 0) return 0;
15681573

15691574
const DWRITE_GLYPH_OFFSET* offsets = renderer->GetGlyphOffsets();
15701575
UINT32 i = 0, j = 0;
@@ -1582,6 +1587,8 @@ JNIEXPORT jint JNICALL OS_NATIVE(JFXTextRendererGetClusterMap)
15821587
if (!arg1) return 0;
15831588
jshort* data = env->GetShortArrayElements(arg1, NULL);
15841589
if (!data) return 0;
1590+
if (start < 0) return 0;
1591+
if (glyphStart < 0) return 0;
15851592

15861593
JFXTextRenderer* renderer = (JFXTextRenderer*)arg0;
15871594
// Type cast unsigned int to int. It is safe to assume that GetLength will never exceed max of jint
@@ -1890,6 +1897,8 @@ JNIEXPORT jlong JNICALL OS_NATIVE(CreateTextLayout)
18901897
IDWriteTextLayout* result = NULL;
18911898
jchar *lparg1 = NULL;
18921899
if (arg1) if ((lparg1 = env->GetCharArrayElements(arg1, NULL)) == NULL) goto fail;
1900+
if (start < 0 || count < 0) goto fail;
1901+
if (count > INT_MAX - start) goto fail;
18931902
if (start + count > env->GetArrayLength(arg1)) goto fail;
18941903

18951904
const WCHAR * text = (const WCHAR *)(lparg1 + start);

‎modules/javafx.graphics/src/main/native-font/fontpath.c

+116-33
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@
3333
#include <jni.h>
3434
#include <com_sun_javafx_font_PrismFontFactory.h>
3535

36-
#define BSIZE (max(512, MAX_PATH+1))
37-
3836
/* Typically all local references held by a JNI function are automatically
3937
* released by JVM when the function returns. However, there is a limit to the
4038
* number of local references that can remain active. If the local references
@@ -64,56 +62,141 @@ JNIEXPORT jint JNICALL JNI_OnLoad_javafx_font(JavaVM *vm, void *reserved) {
6462
}
6563
#endif // STATIC_BUILD
6664

67-
JNIEXPORT jbyteArray JNICALL
65+
JNIEXPORT jstring JNICALL
6866
Java_com_sun_javafx_font_PrismFontFactory_getFontPath(JNIEnv *env, jobject thiz)
6967
{
70-
char windir[BSIZE];
71-
char sysdir[BSIZE];
72-
char fontpath[BSIZE*2];
73-
char *end;
74-
jbyteArray byteArrObj;
75-
int pathLen;
76-
unsigned char *data;
68+
const wchar_t* const FONTS_DIR = L"\\Fonts";
69+
const UINT FONTS_DIR_STRLEN = (UINT)wcslen(FONTS_DIR);
70+
errno_t err = 0;
71+
wchar_t* windir = NULL;
72+
UINT windirBufSize = 0; // total buffer size in wchar_t elements (including NULL terminator)
73+
UINT windirFilledLen = 0; // amount of wchar_t elements filled (excluding NULL terminator)
74+
wchar_t* sysdir = NULL;
75+
UINT sysdirBufSize = 0;
76+
UINT sysdirFilledLen = 0;
77+
wchar_t* fontpath = NULL;
78+
UINT fontpathBufSize = 0;
79+
UINT fontpathFilledLen = 0;
80+
wchar_t *end = NULL;
81+
jsize pathLen = 0;
82+
jstring stringObj = NULL;
83+
84+
/* Preallocate dummy 1-char buffers in case WinAPI wants to write something despite count being 0.
85+
*
86+
* Windows API doesn't explicitly say that calling GetSystem/GetWindowsDirectory(NULL, 0)
87+
* will NOT attempt writing to NULL, so we want to provide something to prevent access
88+
* violation if they do
89+
*/
90+
sysdir = calloc(1, sizeof(wchar_t));
91+
windir = calloc(1, sizeof(wchar_t));
92+
if (!sysdir || !windir) goto finish;
7793

7894
/* Locate fonts directories relative to the Windows System directory.
7995
* If Windows System location is different than the user's window
8096
* directory location, as in a shared Windows installation,
8197
* return both locations as potential font directories
8298
*/
83-
GetSystemDirectory(sysdir, BSIZE);
84-
end = strrchr(sysdir,'\\');
85-
if (end && (stricmp(end,"\\System") || stricmp(end,"\\System32"))) {
86-
*end = 0;
87-
strcat(sysdir, "\\Fonts");
99+
UINT ret = GetSystemDirectoryW(sysdir, 0);
100+
if (ret == 0) {
101+
goto finish;
102+
} else {
103+
/* if buffer is too small, GetSystemDirectory will return the length in wchar_t-s
104+
* that's needed to allocate the buffer, including terminating null character.
105+
* `*Len` variables keep amount of elements without the NULL-terminator, so appropriate
106+
* corrections have to be applied here.
107+
*/
108+
free(sysdir);
109+
sysdirBufSize = ret + FONTS_DIR_STRLEN;
110+
sysdir = calloc(sysdirBufSize, sizeof(wchar_t));
111+
if (!sysdir) goto finish;
112+
ret = GetSystemDirectoryW(sysdir, sysdirBufSize - FONTS_DIR_STRLEN);
113+
if (ret == 0 || ret >= (sysdirBufSize - FONTS_DIR_STRLEN)) {
114+
goto finish;
115+
}
116+
// write was successful so now ret contains only characters written (without NULL-terminator)
117+
sysdirFilledLen = ret;
118+
}
119+
120+
/* Figure out fonts location based on acquired System directory - commonly it is one level up
121+
* from sysdir and then in "Fonts" dir
122+
*/
123+
end = wcsrchr(sysdir, '\\');
124+
if (end) {
125+
const wchar_t* const SYSTEM_DIR = L"\\System";
126+
const wchar_t* const SYSTEM32_DIR = L"\\System32";
127+
128+
UINT sysdirToEnd = (UINT)(end - sysdir);
129+
UINT endLen = sysdirFilledLen - sysdirToEnd;
130+
131+
// If the last directory in sysdir is "System" or "System32", strip that and replace it with "\Fonts"
132+
if ((_wcsnicmp(end, SYSTEM_DIR, endLen) == 0) || (_wcsnicmp(end, SYSTEM32_DIR, endLen) == 0)) {
133+
*end = 0;
134+
// no length re-check here, both \System and \System32 are longer than \Fonts string
135+
sysdirFilledLen -= endLen;
136+
err = wcsncat_s(sysdir, sysdirBufSize, FONTS_DIR, FONTS_DIR_STRLEN);
137+
if (err != 0) goto finish;
138+
sysdirFilledLen += FONTS_DIR_STRLEN;
139+
}
88140
}
89141

90-
GetWindowsDirectory(windir, BSIZE);
91-
if (strlen(windir) > BSIZE-7) {
92-
*windir = 0;
142+
// Acquire Windows' directory - follows same assumptions as sysdir above
143+
ret = GetWindowsDirectoryW(windir, 0);
144+
if (ret == 0) {
145+
goto finish;
93146
} else {
94-
strcat(windir, "\\Fonts");
147+
free(windir);
148+
windirBufSize = ret + FONTS_DIR_STRLEN;
149+
windir = calloc(windirBufSize, sizeof(wchar_t));
150+
if (!windir) goto finish;
151+
ret = GetWindowsDirectoryW(windir, windirBufSize - FONTS_DIR_STRLEN);
152+
if (ret == 0 || ret >= (windirBufSize - FONTS_DIR_STRLEN)) {
153+
goto finish;
154+
}
155+
windirFilledLen = ret;
95156
}
96157

97-
strcpy(fontpath,sysdir);
98-
if (stricmp(sysdir,windir)) {
99-
strcat(fontpath,";");
100-
strcat(fontpath,windir);
158+
// "Fonts" directory should be placed right inside Windows directory, so just append it to the path
159+
err = wcsncat_s(windir, windirBufSize, FONTS_DIR, FONTS_DIR_STRLEN);
160+
if (err != 0) goto finish;
161+
windirFilledLen += FONTS_DIR_STRLEN;
162+
163+
// Copy sysdir to final string that we'll return to JVM
164+
fontpathBufSize = windirFilledLen + sysdirFilledLen + 2; // add semicolon and zero-terminator
165+
fontpath = calloc(fontpathBufSize, sizeof(wchar_t));
166+
if (!fontpath) goto finish;
167+
err = wcsncpy_s(fontpath, fontpathBufSize, sysdir, sysdirFilledLen);
168+
if (err != 0) goto finish;
169+
fontpathFilledLen = sysdirFilledLen;
170+
171+
/* JFX expects either one path, or two separated by a semicolon.
172+
* If sysdir and windir are different, form a complete path "list" by
173+
* joining them in "<sysdir>;<windir>" pattern. JVM side will unpack it.
174+
*/
175+
if (_wcsnicmp(sysdir, windir, min(sysdirFilledLen, windirFilledLen))) {
176+
err = wcsncat_s(fontpath, fontpathBufSize, L";", 1);
177+
if (err != 0) goto finish;
178+
err = wcsncat_s(fontpath, fontpathBufSize, windir, windirFilledLen);
179+
if (err != 0) goto finish;
180+
fontpathFilledLen += windirFilledLen + 1;
101181
}
102182

103-
pathLen = strlen(fontpath);
183+
pathLen = (jsize)wcsnlen_s(fontpath, fontpathBufSize);
184+
185+
// Lastly, return what we just created to JVM as a String
186+
stringObj = (*env)->NewString(env, fontpath, fontpathFilledLen);
104187

105-
byteArrObj = (*env)->NewByteArray(env, pathLen);
106-
if (byteArrObj == NULL) {
107-
return (jbyteArray)NULL;
188+
finish:
189+
if (sysdir != NULL) {
190+
free(sysdir);
191+
}
192+
if (windir != NULL) {
193+
free(windir);
108194
}
109-
data = (*env)->GetByteArrayElements(env, byteArrObj, NULL);
110-
if (data == NULL) {
111-
return byteArrObj;
195+
if (fontpath != NULL) {
196+
free(fontpath);
112197
}
113-
memcpy(data, fontpath, pathLen);
114-
(*env)->ReleaseByteArrayElements(env, byteArrObj, (jbyte*) data, (jint)0);
115198

116-
return byteArrObj;
199+
return stringObj;
117200
}
118201

119202
/* The code below is used to obtain information from the windows font APIS

‎modules/javafx.graphics/src/main/native-font/freetype.c

+51-11
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,19 @@
3131
#include <dlfcn.h>
3232
#include <ft2build.h>
3333
#include <stdint.h>
34+
#include <errno.h>
3435
#include FT_FREETYPE_H
3536
#include FT_OUTLINE_H
3637
#include FT_LCD_FILTER_H
3738

3839
#define OS_NATIVE(func) Java_com_sun_javafx_font_freetype_OSFreetype_##func
3940

41+
#define SAFE_FREE(PTR) \
42+
if ((PTR) != NULL) { \
43+
free(PTR); \
44+
(PTR) = NULL; \
45+
}
46+
4047
extern jboolean checkAndClearException(JNIEnv *env);
4148
#ifdef STATIC_BUILD
4249
JNIEXPORT jint JNICALL
@@ -485,35 +492,54 @@ JNIEXPORT jint JNICALL OS_NATIVE(FT_1Set_1Char_1Size)
485492
/***********************************************/
486493

487494
#define F26DOT6TOFLOAT(n) (float)n/64.0;
488-
static const int DEFAULT_LEN_TYPES = 10;
489-
static const int DEFAULT_LEN_COORDS = 50;
495+
static const size_t DEFAULT_LEN_TYPES = 10;
496+
static const size_t DEFAULT_LEN_COORDS = 50;
490497
typedef struct _PathData {
491498
jbyte* pointTypes;
492-
int numTypes;
493-
int lenTypes;
499+
size_t numTypes;
500+
size_t lenTypes;
494501
jfloat* pointCoords;
495-
int numCoords;
496-
int lenCoords;
502+
size_t numCoords;
503+
size_t lenCoords;
497504
} PathData;
498505

499506
static PathData* checkSize(void* user, int coordCount)
500507
{
501508
PathData* info = (PathData *)user;
509+
502510
if (info->numTypes == info->lenTypes) {
511+
if (info->lenTypes > SIZE_MAX - DEFAULT_LEN_TYPES) goto fail;
503512
info->lenTypes += DEFAULT_LEN_TYPES;
504-
info->pointTypes = (jbyte*)realloc(info->pointTypes, info->lenTypes * sizeof(jbyte));
513+
514+
jbyte* newPointTypes = (jbyte*)realloc(info->pointTypes, info->lenTypes * sizeof(jbyte));
515+
if (newPointTypes == NULL) goto fail;
516+
info->pointTypes = newPointTypes;
505517
}
518+
506519
if (info->numCoords + (coordCount * 2) > info->lenCoords) {
520+
if (info->lenCoords > SIZE_MAX - DEFAULT_LEN_COORDS) goto fail;
507521
info->lenCoords += DEFAULT_LEN_COORDS;
508-
info->pointCoords = (jfloat*)realloc(info->pointCoords, info->lenCoords * sizeof(jfloat));
522+
523+
jbyte* newPointCoords = (jfloat*)realloc(info->pointCoords, info->lenCoords * sizeof(jfloat));
524+
if (newPointCoords == NULL) goto fail;
525+
info->pointCoords = newPointCoords;
509526
}
527+
510528
return info;
529+
530+
fail:
531+
SAFE_FREE(info->pointTypes);
532+
SAFE_FREE(info->pointCoords);
533+
return NULL;
511534
}
512535

513536
static int JFX_Outline_MoveToFunc(const FT_Vector* to,
514537
void* user)
515538
{
516539
PathData *info = checkSize(user, 1);
540+
if (info == NULL) {
541+
return FT_Err_Array_Too_Large;
542+
}
517543
info->pointTypes[info->numTypes++] = 0;
518544
info->pointCoords[info->numCoords++] = F26DOT6TOFLOAT(to->x);
519545
info->pointCoords[info->numCoords++] = -F26DOT6TOFLOAT(to->y);
@@ -524,6 +550,9 @@ static int JFX_Outline_LineToFunc(const FT_Vector* to,
524550
void* user)
525551
{
526552
PathData *info = checkSize(user, 1);
553+
if (info == NULL) {
554+
return FT_Err_Array_Too_Large;
555+
}
527556
info->pointTypes[info->numTypes++] = 1;
528557
info->pointCoords[info->numCoords++] = F26DOT6TOFLOAT(to->x);
529558
info->pointCoords[info->numCoords++] = -F26DOT6TOFLOAT(to->y);
@@ -535,6 +564,9 @@ static int JFX_Outline_ConicToFunc(const FT_Vector* control,
535564
void* user )
536565
{
537566
PathData *info = checkSize(user, 2);
567+
if (info == NULL) {
568+
return FT_Err_Array_Too_Large;
569+
}
538570
info->pointTypes[info->numTypes++] = 2;
539571
info->pointCoords[info->numCoords++] = F26DOT6TOFLOAT(control->x);
540572
info->pointCoords[info->numCoords++] = -F26DOT6TOFLOAT(control->y);
@@ -549,6 +581,9 @@ static int JFX_Outline_CubicToFunc(const FT_Vector* control1,
549581
void* user)
550582
{
551583
PathData *info = checkSize(user, 3);
584+
if (info == NULL) {
585+
return FT_Err_Array_Too_Large;
586+
}
552587
info->pointTypes[info->numTypes++] = 3;
553588
info->pointCoords[info->numCoords++] = F26DOT6TOFLOAT(control1->x);
554589
info->pointCoords[info->numCoords++] = -F26DOT6TOFLOAT(control1->y);
@@ -583,12 +618,16 @@ JNIEXPORT jobject JNICALL OS_NATIVE(FT_1Outline_1Decompose)
583618
data.pointTypes = (jbyte*)malloc(sizeof(jbyte) * DEFAULT_LEN_TYPES);
584619
data.numTypes = 0;
585620
data.lenTypes = DEFAULT_LEN_TYPES;
621+
if (data.pointTypes == NULL) goto fail;
622+
586623
data.pointCoords = (jfloat*)malloc(sizeof(jfloat) * DEFAULT_LEN_COORDS);
587624
data.numCoords = 0;
588625
data.lenCoords = DEFAULT_LEN_COORDS;
626+
if (data.pointCoords == NULL) goto fail;
589627

590628
/* Decompose outline */
591-
FT_Outline_Decompose(outline, &JFX_Outline_Funcs, &data);
629+
FT_Error ftError = FT_Outline_Decompose(outline, &JFX_Outline_Funcs, &data);
630+
if (ftError != FT_Err_Ok) goto fail;
592631

593632
static jclass path2DClass = NULL;
594633
static jmethodID path2DCtr = NULL;
@@ -628,9 +667,10 @@ JNIEXPORT jobject JNICALL OS_NATIVE(FT_1Outline_1Decompose)
628667
goto fail;
629668
}
630669
}
670+
631671
fail:
632-
free(data.pointTypes);
633-
free(data.pointCoords);
672+
SAFE_FREE(data.pointTypes);
673+
SAFE_FREE(data.pointCoords);
634674
return path2D;
635675
}
636676

‎modules/javafx.graphics/src/main/native-glass/win/Utils.h

+4
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,10 @@ class JBufferArray {
414414
if (!arr) {
415415
data = (T*)env->GetDirectBufferAddress(buf);
416416
} else {
417+
if (offs < 0 || offs > env->GetArrayLength(arr)) {
418+
fprintf(stderr, "Failed to attach bytes array\n");
419+
return;
420+
}
417421
array.Attach(env, arr);
418422
offset = offs;
419423
}

0 commit comments

Comments
 (0)
This repository has been archived.