JBR-2617 Text with opacity renders black

Implemented alpha blending in grayscale text rendering (UX-1320)
Corrected bright text thickness (smooth on), bright and dark text thickness (smooth off)
Added JVM properties for fine tuning

(cherry picked from commit c30306f779)
(cherry picked from commit c95adeb8f2)
(cherry picked from commit 269c9580fb)
(cherry picked from commit 55c7be5fe9)
(cherry picked from commit e28ff71e97)
This commit is contained in:
Alexey Ushakov
2020-08-04 19:09:02 +03:00
committed by jbrbot
parent c1f963341c
commit 81439529a4
3 changed files with 154 additions and 65 deletions

View File

@@ -1073,4 +1073,96 @@ JNIEXPORT jstring JNICALL Java_sun_java2d_opengl_OGLContext_getOGLIdString
return ret;
}
static int JVM_GetIntProperty(JNIEnv *env, const char* name, int defaultValue) {
static jclass systemCls = NULL;
if (systemCls == NULL) {
systemCls = (*env)->FindClass(env, "java/lang/System");
if (systemCls == NULL) {
return defaultValue;
}
}
static jmethodID mid = NULL;
if (mid == NULL) {
mid = (*env)->GetStaticMethodID(env, systemCls, "getProperty",
"(Ljava/lang/String;)Ljava/lang/String;");
if (mid == NULL) {
return defaultValue;
}
}
jstring jName = (*env)->NewStringUTF(env, name);
if (jName == NULL) {
return defaultValue;
}
int result = defaultValue;
jstring jvalue = (*env)->CallStaticObjectMethod(env, systemCls, mid, jName);
if (jvalue != NULL) {
const char *utf8string = (*env)->GetStringUTFChars(env, jvalue, NULL);
if (utf8string != NULL) {
const int parsedVal = atoi(utf8string);
if (parsedVal > 0) {
result = parsedVal;
}
}
(*env)->ReleaseStringUTFChars(env, jvalue, utf8string);
}
(*env)->DeleteLocalRef(env, jName);
return result;
}
void OGLContext_InitGrayRenderHints(JNIEnv *env, OGLContext *oglc) {
static GrayRenderHints *grayRenderHints = NULL;
static GrayRenderHints defaultRenderHints[] = {
// hints for "use font smoothing" option
// disabled
{1.666f, 0.333f, 1.0f, 1.25f},
// enabled
{1.666f, 0.333f, 0.454f, 1.4f}
};
if (grayRenderHints == NULL) {
// read from VM-properties
int val = JVM_GetIntProperty(env, "awt.font.nosm.light_gamma", 0);
if (val > 0) {
defaultRenderHints[0].light_gamma = val / 1000.0;
}
val = JVM_GetIntProperty(env, "awt.font.nosm.dark_gamma", 0);
if (val > 0) {
defaultRenderHints[0].dark_gamma = val / 1000.0;
}
val = JVM_GetIntProperty(env, "awt.font.nosm.light_exp", 0);
if (val > 0) {
defaultRenderHints[0].light_exp = val / 1000.0;
}
val = JVM_GetIntProperty(env, "awt.font.nosm.dark_exp", 0);
if (val > 0) {
defaultRenderHints[0].dark_exp = val / 1000.0;
}
val = JVM_GetIntProperty(env, "awt.font.sm.light_gamma", 0);
if (val > 0) {
defaultRenderHints[1].light_gamma = val / 1000.0;
}
val = JVM_GetIntProperty(env, "awt.font.sm.dark_gamma", 0);
if (val > 0) {
defaultRenderHints[1].dark_gamma = val / 1000.0;
}
val = JVM_GetIntProperty(env, "awt.font.sm.light_exp", 0);
if (val > 0) {
defaultRenderHints[1].light_exp = val / 1000.0;
}
val = JVM_GetIntProperty(env, "awt.font.sm.dark_exp", 0);
if (val > 0) {
defaultRenderHints[1].dark_exp = val / 1000.0;
}
grayRenderHints = defaultRenderHints;
}
oglc->grayRenderHints = grayRenderHints;
}
#endif /* !HEADLESS */

