# HG changeset patch # User prr # Date 1572890515 28800 # Node ID f5adbf1114240c2f93e1839ef02c004d8f258125 # Parent d2123a27cfe74085b4ce4d2b52de66734666305d 8233097: Fontmetrics for large Fonts has zero width Reviewed-by: jdv, serb diff -r d2123a27cfe7 -r f5adbf111424 src/java.desktop/share/native/libfontmanager/freetypeScaler.c --- 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) { diff -r d2123a27cfe7 -r f5adbf111424 test/jdk/java/awt/FontClass/MassiveMetricsTest.java --- /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"); + } + } + } +}