Skip to content

Commit acff32c

Browse files
committed
8328896: Fontmetrics for large Fonts has zero width
Backport-of: 25871af36b1397bdc3715ab0edc589f0483ea0b1
1 parent 445aba4 commit acff32c

File tree

5 files changed

+166
-2
lines changed

5 files changed

+166
-2
lines changed

src/java.desktop/macosx/classes/sun/font/CStrike.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ void getGlyphImageBounds(int glyphCode, Point2D.Float pt, Rectangle result) {
201201
getGlyphImageBounds(glyphCode, pt.x, pt.y, floatRect);
202202

203203
if (floatRect.width == 0 && floatRect.height == 0) {
204-
result.setRect(0, 0, -1, -1);
204+
result.setRect(0, 0, 0, 0);
205205
return;
206206
}
207207

src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1020,4 +1020,20 @@ @implementation CGGI_GlyphCanvas
10201020
CTFontGetAdvancesForGlyphs(font, kCTFontDefaultOrientation, glyphs, advances, count);
10211021
}
10221022
}
1023-
}
1023+
int MAX_SIZE = 1 << 30;
1024+
if (bboxes) {
1025+
for (int i = 0; i < count; i++) {
1026+
if (bboxes[i].origin.x > (double)MAX_SIZE) bboxes[i].origin.x = 0;
1027+
if (bboxes[i].origin.y > (double)MAX_SIZE) bboxes[i].origin.y = 0;
1028+
if (bboxes[i].size.width > (double)MAX_SIZE) bboxes[i].size.width = 0;
1029+
if (bboxes[i].size.height > (double)MAX_SIZE) bboxes[i].size.height = 0;
1030+
}
1031+
}
1032+
if (advances) {
1033+
for (int i = 0; i < count; i++) {
1034+
if (advances[i].width > (double)MAX_SIZE) advances[i].width = 0;
1035+
if (advances[i].height > (double)MAX_SIZE) advances[i].height = 0;
1036+
}
1037+
}
1038+
}
1039+

src/java.desktop/share/classes/sun/font/FileFontStrike.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import java.awt.geom.Rectangle2D;
3838
import java.util.concurrent.ConcurrentHashMap;
3939
import static sun.awt.SunHints.*;
40+
import sun.java2d.pipe.OutlineTextRenderer;
4041

4142

