aboutsummaryrefslogtreecommitdiff
path: root/debian/patches/FreetypeFontScaler_getFontMetricsNative.diff
blob: 08212535ae3b0630a5a3d53553003bd79affc99d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
Description: 
 Problem
 =======
 On OpenJDK JRE and using some TrueType font, JasperReports does not
 display text element which height is just the same as the font size
 eg. { height="8", size="8", font="IPA mincho" }.
 JasperReports checks the text size before drawing the text elements.
 If (ascent + descent) of text is greater than the height of text
 element, this text is not drawn.
 In above case, Sun Java returns the same height (ascent + descent =
 fontsize), but OpenJDK returns the text height greater than font size,
 so not drawn.

 Sample code (includes Japanese char)
 ===================================
 import java.awt.Font;
 import java.awt.font.FontRenderContext;
 import java.awt.font.TextLayout;
 public class JavaApplication1 {
    public static void main(String[] args) throws Exception {
        Font f = new Font("IPA明朝",Font.PLAIN, 8);
        TextLayout layout = new TextLayout("IPA明朝", f,
                new FontRenderContext(null, true, true));
        System.out.println("Ascent:  " + layout.getAscent());
        System.out.println("Descent: " + layout.getDescent());
    }
 }
 Result of this code
 ===================
 Sun Java 6 (sun-java6-jre 6.26-0squeeze1)
 > Ascent:  7.0390625
 > Descent: 0.9609375

 OpenJDK 6 (openjdk-6-jre 6b24~pre2-1)
 > Ascent:  7.046875
 > Descent: 0.96875

 OpenJDK 7 (openjdk-7-jre 7~b147-2.0-1)
 > Ascent:  7.046875
 > Descent: 0.96875

 Sun Java returns correct height, but OpenJDK returns greater value
 than Sun's.
 Analysis of Source code
 =======================
 In OpenJDK6/7 native method sun.font.FreetypeFontScaler.getFontMetricsNative():
 jdk/src/share/native/sun/font/freetypeScaler.c
 >JNIEXPORT jobject JNICALL
 >Java_sun_font_FreetypeFontScaler_getFontMetricsNative(
 >        JNIEnv *env, jobject scaler, jobject font2D,
 >        jlong pScalerContext, jlong pScaler) {
 (snip)
 >    /* ascent */
 >    ax = 0;
 >    ay = -(jfloat) FT26Dot6ToFloat(FT_MulFix(
 >                       ((jlong) scalerInfo->face->ascender + bmodifier/2),
 >                       (jlong) scalerInfo->face->size->metrics.y_scale));
 >    /* descent */
 >    dx = 0;
 >    dy = -(jfloat) FT26Dot6ToFloat(FT_MulFix(
 >                       ((jlong) scalerInfo->face->descender + bmodifier/2),
 >                       (jlong) scalerInfo->face->size->metrics.y_scale));
 (snip)
 >    metrics = (*env)->NewObject(env,
 >                                sunFontIDs.strikeMetricsClass,
 >                                sunFontIDs.strikeMetricsCtr,
 >                                ax, ay, dx, dy, bx, by, lx, ly, mx, my);
 >
 >    return metrics;
 >} 
 This code uses FT_MulFix to convert size. But FT_MulFix sometimes rounds
 up and loses precision.
 In FreeType2's FT_MulFix:
 freetype-2.4.8/src/base/ftcalc.c
 >   c = (FT_Long)( ( (FT_Int64)a * b + 0x8000L ) >> 16 );
 If both ascent and descent are rounded up, (ascent + descent) is greater
 than original height.
 In the sample case (IPA mincho font),
  bmodifier = 0
  scalerInfo->face->ascender = 1802L
  scalerInfo->face->descender = -246L
  scalerInfo->face->size->metrics.y_scale = 16384L
 In this case, 1802 mod 4 = 2 and 246 mod 4 = 2, so both are rounded up.
 This causes (ay + dy) > font-size.
 (Note: (Sun) 1802.0/256.0 = 7.0390625, (OpenJDK) 1804.0/256.0 = 7.046875)
 Suggested fix
 =============
 Fix to keep the precision in the font metrics conversion in
 Java_sun_font_FreetypeFontScaler_getFontMetricsNative().
Author: Nobuhiro Ban <ban.nobuhiro@gmail.com>
Bug-Debian: http://bugs.debian.org/657854
--- openjdk/jdk/src/share/native/sun/font/freetypeScaler.c
+++ openjdk/jdk/src/share/native/sun/font/freetypeScaler.c
@@ -488,14 +488,15 @@
 
     /**** Note: only some metrics are affected by styling ***/
 
+#define FT_MulFixFloatShift6(a, b) (((float) (a)) * ((float) (b)) / 65536.0 / 64.0)
     /* ascent */
     ax = 0;
-    ay = -(jfloat) FT26Dot6ToFloat(FT_MulFix(
+    ay = -(jfloat) (FT_MulFixFloatShift6(
                        ((jlong) scalerInfo->face->ascender + bmodifier/2),
                        (jlong) scalerInfo->face->size->metrics.y_scale));
     /* descent */
     dx = 0;
-    dy = -(jfloat) FT26Dot6ToFloat(FT_MulFix(
+    dy = -(jfloat) (FT_MulFixFloatShift6(
                        ((jlong) scalerInfo->face->descender + bmodifier/2),
                        (jlong) scalerInfo->face->size->metrics.y_scale));
     /* baseline */
@@ -503,7 +504,7 @@
 
     /* leading */
     lx = 0;
-    ly = (jfloat) FT26Dot6ToFloat(FT_MulFix(
+    ly = (jfloat) (FT_MulFixFloatShift6(
                       (jlong) scalerInfo->face->height + bmodifier,
                       (jlong) scalerInfo->face->size->metrics.y_scale))
                   + ay - dy;