--- a/src/java.desktop/share/native/libfontmanager/freetypeScaler.c Thu Oct 24 14:54:31 2019 -0700
+++ b/src/java.desktop/share/native/libfontmanager/freetypeScaler.c Mon Nov 04 10:01:55 2019 -0800
@@ -611,6 +611,12 @@
return metrics;
}
+static jlong
+ getGlyphImageNativeInternal(
+ JNIEnv *env, jobject scaler, jobject font2D,
+ jlong pScalerContext, jlong pScaler, jint glyphCode,
+ jboolean renderImage);
+
/*
* Class: sun_font_FreetypeFontScaler
* Method: getGlyphAdvanceNative
@@ -622,24 +628,23 @@
jlong pScalerContext, jlong pScaler, jint glyphCode) {
/* This method is rarely used because requests for metrics are usually
- coupled with request for bitmap and to large extend work can be reused
- (to find out metrics we need to hint glyph).
- So, we typically go through getGlyphImage code path.
-
- For initial freetype implementation we delegate
- all work to getGlyphImage but drop result image.
- This is waste of work related to scan conversion and conversion from
- freetype format to our format but for now this seems to be ok.
-
- NB: investigate performance benefits of refactoring code
- to avoid unnecesary work with bitmaps. */
+ * coupled with a request for the bitmap and to a large extent the
+ * work can be reused (to find out metrics we may need to hint the glyph).
+ * So, we typically go through the getGlyphImage code path.
+ * When we do get here, we need to pass a parameter which indicates
+ * that we don't need freetype to render the bitmap, and consequently
+ * don't need to allocate our own storage either.
+ * This is also important when enter here requesting metrics for sizes
+ * of text which a large size would be rejected for a bitmap but we
+ * still need the metrics.
+ */
GlyphInfo *info;
jfloat advance = 0.0f;
jlong image;
- image = Java_sun_font_FreetypeFontScaler_getGlyphImageNative(
- env, scaler, font2D, pScalerContext, pScaler, glyphCode);
+ image = getGlyphImageNativeInternal(
+ env, scaler, font2D, pScalerContext, pScaler, glyphCode, JNI_FALSE);
info = (GlyphInfo*) jlong_to_ptr(image);
if (info != NULL) {
@@ -660,17 +665,12 @@
JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext,
jlong pScaler, jint glyphCode, jobject metrics) {
- /* As initial implementation we delegate all work to getGlyphImage
- but drop result image. This is clearly waste of resorces.
-
- TODO: investigate performance benefits of refactoring code
- by avoiding bitmap generation and conversion from FT
- bitmap format. */
+ /* See the comments in getGlyphMetricsNative. They apply here too. */
GlyphInfo *info;
- jlong image = Java_sun_font_FreetypeFontScaler_getGlyphImageNative(
+ jlong image = getGlyphImageNativeInternal(
env, scaler, font2D,
- pScalerContext, pScaler, glyphCode);
+ pScalerContext, pScaler, glyphCode, JNI_FALSE);
info = (GlyphInfo*) jlong_to_ptr(image);
if (info != NULL) {
@@ -804,6 +804,17 @@
JNIEnv *env, jobject scaler, jobject font2D,
jlong pScalerContext, jlong pScaler, jint glyphCode) {
+ return getGlyphImageNativeInternal(
+ env, scaler, font2D,
+ pScalerContext, pScaler, glyphCode, JNI_TRUE);
+}
+
+static jlong
+ getGlyphImageNativeInternal(
+ JNIEnv *env, jobject scaler, jobject font2D,
+ jlong pScalerContext, jlong pScaler, jint glyphCode,
+ jboolean renderImage) {
+
int error, imageSize;
UInt16 width, height;
GlyphInfo *glyphInfo;
@@ -866,7 +877,7 @@
/* generate bitmap if it is not done yet
e.g. if algorithmic styling is performed and style was added to outline */
- if (ftglyph->format == FT_GLYPH_FORMAT_OUTLINE) {
+ if (renderImage && (ftglyph->format == FT_GLYPH_FORMAT_OUTLINE)) {
FT_BBox bbox;
FT_Outline_Get_CBox(&(ftglyph->outline), &bbox);
int w = (int)((bbox.xMax>>6)-(bbox.xMin>>6));
@@ -881,12 +892,17 @@
}
}
- width = (UInt16) ftglyph->bitmap.width;
- height = (UInt16) ftglyph->bitmap.rows;
- if (width > MAX_GLYPH_DIM || height > MAX_GLYPH_DIM) {
- glyphInfo = getNullGlyphImage();
- return ptr_to_jlong(glyphInfo);
- }
+ if (renderImage) {
+ width = (UInt16) ftglyph->bitmap.width;
+ height = (UInt16) ftglyph->bitmap.rows;
+ if (width > MAX_GLYPH_DIM || height > MAX_GLYPH_DIM) {
+ glyphInfo = getNullGlyphImage();
+ return ptr_to_jlong(glyphInfo);
+ }
+ } else {
+ width = 0;
+ height = 0;
+ }
imageSize = width*height;
@@ -900,13 +916,16 @@
glyphInfo->rowBytes = width;
glyphInfo->width = width;
glyphInfo->height = height;
- glyphInfo->topLeftX = (float) ftglyph->bitmap_left;
- glyphInfo->topLeftY = (float) -ftglyph->bitmap_top;
+
+ if (renderImage) {
+ glyphInfo->topLeftX = (float) ftglyph->bitmap_left;
+ glyphInfo->topLeftY = (float) -ftglyph->bitmap_top;
- if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) {
- glyphInfo->width = width/3;
- } else if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) {
- glyphInfo->height = glyphInfo->height/3;
+ if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) {
+ glyphInfo->width = width/3;
+ } else if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) {
+ glyphInfo->height = glyphInfo->height/3;
+ }
}
if (context->fmType == TEXT_FM_ON) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/awt/FontClass/MassiveMetricsTest.java Mon Nov 04 10:01:55 2019 -0800
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8233097
+ * @summary Test we get non-zero metrics with large sizes.
+ * @run main MassiveMetricsTest
+ */
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.image.BufferedImage;
+
+public class MassiveMetricsTest {
+
+ public static void main(String [] args) {
+
+ GraphicsEnvironment ge =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ Font[] fonts = ge.getAllFonts();
+ BufferedImage bi = new BufferedImage(1,1,1);
+ Graphics2D g2d = bi.createGraphics();
+ int[] sizes = { 80, 100, 120, 600, 1600, 2400, 3600, 7200, 12000 };
+ String s = "m";
+
+ for (Font f : fonts) {
+ Font sz12Font = f.deriveFont(Font.PLAIN, 12);
+ FontMetrics sz12 = g2d.getFontMetrics(sz12Font);
+ if (sz12.stringWidth(s) == 0) {
+ continue; // code point not supported or similar.
+ }
+ boolean fail = false;
+ for (int sz : sizes) {
+ Font font = f.deriveFont(Font.PLAIN, sz);
+ FontMetrics fm = g2d.getFontMetrics(font);
+ if (fm.stringWidth(s) == 0) {
+ fail = true;
+ System.err.println("zero for " + font);
+ }
+ }
+ if (fail) {
+ throw new RuntimeException("Zero stringwidth");
+ }
+ }
+ }
+}