Skip to content

Commit

Permalink
Enhance the PDF glyph handling to handle advanced kerning and ligatur…
Browse files Browse the repository at this point in the history
…es (#2059)
  • Loading branch information
speckyspooky authored Feb 28, 2025
1 parent 83e4837 commit 4bb9439
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import java.awt.print.Paper;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -599,7 +598,7 @@ private void drawText(String text, float textX, float textY, FontInfo fontInfo,
// PDF/A fallback font must be entered fully qualified with path and file name
String defaultFontPdfA = this.pageDevice.getDefaultFontPdfA();
if (defaultFontPdfA != null) {
font = BaseFont.createFont(defaultFontPdfA, BaseFont.IDENTITY_H, true);
font = BaseFont.createFont(defaultFontPdfA, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
font.setIncludeCidSet(this.pageDevice.isIncludeCidSet());
}
logger.log(Level.WARNING,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ public void concatPDFs(List<InputStream> streamOfPDFFiles, boolean paginate) {
// Create a writer for the outputstream
PdfWriter writer = this.writer;

BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED); // TGXX
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
PdfContentByte cb = writer.getDirectContent(); // Holds the PDF

PdfImportedPage page;
Expand Down
3 changes: 3 additions & 0 deletions engine/org.eclipse.birt.report.engine.fonts/fontsConfig.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
currently "Times-Roman", to denote a place of missing character.
-->
<font>
<!-- font advanced kerning ligatures will be used, enabled: false/unused (default), true/used -->
<kerning-and-ligatures enabled="false" />

<!--
In <font-aliases> section, you can:
a. Define a mapping from a generic family to a font family.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*******************************************************************************
-->
<font>
<!-- font advanced kerning ligatures will be used, enabled: false/unused (default), true/used -->
<!--<kerning-and-ligatures enabled="true" />-->
<font-aliases>
<mapping name="serif" font-family="Times-Roman" />
<mapping name="sans-serif" font-family="Helvetica" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008 Actuate Corporation.
* Copyright (c) 2008, 2025 Actuate Corporation and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
Expand Down Expand Up @@ -111,6 +111,9 @@ public ParseState startElement(String tagName) {
private final static String TAG_CHARACTER = "character"; //$NON-NLS-1$
private final static String ATTR_VALUE = "value"; //$NON-NLS-1$

private final static String TAG_FONT_KERNING = "kerning-and-ligatures"; //$NON-NLS-1$
private final static String ATTR_KERNING_ENABLED = "enabled"; //$NON-NLS-1$

private class RootState extends ParseState {

@Override
Expand Down Expand Up @@ -146,6 +149,9 @@ public ParseState startElement(String tagName) {
if (TAG_COMPOSITE_FONT.equals(tagValue)) {
return new CompositeFontState();
}
if (TAG_FONT_KERNING.equals(tagValue)) {
return new FontKerningState();
}
return super.startElement(tagName);
}
}
Expand Down Expand Up @@ -173,6 +179,17 @@ public void parseAttrs(Attributes attrs) {
}
}

private class FontKerningState extends ParseState {

@Override
public void parseAttrs(Attributes attrs) {
String kerning = getStringValue(attrs, ATTR_KERNING_ENABLED);
if (kerning != null) {
config.setFontKerning(Boolean.valueOf(kerning));
}
}
}

private class FontAliasesState extends ParseState {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,23 @@
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
* Reader to read the font configuration file (fontsConfig*.xml)
*
* @since 3.3
*
*/
public class FontConfigReader {

/**
* Constructor
*
* @param url file url
* @return the configured font mapping
* @throws IOException
* @throws ParserConfigurationException
* @throws SAXException
*/
public FontMappingConfig parseConfig(URL url) throws IOException, ParserConfigurationException, SAXException {
InputStream input = url.openStream();
try (input) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004,2008 Actuate Corporation.
* Copyright (c) 2004, 2008, 2025 Actuate Corporation and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
Expand Down Expand Up @@ -27,6 +27,7 @@

import com.lowagie.text.Font;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.LayoutProcessor;

/**
* the font handler, which maps fontFamily, fontStyle, fontWeight properties to
Expand Down Expand Up @@ -99,6 +100,7 @@ public FontHandler(FontMappingManager fontManager, ITextContent textContent, boo
textContent) / PDFConstants.LAYOUT_TO_PDF_RATIO;

if (!fontSubstitution) {
enableKerningAndLigatures();
for (int i = 0; i < fontFamilies.length; i++) {
String fontName = fontManager.getAliasedFont(fontFamilies[i]);
bf = fontManager.createFont(fontName, fontStyle);
Expand All @@ -110,6 +112,14 @@ public FontHandler(FontMappingManager fontManager, ITextContent textContent, boo
}
}

/**
* The constructor
*
* @param fontManager font manager
* @param fontFamilies font families
* @param fontStyle font style
* @param fontSubstitution font substitution
*/
public FontHandler(FontMappingManager fontManager, String fontFamilies[], int fontStyle, boolean fontSubstitution) {
this.fontManager = fontManager;

Expand All @@ -120,6 +130,7 @@ public FontHandler(FontMappingManager fontManager, String fontFamilies[], int fo
this.fontSize = fontSize / PDFConstants.LAYOUT_TO_PDF_RATIO;

if (!fontSubstitution) {
enableKerningAndLigatures();
for (int i = 0; i < fontFamilies.length; i++) {
String fontName = fontManager.getAliasedFont(fontFamilies[i]);
bf = fontManager.createFont(fontName, fontStyle);
Expand Down Expand Up @@ -192,6 +203,7 @@ public BaseFont getMappedFont(char c) {
}
}
// search in the font family to find one to display the character
enableKerningAndLigatures();
for (int i = 0; i < fontFamilies.length; i++) {
// Translate the font alias to font family
String fontFamily = fontManager.getAliasedFont(fontFamilies[i]);
Expand Down Expand Up @@ -306,4 +318,15 @@ private String getEnglishName(String[][] names) {

return tmp;
}

/**
* Enable the font mode to handle advanced kerning and ligatures
*
* @since 4.19
*/
private void enableKerningAndLigatures() {
if (fontManager.useFontKerningAdvanced() && !LayoutProcessor.isEnabled()) {
LayoutProcessor.enableKernLiga();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008 Actuate Corporation.
* Copyright (c) 2008, 2025 Actuate Corporation and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
Expand Down Expand Up @@ -45,6 +45,9 @@ public class FontMappingConfig {
*/
protected HashMap<String, CompositeFontConfig> compositeFonts = new HashMap<String, CompositeFontConfig>();

/** Usage of the advanced font kerning and ligatures */
protected boolean fontKerningAdvancedUsage = false;

/**
* Constructor
*/
Expand Down Expand Up @@ -144,4 +147,22 @@ public void addCompositeFont(CompositeFontConfig fontConfig) {
public Collection<CompositeFontConfig> getAllCompositeFonts() {
return compositeFonts.values();
}

/**
* Set the usage of advanced font kerning and ligatures
*
* @param kerning usage of advanced font kerning and ligatures
*/
public void setFontKerning(boolean kerning) {
fontKerningAdvancedUsage = kerning;
}

/**
* Get the usage of advanced font kerning and ligatures
*
* @return the usage of advanced font kerning and ligatures
*/
public boolean getFontKerning() {
return fontKerningAdvancedUsage;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004,2008 Actuate Corporation.
* Copyright (c) 2004, 2008, 2025 Actuate Corporation and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
Expand All @@ -21,6 +21,12 @@

import com.lowagie.text.pdf.BaseFont;

/**
* Manager to handle the font mapping configuration
*
* @since 3.3
*
*/
public class FontMappingManager {

/** all fonts key */
Expand All @@ -40,6 +46,9 @@ public class FontMappingManager {
/** The font-family replacement */
private Map fontAliases = new HashMap();

/** Usage of the advanced font kerning and ligatures */
private boolean fontKerningAdvancedUsage = false;

/**
* composite fonts
*/
Expand All @@ -54,10 +63,14 @@ public class FontMappingManager {
this.fontAliases.putAll(parent.getFontAliases());
this.fontEncodings.putAll(parent.getFontEncodings());
this.compositeFonts.putAll(parent.getCompositeFonts());
if (!this.fontKerningAdvancedUsage)
this.fontKerningAdvancedUsage = parent.fontKerningAdvancedUsage;
}
this.fontEncodings.putAll(config.fontEncodings);
this.searchSequences.putAll(config.searchSequences);
this.fontAliases.putAll(config.fontAliases);
if (!this.fontKerningAdvancedUsage)
this.fontKerningAdvancedUsage = config.fontKerningAdvancedUsage;

String[] sequence = getSearchSequence(locale);
Iterator iter = config.compositeFonts.entrySet().iterator();
Expand All @@ -70,26 +83,60 @@ public class FontMappingManager {
}
}

/**
* Get the parent font mapping manager
*
* @return the parent font mapping manager
*/
public FontMappingManager getParent() {
return parent;
}

/**
* Get the font encodings
*
* @return the font encodings
*/
public Map getFontEncodings() {
return fontEncodings;
}

/**
* Get the font aliases
*
* @return the font aliases
*/
public Map getFontAliases() {
return fontAliases;
}

/**
* Get the search sequences
*
* @return the search sequences
*/
public Map getSearchSequences() {
return searchSequences;
}

/**
* Get the composite fonts
*
* @return the composite fonts
*/
public Map getCompositeFonts() {
return compositeFonts;
}

/**
* Get the usage of advanced font kerning and ligatures
*
* @return the usage of advanced font kerning and ligatures
*/
public boolean useFontKerningAdvanced() {
return fontKerningAdvancedUsage;
}

protected String[] getSearchSequence(Locale locale) {
StringBuilder sb = new StringBuilder();
String[] localeKeys = new String[3];
Expand All @@ -105,10 +152,22 @@ protected String[] getSearchSequence(Locale locale) {
return null;
}

/**
* Get the composite font based at font name
*
* @param name font name
* @return the composite font based at font name
*/
public CompositeFont getCompositeFont(String name) {
return (CompositeFont) compositeFonts.get(name);
}

/**
* Get the default physical font
*
* @param c special character of the font
* @return the default physical font
*/
public String getDefaultPhysicalFont(char c) {
CompositeFont compositeFont = (CompositeFont) compositeFonts.get(FONT_NAME_ALL_FONTS);
if (compositeFont != null) {
Expand All @@ -121,6 +180,12 @@ public String getDefaultPhysicalFont(char c) {
return null;
}

/**
* Get the aliased font
*
* @param fontAlias font alias name
* @return the aliased font
*/
public String getAliasedFont(String fontAlias) {
String alias = (String) fontAliases.get(fontAlias.toLowerCase());
if (alias != null) {
Expand All @@ -133,7 +198,7 @@ public String getAliasedFont(String fontAlias) {
* Creates iText BaseFont with the given font family name.
*
* @param fontFamily the specified font family name.
* @param style font style
* @param fontStyle font style
* @return the created BaseFont.
*/
public BaseFont createFont(String fontFamily, int fontStyle) {
Expand Down

0 comments on commit 4bb9439

Please sign in to comment.