4243
public class FileFontStrike extends PhysicalStrike {
@@ -107,6 +108,7 @@ public class FileFontStrike extends PhysicalStrike {
107108
boolean useNatives;
108109
NativeStrike[] nativeStrikes;
109110

111+
static final int MAX_IMAGE_SIZE = OutlineTextRenderer.THRESHHOLD;
110112
/* Used only for communication to native layer */
111113
private int intPtSize;
112114

@@ -697,6 +699,20 @@ float getCodePointAdvance(int cp) {
697699
void getGlyphImageBounds(int glyphCode, Point2D.Float pt,
698700
Rectangle result) {
699701

702+
if (intPtSize > MAX_IMAGE_SIZE) {
703+
Rectangle.Float obds = getGlyphOutlineBounds(glyphCode);
704+
if (obds.isEmpty()) {
705+
Rectangle bds = getGlyphOutline(glyphCode, pt.x, pt.y).getBounds();
706+
result.setBounds(bds);
707+
} else {
708+
result.x = (int)Math.floor(pt.x + obds.getX() + 0.5f);
709+
result.y = (int)Math.floor(pt.y + obds.getY() + 0.5f);
710+
result.width = (int)Math.floor(obds.getWidth() + 0.5f);
711+
result.height = (int)Math.floor(obds.getHeight() + 0.5f);
712+
}
713+
return;
714+
}
715+
700716
long ptr = getGlyphImagePtr(glyphCode);
701717
float topLeftX, topLeftY;
702718

src/java.desktop/share/native/libfontmanager/freetypeScaler.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,8 @@ static double euclidianDistance(double a, double b) {
486486
return sqrt(a*a+b*b);
487487
}
488488

489+
#define TOO_LARGE(a, b) (abs((int)(a / b)) > 32766)
490+
489491
JNIEXPORT jlong JNICALL
490492
Java_sun_font_FreetypeFontScaler_createScalerContextNative(
491493
JNIEnv *env, jobject scaler, jlong pScaler, jdoubleArray matrix,
@@ -497,6 +499,7 @@ Java_sun_font_FreetypeFontScaler_createScalerContextNative(
497499
(FTScalerInfo*) jlong_to_ptr(pScaler);
498500

499501
if (context == NULL) {
502+
free(context);
500503
invalidateJavaScaler(env, scaler, NULL);
501504
return (jlong) 0;
502505
}
@@ -506,7 +509,18 @@ Java_sun_font_FreetypeFontScaler_createScalerContextNative(
506509
//text can not be smaller than 1 point
507510
ptsz = 1.0;
508511
}
512+
if (ptsz > 16384) {
513+
ptsz = 16384; // far enough from 32767
514+
fm = TEXT_FM_ON; // avoids calculations which might overflow
515+
}
509516
context->ptsz = (int)(ptsz * 64);
517+
if (TOO_LARGE(dmat[0], ptsz) || TOO_LARGE(dmat[1], ptsz) ||
518+
TOO_LARGE(dmat[2], ptsz) || TOO_LARGE(dmat[3], ptsz))
519+
{
520+
free(context);
521+
return (jlong)0;
522+
}
523+
510524
context->transform.xx = FloatToFTFixed((float)(dmat[0]/ptsz));
511525
context->transform.yx = -FloatToFTFixed((float)(dmat[1]/ptsz));
512526
context->transform.xy = -FloatToFTFixed((float)(dmat[2]/ptsz));
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import java.awt.Font;
25+
import java.awt.FontMetrics;
26+
import java.awt.Graphics2D;
27+
import java.awt.Rectangle;
28+
import java.awt.font.FontRenderContext;
29+
import java.awt.font.GlyphVector;
30+
import java.awt.geom.AffineTransform;
31+
import java.awt.geom.Rectangle2D;
32+
import java.awt.image.BufferedImage;
33+
34+
/*
35+
* @test
36+
* @bug 8328896
37+
* @summary test that using very large font sizes used don't break later uses
38+
*/
39+
40+
public class ExtremeFontSizeTest {
41+
42+
static BufferedImage bi = new BufferedImage(1,1,1);
43+
static Graphics2D g2d = bi.createGraphics();
44+
static String testString = "M";
45+
static Font font = new Font("SansSerif", Font.PLAIN, 12);
46+
static int fontSize = 0;
47+
static boolean failed = false;
48+
static int[] fontSizes = { 10, 12, 1000, 2000, 20000, 100000, 8 };
49+
static double[] scales = { 1.0, 900.0};
50+
static boolean[] fms = { false, true };
51+
52+
public static void main(String[] args) {
53+
54+
/* run tests validating bounds etc are non-zero
55+
* then run with extreme scales for which zero is allowed - but not required
56+
* then run the first tests again to be sure they are still reasonable.
57+
*/
58+
runTests();
59+
test(5_000_000, 10_000, false, testString, false);
60+
test(5_000_000, 10_000, true, testString, false);
61+
test(0, 0.00000001, false, testString, false);
62+
runTests();
63+
64+
if (failed) {
65+
throw new RuntimeException("Test failed. Check stdout log.");
66+
}
67+
}
68+
69+
static void runTests() {
70+
for (int fontSize : fontSizes) {
71+
for (double scale : scales) {
72+
for (boolean fm : fms) {
73+
test(fontSize, scale, fm, testString, true);
74+
}
75+
}
76+
}
77+
}
78+
79+
static void test(int size, double scale, boolean fm, String str, boolean checkAll) {
80+
81+
AffineTransform at = AffineTransform.getScaleInstance(scale, scale);
82+
FontRenderContext frc = new FontRenderContext(at, false, fm);
83+
font = font.deriveFont((float)size);
84+
g2d.setTransform(at);
85+
g2d.setFont(font);
86+
FontMetrics metrics = g2d.getFontMetrics();
87+
int height = metrics.getHeight();
88+
double width = font.getStringBounds(str, frc).getWidth();
89+
90+
GlyphVector gv = font.createGlyphVector(frc, str.toCharArray());
91+
Rectangle pixelBounds = gv.getPixelBounds(frc, 0, 0);
92+
Rectangle2D visualBounds = gv.getVisualBounds();
93+
94+
System.out.println("Test parameters: size="+size+" scale="+scale+" fm="+fm+" str="+str);
95+
System.out.println("font height="+metrics.getHeight());
96+
System.out.println("string bounds width="+width);
97+
System.out.println("GlyphVector Pixel Bounds="+ pixelBounds);
98+
System.out.println("GlyphVector Visual Bounds="+ visualBounds);
99+
100+
101+
if (height < 0 || width < 0 || pixelBounds.getWidth() < 0 || visualBounds.getWidth() < 0) {
102+
failed = true;
103+
System.out.println(" *** Unexpected negative size reported *** ");
104+
}
105+
if (!checkAll) {
106+
System.out.println();
107+
return;
108+
}
109+
110+
if (height == 0 || width == 0 || (pixelBounds.isEmpty()) || visualBounds.isEmpty() ) {
111+
failed = true;
112+
System.out.println("Pixel bounds empty="+pixelBounds.isEmpty());
113+
System.out.println("Visual bounds empty="+visualBounds.isEmpty());
114+
System.out.println(" *** RESULTS NOT AS EXPECTED *** ");
115+
}
116+
System.out.println();
117+
}
118+
}

0 commit comments

Comments
 (0)