JDK-7162125 : [macosx] A font has different behaviour for ligatures depending on its creation mode
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 7,8,9
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • OS: os_x
  • CPU: x86
  • Submitted: 2012-04-17
  • Updated: 2020-09-25
  • Resolved: 2015-11-17
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u162Fixed 9 b96Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
version "1.7.0-u6-b01"
OpenJDK Runtime Environment (build 1.7.0-u6-b01-20120314)
OpenJDK 64-Bit Server VM (build 23.0-b16, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Mac OS 10.6.8


A DESCRIPTION OF THE PROBLEM :
Latin ligatures are only active for fonts which where created using
Font.createFont(). The exact same font, created with new Font(), does not honour the TextAttribute.LIGATURES attribute correctly.



STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Get the LinuxLibertine font from http://www.linuxlibertine.org/.
Install the font LinLibertine_R_G.ttf and put a copy of it in the same folder as the java test code.
Compile and run the test code.


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Same display for both labels, with "ff" ligature in the word "efficace".

ACTUAL -
The "ff" ligature is done for the lower label (whose font is directly opened by java), but is not available for the upper label (whose font is taken from the system).


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class TestLiber {
	
	Font createFont1() {
		Font f= new Font("Linux Libertine G", Font.PLAIN, 28);

		Map<TextAttribute, Object> map= new HashMap<TextAttribute, Object>();
		map.put(TextAttribute.SIZE, 60);
		map.put(TextAttribute.KERNING, TextAttribute.KERNING_ON);
		map.put(TextAttribute.LIGATURES, TextAttribute.LIGATURES_ON);
		f= f.deriveFont(map);
		return f;
	}
	
	Font createFont2() {
		try {
			Font f= Font.createFont(Font.TRUETYPE_FONT, new FileInputStream("LinLibertine_R_G.ttf"));

			Map<TextAttribute, Object> map= new HashMap<TextAttribute, Object>();
			map.put(TextAttribute.SIZE, 60);
			map.put(TextAttribute.KERNING, TextAttribute.KERNING_ON);
			map.put(TextAttribute.LIGATURES, TextAttribute.LIGATURES_ON);
			f= f.deriveFont(map);
			return f;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public TestLiber() throws FileNotFoundException, FontFormatException, IOException {
		JFrame frame= new JFrame();
		
		String string = "il estoit efficace ect. nettoyer";

		
		JLabel label= new JLabel(string);
		JLabel label2= new JLabel(string);

		label.setFont(createFont1());
		label2.setFont(createFont2());
		frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(),BoxLayout.PAGE_AXIS));
		frame.add(label);
		frame.add(label2);
		frame.pack();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
	
	
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {

			public void run() {
				try {
					new TestLiber();
				} catch (Exception e) {
					e.printStackTrace();
					throw new RuntimeException(e);
					
				}
			}
			
		});
	}
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
directly use the files for the fonts and bypass the system ?

Comments
No immediate plans to resolve for JDK 7
13-03-2017

The problem is that complex text layout and accompanying typographic support is largely limping along on OS X and then only thanks to some canonical tables that the ICU library has. The bug is that the internal font "peer" that passes the font tables containing the necessary information for OpenType (and AAT) layout does not implement the necessary functions. So there is no way to get the information that the font itself contains, resulting in incorrect rendering The fix needs to be to add to the osx "CFont" class the necessary code to pass that information. That is not so hard. But there is an additional complication that the OS X code uses "fallback" or "substitution" or "cascading" fonts and so a font like "Lucida Grande" might report that it supports code points from Indic scripts when it does not. It does this by reporting negative glyph codes for such cases and fixes it up in the final rendering step. The problem with that is that layout needs to use the font-specific tables and this subverts that. We need to know for sure which code points are supported and split into runs of text that the font supports. So we need to find the real fonts that the CFont uses. In core text this is obtainable as the cascading font list. We can get this and construct a CompositeFont and make its glyph mapper check that there are no *negative* glyph codes not just no zero ones. Now we can give layout proper runs and tables. The final bit is that rendering needs to also know that if it is passed a font that might implement FontSubstition that it needs to expect that layout returned glyph codes that are intended to be used with the Composite.
13-11-2015

EVALUATION This report is on Mac. and in the "new Font()" case rendering is probably heading down some Apple native code path which doesn't support this and Font.createFont() will utilise T2K or freetype at least for rasterisation and presumably is heading down the ICU path for layout .. so gets ligatures. If the Apple native code path doesn't support this functionality there may not be an easy fix.
17-04-2012