View File

@@ -52,6 +52,16 @@ typedef struct {
GLenum dst;
} OGLBlendRule;
/**
* Use this hints if gray gamma shader is enabled
*/
typedef struct {
float light_gamma; // brightness of light text
float dark_gamma; // brightness of dark text
float light_exp; // thickness of light text
float dark_exp; // thickness of dark text
} GrayRenderHints;
/**
* The OGLContext structure contains cached state relevant to the native
* OpenGL context stored within the native ctxInfo field. Each Java-level
@@ -85,6 +95,7 @@ typedef struct {
GLuint blitTextureID;
GLint textureFunction;
jboolean vertexCacheEnabled;
GrayRenderHints *grayRenderHints;
} OGLContext;
/**
@@ -221,5 +232,6 @@ void OGLContext_GetExtensionInfo(JNIEnv *env, jint *caps);
jboolean OGLContext_IsVersionSupported(const unsigned char *versionstr);
GLhandleARB OGLContext_CreateFragmentProgram(const char *fragmentShaderSource);
void OGLContext_InitGrayRenderHints(JNIEnv *env, OGLContext *oglc);
#endif /* OGLContext_h_Included */

View File

@@ -98,17 +98,6 @@ static GLhandleARB lcdTextProgram = 0;
*/
static GLhandleARB grayTextProgram = 0;
/**
* Use this gamma if gray gamma shader is enabled
* GRAY_LIGHT_GAMMA for light text on dark background
* GRAY_DARK_GAMMA for dark text on light backfround
* GRAY_GAMMA_THRESHOLD a threshold to switch gamma
* depending on text brightness
*/
#define GRAY_LIGHT_GAMMA 220
#define GRAY_DARK_GAMMA 140
#define GRAY_GAMMA_THRESHOLD 0.5f
/**
* This value tracks the previous LCD contrast setting, so if the contrast
* value hasn't changed since the last time the gamma uniforms were
@@ -323,29 +312,32 @@ static const char *lcdTextShaderSource =
"}";
static const char *grayGammaTextShaderSource =
"uniform vec3 src_adj;"
"uniform vec4 src_adj;"
"uniform sampler2D glyph_tex;"
"uniform float inv_light_gamma;"
"uniform float inv_dark_gamma;"
"uniform float threshold;"
"uniform float inv_light_exp;"
"uniform float inv_dark_exp;"
"void main(void)"
"{"
" float glyph_clr = float(texture2D(glyph_tex, gl_TexCoord[0].st));"
" if (dot(src_adj, vec3(1.0/3.0, 1.0/3.0, 1.0/3.0)) > threshold) {"
" glyph_clr = pow(glyph_clr, inv_light_gamma);"
" } else { "
" glyph_clr = pow(glyph_clr, inv_dark_gamma);"
" }"
" gl_FragColor = vec4(src_adj, glyph_clr);"
"}";
"float a = src_adj.a;"
"vec3 col = src_adj.rgb;"
static const char *grayTextShaderSource =
"uniform vec3 src_adj;"
"uniform sampler2D glyph_tex;"
"void main(void)"
"{"
" float glyph_clr = float(texture2D(glyph_tex, gl_TexCoord[0].st));"
" gl_FragColor = vec4(src_adj, glyph_clr);"
// calculate brightness of the fragment
"float b = dot(col, vec3(1.0/3.0, 1.0/3.0, 1.0/3.0))*a;"
// adjust fragment coverage
"float frag_cov = float(texture2D(glyph_tex, gl_TexCoord[0].st));"
"float exp = mix(inv_dark_exp, inv_light_exp, b);"
"frag_cov = pow(frag_cov, exp);"
// adjust fragment color and alpha for alpha < 1.0
"if (a < 1.0) {"
"float g = mix(inv_dark_gamma, inv_light_gamma,b);"
"col = pow(col, vec3(g));"
"a = pow(a, exp);"
"}"
"gl_FragColor = vec4(col, a*frag_cov);"
"}";
/**
@@ -382,21 +374,21 @@ OGLTR_CreateLCDTextProgram()
return lcdTextProgram;
}
/**
* Compiles and links the LCD text shader program. If successful, this
* function returns a handle to the newly created shader program; otherwise
* returns 0.
*/
static GLhandleARB
OGLTR_CreateGrayTextProgram(jint lightContrast, jint darkContrast, jfloat threshold)
OGLTR_CreateGrayTextProgram(OGLContext *oglc, jboolean useFontSmoothing)
{
GLhandleARB grayTextProgram;
GLint loc;
J2dTraceLn(J2D_TRACE_INFO, "OGLTR_CreateGrayTextProgram");
grayTextProgram = OGLContext_CreateFragmentProgram(
lightContrast > 0 ? grayGammaTextShaderSource : grayTextShaderSource);
grayTextProgram = OGLContext_CreateFragmentProgram(grayGammaTextShaderSource);
if (grayTextProgram == 0) {
J2dRlsTraceLn(J2D_TRACE_ERROR,
@@ -407,20 +399,21 @@ OGLTR_CreateGrayTextProgram(jint lightContrast, jint darkContrast, jfloat thresh
// "use" the program object temporarily so that we can set the uniforms
j2d_glUseProgramObjectARB(grayTextProgram);
if (lightContrast > 0) {
double ilg = 1.0 / (((double) lightContrast) / 100.0);
double idg = 1.0 / (((double) darkContrast) / 100.0);
J2dTraceLn1(J2D_TRACE_INFO,
"OGLTR_CreateGrayTextProgram: contrast=%d", lightContrast);
GrayRenderHints *hints = &(oglc->grayRenderHints[useFontSmoothing]);
J2dTraceLn5(J2D_TRACE_INFO,
"OGLTR_CreateGrayTextProgram: useFontSmoothing=%d "
"light_gamma=%f dark_gamma=%f light_exp=%f dark_exp=%f",
useFontSmoothing, hints->light_gamma, hints->dark_gamma,
hints->light_exp, hints->dark_exp);
loc = j2d_glGetUniformLocationARB(grayTextProgram, "inv_light_gamma");
j2d_glUniform1fARB(loc, ilg);
loc = j2d_glGetUniformLocationARB(grayTextProgram, "inv_dark_gamma");
j2d_glUniform1fARB(loc, idg);
loc = j2d_glGetUniformLocationARB(grayTextProgram, "threshold");
j2d_glUniform1fARB(loc, threshold);
}
loc = j2d_glGetUniformLocationARB(grayTextProgram, "inv_light_gamma");
j2d_glUniform1fARB(loc, hints->light_gamma);
loc = j2d_glGetUniformLocationARB(grayTextProgram, "inv_dark_gamma");
j2d_glUniform1fARB(loc, hints->dark_gamma);
loc = j2d_glGetUniformLocationARB(grayTextProgram, "inv_light_exp");
j2d_glUniform1fARB(loc, hints->light_exp);
loc = j2d_glGetUniformLocationARB(grayTextProgram, "inv_dark_exp");
j2d_glUniform1fARB(loc, hints->dark_exp);
// "unuse" the program object; it will be re-bound later as needed
j2d_glUseProgramObjectARB(0);
@@ -504,7 +497,7 @@ OGLTR_UpdateLCDTextColor(jint contrast)
static jboolean
OGLTR_UpdateGrayTextColor()
{
GLfloat radj, gadj, badj;
GLfloat radj, gadj, badj, aadj;
GLfloat clr[4];
GLint loc;
@@ -523,10 +516,11 @@ OGLTR_UpdateGrayTextColor()
radj = (GLfloat)clr[0];
gadj = (GLfloat)clr[1];
badj = (GLfloat)clr[2];
aadj = (GLfloat)clr[3];
// update the "src_adj" parameter of the shader program with this value
loc = j2d_glGetUniformLocationARB(grayTextProgram, "src_adj");
j2d_glUniform3fARB(loc, radj, gadj, badj);
j2d_glUniform4fARB(loc, radj, gadj, badj, aadj);
return JNI_TRUE;
}
@@ -596,9 +590,7 @@ OGLTR_EnableLCDGlyphModeState(GLuint glyphTextureID,
* Enables the GrayScale text shader and updates any related states
*/
static jboolean
OGLTR_EnableGrayGlyphModeState(GLuint glyphTextureID,
jint lightContrast, jint darkContrast,
jfloat threshold)
OGLTR_EnableGrayGlyphModeState(OGLContext *oglc, GLuint glyphTextureID, jboolean useFontSmoothing)
{
// bind the texture containing glyph data to texture unit 0
j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
@@ -612,8 +604,7 @@ OGLTR_EnableGrayGlyphModeState(GLuint glyphTextureID,
// create the Gray text shader, if necessary
if (grayTextProgram == 0) {
grayTextProgram = OGLTR_CreateGrayTextProgram(
lightContrast, darkContrast, threshold);
grayTextProgram = OGLTR_CreateGrayTextProgram(oglc, useFontSmoothing);
if (grayTextProgram == 0) {
return JNI_FALSE;
}
@@ -710,8 +701,7 @@ OGLTR_DisableGlyphModeState()
}
static jboolean
OGLTR_DrawGrayscaleGlyphViaCache(OGLContext *oglc, GlyphInfo *ginfo,
jint x, jint y, jint lightContrast, jint darkContrast, jfloat threshold)
OGLTR_DrawGrayscaleGlyphViaCache(OGLContext *oglc, GlyphInfo *ginfo, jint x, jint y, jboolean useFontSmoothing)
{
CacheCellInfo *cell;
jfloat x1, y1, x2, y2;
@@ -726,8 +716,7 @@ OGLTR_DrawGrayscaleGlyphViaCache(OGLContext *oglc, GlyphInfo *ginfo,
}
}
if (!OGLTR_EnableGrayGlyphModeState(
glyphCacheAA->cacheID, lightContrast, darkContrast, threshold))
if (!OGLTR_EnableGrayGlyphModeState(oglc, glyphCacheAA->cacheID, useFontSmoothing))
{
return JNI_FALSE;
}
@@ -1211,9 +1200,7 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
{
int glyphCounter;
GLuint dstTextureID = 0;
jint lighGamma = 0;
jint darkGamma = 0;
jfloat threshold = 0;
jboolean fontSmoothing = JNI_FALSE;
J2dTraceLn(J2D_TRACE_INFO, "OGLTR_DrawGlyphList");
@@ -1250,11 +1237,7 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
}
subPixPos = lcdSubPixelPosSupported ? subPixPos : 0;
if (useFontSmoothing) {
lighGamma = GRAY_LIGHT_GAMMA;
darkGamma = GRAY_DARK_GAMMA;
threshold = GRAY_GAMMA_THRESHOLD;
}
fontSmoothing = useFontSmoothing;
#endif
for (glyphCounter = 0; glyphCounter < totalGlyphs; glyphCounter++) {
@@ -1291,12 +1274,14 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
}
if (ginfo->rowBytes == ginfo->width) {
if (oglc->grayRenderHints == NULL) {
OGLContext_InitGrayRenderHints(env, oglc);
}
// grayscale or monochrome glyph data
if (ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
{
ok = OGLTR_DrawGrayscaleGlyphViaCache(oglc, ginfo, x, y,
lighGamma, darkGamma, threshold);
ok = OGLTR_DrawGrayscaleGlyphViaCache(oglc, ginfo, x, y, fontSmoothing);
} else {
ok = OGLTR_DrawGrayscaleGlyphNoCache(oglc, ginfo, x, y);
}