# HG changeset patch # User mbalao # Date 1550783959 10800 # Thu Feb 21 18:19:19 2019 -0300 # Node ID b562aaf7be904c2c613285521e22d2ad7862b317 # Parent 72709e703abdeac0b18a398edf690ec4cf0639e4 8218854: FontMetrics.getMaxAdvance may be less than the maximum FontMetrics.charWidth Summary: Consider algorithmic bold in FontMetrics.getMaxAdvance value and update obliqueness. Reviewed-by: prr diff --git a/src/java.desktop/share/native/libfontmanager/freetypeScaler.c b/src/java.desktop/share/native/libfontmanager/freetypeScaler.c --- a/src/java.desktop/share/native/libfontmanager/freetypeScaler.c +++ b/src/java.desktop/share/native/libfontmanager/freetypeScaler.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -405,10 +405,18 @@ return errCode; } -/* ftsynth.c uses (0x10000, 0x06000, 0x0, 0x10000) matrix to get oblique - outline. Therefore x coordinate will change by 0x06000*y. - Note that y coordinate does not change. */ -#define OBLIQUE_MODIFIER(y) (context->doItalize ? ((y)*6/16) : 0) +/* ftsynth.c uses (0x10000, 0x0366A, 0x0, 0x10000) matrix to get oblique + outline. Therefore x coordinate will change by 0x0366A*y. + Note that y coordinate does not change. These values are based on + libfreetype version 2.9.1. */ +#define OBLIQUE_MODIFIER(y) (context->doItalize ? ((y)*0x366A/0x10000) : 0) + +/* FT_GlyphSlot_Embolden (ftsynth.c) uses FT_MulFix(units_per_EM, y_scale) / 24 + * strength value when glyph format is FT_GLYPH_FORMAT_OUTLINE. This value has + * been taken from libfreetype version 2.6 and remain valid at least up to + * 2.9.1. */ +#define BOLD_MODIFIER(units_per_EM, y_scale) \ + (context->doBold ? FT_MulFix(units_per_EM, y_scale) / 24 : 0) /* * Class: sun_font_FreetypeFontScaler @@ -495,7 +503,9 @@ /* max advance */ mx = (jfloat) FT26Dot6ToFloat( scalerInfo->face->size->metrics.max_advance + - OBLIQUE_MODIFIER(scalerInfo->face->size->metrics.height)); + OBLIQUE_MODIFIER(scalerInfo->face->size->metrics.height) + + BOLD_MODIFIER(scalerInfo->face->units_per_EM, + scalerInfo->face->size->metrics.y_scale)); my = 0; metrics = (*env)->NewObject(env, diff --git a/test/jdk/java/awt/font/MaxAdvanceIsMax/MaxAdvanceIsMax.java b/test/jdk/java/awt/font/MaxAdvanceIsMax/MaxAdvanceIsMax.java new file mode 100644 --- /dev/null +++ b/test/jdk/java/awt/font/MaxAdvanceIsMax/MaxAdvanceIsMax.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. + * 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 8218854 + * @requires jdk.version.major >= 8 + * @run main/othervm MaxAdvanceIsMax + */ + +import java.awt.*; +import java.awt.image.BufferedImage; + +public class MaxAdvanceIsMax { + + private static boolean debug = true; + + private static Font[] fonts; + + private static final class AntialiasHint { + private Object aaHint; + private String asString = ""; + + AntialiasHint(Object aaHint) { + if (aaHint.equals( + RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)) { + asString += "FT_LOAD_TARGET_MONO"; + } else if (aaHint.equals( + RenderingHints.VALUE_TEXT_ANTIALIAS_ON)) { + asString += "FT_LOAD_TARGET_NORMAL"; + } else if (aaHint.equals( + RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB)) { + asString += "FT_LOAD_TARGET_LCD"; + } else if (aaHint.equals( + RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB)) { + asString += "FT_LOAD_TARGET_LCD_V"; + } + this.aaHint = aaHint; + } + + public Object getHint() { + return aaHint; + } + + public String toString() { + return asString; + } + } + + private static final AntialiasHint[] antialiasHints = { + new AntialiasHint(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF), + new AntialiasHint(RenderingHints.VALUE_TEXT_ANTIALIAS_ON), + new AntialiasHint(RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB), + new AntialiasHint(RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB) + }; + + private static final class StyleAndSize { + int style; + float size; + public StyleAndSize(int style, float size) { + this.style = style; + this.size = size; + } + }; + + private static final StyleAndSize[] stylesAndSizes = new StyleAndSize[] { + new StyleAndSize(Font.BOLD | Font.ITALIC, 1) + }; + + private static final void loadFonts() { + try { + GraphicsEnvironment e = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + fonts = e.getAllFonts(); + } catch (Exception e) {} + } + + public static void main(String[] args) throws Exception { + loadFonts(); + BufferedImage bi = new BufferedImage(500, 500, + BufferedImage.TYPE_INT_RGB); + for (AntialiasHint antialiasHint : antialiasHints) { + for (Font f : fonts) { + for (StyleAndSize styleAndSize : stylesAndSizes) { + f = f.deriveFont(styleAndSize.style, styleAndSize.size); + Graphics2D g2d = bi.createGraphics(); + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + antialiasHint.getHint()); + FontMetrics fm = g2d.getFontMetrics(f); + int[] width; + int maxWidth = -1; + int maxAdvance = fm.getMaxAdvance(); + if (debug) { + System.out.println("Testing " + f + " in " + + antialiasHint); + System.out.println("getMaxAdvance: " + maxAdvance); + } + if (maxAdvance != -1) { + String failureMessage = null; + width = fm.getWidths(); + for (int j = 0; j < width.length; j++) { + if (width[j] > maxWidth) { + maxWidth = width[j]; + } + if (width[j] > maxAdvance) { + failureMessage = "FAILED: getMaxAdvance is " + + "not max for font: " + + f.toString() + + " getMaxAdvance(): " + + maxAdvance + + " getWidths()[" + j + "]: " + + width[j]; + throw new Exception(failureMessage); + } + } + } + if (debug) { + System.out.println("Max char width: " + maxWidth); + System.out.println("PASSED"); + System.out.println("........................."); + } + } + } + } + System.out.println("TEST PASS - OK"); + } +}