1- package com .levigo .jadice .fonts ;
2-
3- import static com .levigo .jadice .document .io .IOUtils .wrap ;
4- import static com .levigo .jadice .format .truetype .internal .FSType .FSTYPE_EMBEDDING_INSTALLABLE ;
5- import static com .levigo .jadice .format .truetype .internal .structure .TrueTypeConstants .PLATFORM_ID_MS ;
6- import static com .levigo .jadice .format .truetype .internal .structure .TrueTypeConstantsMS .ENCODING_ID_MS_UNICODE_BMP ;
7- import static java .awt .geom .AffineTransform .getScaleInstance ;
8- import static org .hamcrest .CoreMatchers .is ;
9- import static org .junit .Assert .assertThat ;
10-
11- import java .awt .Color ;
12- import java .awt .Graphics2D ;
13- import java .awt .Rectangle ;
14- import java .awt .geom .Rectangle2D ;
15- import java .awt .image .BufferedImage ;
16- import java .io .IOException ;
17-
18- import org .junit .Before ;
19- import org .junit .Test ;
20- import org .junit .runner .RunWith ;
21- import org .junit .runners .Parameterized ;
22-
23- import com .levigo .jadice .document .ImageComparisonTest ;
24- import com .levigo .jadice .document .JadiceException ;
25- import com .levigo .jadice .document .internal .model .font .JadiceGlyphVector ;
26- import com .levigo .jadice .document .internal .render .font .GraphicsContextOutlineFontRenderer ;
27- import com .levigo .jadice .document .internal .render .j2d .Graphics2DBridge ;
28- import com .levigo .jadice .document .io .SeekableInputStream ;
29- import com .levigo .jadice .format .truetype .internal .TrueTypeFont ;
30- import com .levigo .jadice .format .truetype .internal .TrueTypeFontLoader ;
31- import com .levigo .jadice .format .truetype .internal .structure .CMap ;
32-
33- @ RunWith (Parameterized .class )
34- public class CompatibilityTest extends ImageComparisonTest {
35-
36- private static final String SAMPLE_TEXT = "ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ " + "abcdefghijklmnopqrstuvwxyzäöüß "
37- + "1234567890 " + "@€!\" §$%&/()=?{}[]\\ <>|,;.:-_#'+*~´`µ°^²³" ;
38-
39- private static final int FONT_SIZE = 40 ;
40-
41- private static final int MARKER_SIZE = 3 ;
42-
43- @ Parameterized .Parameters (name = "{index} - {0}" )
44- public static Object [] parameters () {
45- return new Object []{
46- "mono/Cousine-Regular.ttf" , "mono/Cousine-Bold.ttf" , "mono/Cousine-Italic.ttf" , "mono/Cousine-BoldItalic.ttf" ,
47- "sans/Arimo-Regular.ttf" , "sans/Arimo-Bold.ttf" , "sans/Arimo-Italic.ttf" , "sans/Arimo-BoldItalic.ttf" ,
48- "serif/Tinos-Regular.ttf" , "serif/Tinos-Bold.ttf" , "serif/Tinos-Italic.ttf" , "serif/Tinos-BoldItalic.ttf" ,
49- "symbol/Levibats-Regular.ttf"
50- };
51- }
52-
53- @ Parameterized .Parameter (0 )
54- public String fontResource ;
55-
56- public TrueTypeFont font ;
57-
58- @ Before
59- public void setUpTrueTypeFont () throws IOException , JadiceException {
60- final SeekableInputStream inputStream = wrap (getClass ().getResourceAsStream (fontResource ));
61- final TrueTypeFontLoader fontLoader = new TrueTypeFontLoader ();
62- font = (TrueTypeFont ) fontLoader .load (inputStream );
63- }
64-
65- @ Test
66- public void assertThat_fsType_allowsEditing () {
67- assertThat (font .getFsType (), is (FSTYPE_EMBEDDING_INSTALLABLE .getMask ()));
68- }
69-
70- @ Test
71- public void assertThat_renderedGlyphVector_hasExpectedVisualOutput () throws Exception {
72- final CMap microsoftUnicodeCMap = font .getCMap (PLATFORM_ID_MS , ENCODING_ID_MS_UNICODE_BMP );
73- final int [] codePoints = new int [SAMPLE_TEXT .length ()];
74- final char [] sampleTextChars = SAMPLE_TEXT .toCharArray ();
75- for (int i = 0 ; i < sampleTextChars .length ; i ++) {
76- codePoints [i ] = microsoftUnicodeCMap .map (sampleTextChars [i ]);
77- }
78-
79- final JadiceGlyphVector glyphVector = new JadiceGlyphVector (0 , 0 , font , codePoints , sampleTextChars );
80- glyphVector .setTransform (getScaleInstance (FONT_SIZE , FONT_SIZE ));
81-
82- final BufferedImage renderedGlyphVector = render (glyphVector );
83- compareWithExpected (renderedGlyphVector , fontResource );
84- }
85-
86- private BufferedImage render (final JadiceGlyphVector glv ) {
87- final GraphicsContextOutlineFontRenderer renderer = new GraphicsContextOutlineFontRenderer ();
88-
89- final Rectangle2D b = glv .getGlyphLogicalBounds (0 ).getBounds2D ();
90- b .add (glv .getGlyphLogicalBounds (glv .getNumGlyphs () - 1 ).getBounds2D ());
91- b .add (0 , 0 ); // make sure to include origin!
92-
93- final Rectangle bounds = b .getBounds ();
94- final int gap = bounds .height / 2 ;
95- final BufferedImage img = new BufferedImage (bounds .width + gap , bounds .height + gap , BufferedImage .TYPE_INT_RGB );
96- final Graphics2D g = img .createGraphics ();
97- g .setColor (Color .WHITE );
98- g .fillRect (0 , 0 , img .getWidth (), img .getHeight ());
99-
100- g .setColor (Color .BLACK );
101-
102- final Graphics2DBridge gc = new Graphics2DBridge (g );
103- gc .scale (1 , -1 );
104- gc .translate (gap / 2 , -(bounds .height + bounds .y + gap / 2 ));
105-
106- // draw bounding box
107- g .setColor (Color .RED );
108- g .draw (glv .getVisualBounds ());
109-
110- // draw glyph info
111- final float p1 [] = new float [2 ];
112- final float p0 [] = new float [2 ];
113- for (int i = 0 ; i < glv .getNumGlyphs (); i ++) {
114- g .setColor (Color .ORANGE );
115- g .draw (glv .getGlyphVisualBounds (i ));
116-
117- g .setColor (Color .BLUE );
118- g .draw (glv .getGlyphLogicalBounds (i ));
119-
120- // position
121- g .setColor (Color .GREEN .darker ());
122- glv .getGlyphPosition (i , p1 );
123- p1 [0 ] += glv .getPosX ();
124- p1 [1 ] += glv .getPosY ();
125- drawX (g , (int ) p1 [0 ], (int ) p1 [1 ]);
126-
127- // advance
128- if (i > 0 ) {
129- glv .getGlyphPosition (i - 1 , p0 );
130- p0 [0 ] += glv .getPosX ();
131- p0 [1 ] += glv .getPosY ();
132- g .drawLine ((int ) p0 [0 ], (int ) p0 [1 ], (int ) p1 [0 ], (int ) p1 [1 ]);
133- }
134- }
135-
136- // draw origin
137- g .setColor (Color .MAGENTA );
138- drawX (g , 0 , 0 );
139-
140- // draw outline
141- final com .levigo .jadice .document .internal .model .Color color = com .levigo .jadice .document .internal .model .Color .BLACK ;
142- gc .setColor (color );
143- final Color awtColor = color .toAWTColor ();
144- renderer .render (glv , gc , null , null , awtColor , awtColor );
145-
146- return img ;
147- }
148-
149- private void drawX (final Graphics2D g , int x , int y ) {
150- g .drawLine (x - MARKER_SIZE , y - MARKER_SIZE , x + MARKER_SIZE , y + MARKER_SIZE );
151- g .drawLine (x - MARKER_SIZE , y + MARKER_SIZE , x + MARKER_SIZE , y - MARKER_SIZE );
152- }
153-
154- }
1+ package com .levigo .jadice .fonts ;
2+
3+ import static com .levigo .jadice .format .truetype .internal .FSType .FSTYPE_EMBEDDING_INSTALLABLE ;
4+ import static com .levigo .jadice .format .truetype .internal .structure .TrueTypeConstants .PLATFORM_ID_MS ;
5+ import static com .levigo .jadice .format .truetype .internal .structure .TrueTypeConstantsMS .ENCODING_ID_MS_UNICODE_BMP ;
6+ import static java .awt .geom .AffineTransform .getScaleInstance ;
7+
8+ import java .awt .Color ;
9+ import java .awt .Graphics2D ;
10+ import java .awt .Rectangle ;
11+ import java .awt .geom .Rectangle2D ;
12+ import java .awt .image .BufferedImage ;
13+ import java .util .Arrays ;
14+
15+ import org .junit .jupiter .api .Assertions ;
16+
17+ import com .levigo .jadice .document .internal .model .font .JadiceGlyphVector ;
18+ import com .levigo .jadice .document .internal .render .font .GraphicsContextOutlineFontRenderer ;
19+ import com .levigo .jadice .document .internal .render .j2d .Graphics2DBridge ;
20+ import com .levigo .jadice .format .truetype .internal .TrueTypeFont ;
21+ import com .levigo .jadice .format .truetype .internal .structure .CMap ;
22+
23+ public class FontResourceTest extends AbstractFontResourceTest {
24+ private static final String LEVI_SYMBOL_REGULAR = "LeviSymbol-Regular" ;
25+
26+ private static final String SAMPLE_TEXT = "ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ " + "abcdefghijklmnopqrstuvwxyzäöüß "
27+ + "1234567890 " + "@€!\" §$%&/()=?{}[]\\ <>|,;.:-_#'+*~´`µ°^²³" ;
28+ private static final int FONT_SIZE = 40 ;
29+ private static final int MARKER_SIZE = 3 ;
30+
31+ @ Override
32+ public Iterable <String > fontResourceNames () {
33+ return Arrays .asList (
34+ "mono/Cousine-Regular.ttf" , "mono/Cousine-Bold.ttf" , "mono/Cousine-Italic.ttf" , "mono/Cousine-BoldItalic.ttf" ,
35+ "sans/Arimo-Regular.ttf" , "sans/Arimo-Bold.ttf" , "sans/Arimo-Italic.ttf" , "sans/Arimo-BoldItalic.ttf" ,
36+ "serif/Tinos-Regular.ttf" , "serif/Tinos-Bold.ttf" , "serif/Tinos-Italic.ttf" , "serif/Tinos-BoldItalic.ttf" ,
37+ "symbol/Levibats-Regular.ttf" , "symbol/LeviSymbol-Regular.ttf" );
38+ }
39+
40+ @ FontResourceTestCase
41+ public void assertThat_fsType_allowsEditing () {
42+ Assertions .assertEquals (fontResource .getFsType (), FSTYPE_EMBEDDING_INSTALLABLE .getMask ());
43+ }
44+
45+ @ FontResourceTestCase
46+ public void assertThat_renderedGlyphVector_hasExpectedVisualOutput () throws Exception {
47+ if (skipRenderTest (fontResource ))
48+ return ;
49+
50+ final CMap microsoftUnicodeCMap = fontResource .getCMap (PLATFORM_ID_MS , ENCODING_ID_MS_UNICODE_BMP );
51+ final int [] codePoints = new int [SAMPLE_TEXT .length ()];
52+ final char [] sampleTextChars = SAMPLE_TEXT .toCharArray ();
53+ for (int i = 0 ; i < sampleTextChars .length ; i ++) {
54+ codePoints [i ] = microsoftUnicodeCMap .map (sampleTextChars [i ]);
55+ }
56+
57+ final JadiceGlyphVector glyphVector = new JadiceGlyphVector (0 , 0 , fontResource , codePoints , sampleTextChars );
58+ glyphVector .setTransform (getScaleInstance (FONT_SIZE , FONT_SIZE ));
59+
60+ final BufferedImage renderedGlyphVector = render (glyphVector );
61+ imageComparisonTest .compareWithExpected (renderedGlyphVector , fontResourceName );
62+ }
63+
64+ private BufferedImage render (final JadiceGlyphVector glv ) {
65+ final GraphicsContextOutlineFontRenderer renderer = new GraphicsContextOutlineFontRenderer ();
66+
67+ final Rectangle2D b = glv .getGlyphLogicalBounds (0 ).getBounds2D ();
68+ b .add (glv .getGlyphLogicalBounds (glv .getNumGlyphs () - 1 ).getBounds2D ());
69+ b .add (0 , 0 ); // make sure to include origin!
70+
71+ final Rectangle bounds = b .getBounds ();
72+ final int gap = bounds .height / 2 ;
73+ final BufferedImage img = new BufferedImage (bounds .width + gap , bounds .height + gap , BufferedImage .TYPE_INT_RGB );
74+ final Graphics2D g = img .createGraphics ();
75+ g .setColor (Color .WHITE );
76+ g .fillRect (0 , 0 , img .getWidth (), img .getHeight ());
77+
78+ g .setColor (Color .BLACK );
79+
80+ final Graphics2DBridge gc = new Graphics2DBridge (g );
81+ gc .scale (1 , -1 );
82+ gc .translate (gap / 2 , -(bounds .height + bounds .y + gap / 2 ));
83+
84+ // draw bounding box
85+ g .setColor (Color .RED );
86+ g .draw (glv .getVisualBounds ());
87+
88+ // draw glyph info
89+ final float [] p1 = new float [2 ];
90+ final float [] p0 = new float [2 ];
91+ for (int i = 0 ; i < glv .getNumGlyphs (); i ++) {
92+ g .setColor (Color .ORANGE );
93+ g .draw (glv .getGlyphVisualBounds (i ));
94+
95+ g .setColor (Color .BLUE );
96+ g .draw (glv .getGlyphLogicalBounds (i ));
97+
98+ // position
99+ g .setColor (Color .GREEN .darker ());
100+ glv .getGlyphPosition (i , p1 );
101+ p1 [0 ] += glv .getPosX ();
102+ p1 [1 ] += glv .getPosY ();
103+ drawX (g , (int ) p1 [0 ], (int ) p1 [1 ]);
104+
105+ // advance
106+ if (i > 0 ) {
107+ glv .getGlyphPosition (i - 1 , p0 );
108+ p0 [0 ] += glv .getPosX ();
109+ p0 [1 ] += glv .getPosY ();
110+ g .drawLine ((int ) p0 [0 ], (int ) p0 [1 ], (int ) p1 [0 ], (int ) p1 [1 ]);
111+ }
112+ }
113+
114+ // draw origin
115+ g .setColor (Color .MAGENTA );
116+ drawX (g , 0 , 0 );
117+
118+ // draw outline
119+ final com .levigo .jadice .document .internal .model .Color color = com .levigo .jadice .document .internal .model .Color .BLACK ;
120+ gc .setColor (color );
121+ final Color awtColor = color .toAWTColor ();
122+ renderer .render (glv , gc , null , null , awtColor , awtColor );
123+
124+ return img ;
125+ }
126+
127+ private void drawX (final Graphics2D g , int x , int y ) {
128+ g .drawLine (x - MARKER_SIZE , y - MARKER_SIZE , x + MARKER_SIZE , y + MARKER_SIZE );
129+ g .drawLine (x - MARKER_SIZE , y + MARKER_SIZE , x + MARKER_SIZE , y - MARKER_SIZE );
130+ }
131+
132+ private boolean skipRenderTest (TrueTypeFont font ) {
133+ return LEVI_SYMBOL_REGULAR .equals (font .getDescriptor ().getPostscriptName ());
134+ }
135+ }
0 commit comments