package net.padaf.preflight.font;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.padaf.preflight.ValidationConstants;
import org.apache.fontbox.ttf.CMAPEncodingEntry;
import org.apache.fontbox.ttf.TrueTypeFont;
import org.apache.pdfbox.cos.COSInteger;
import org.apache.pdfbox.encoding.Encoding;
import org.apache.pdfbox.pdmodel.font.PDFont;
public class TrueTypeFontContainer extends AbstractFontContainer {
private List<?> widthsArray = new ArrayList(0);
private int firstCharInWidthsArray = 0;
/**
* Represent the missingWidth value of the FontDescriptor dictionary.
* According to the PDF Reference, if this value is missing, the default
* one is 0.
*/
private float defaultGlyphWidth = 0;
/**
* Object which contains the TrueType font data extracted by the
* TrueTypeParser object
*/
private TrueTypeFont fontObject = null;
private CMAPEncodingEntry cmap = null;
private int numberOfLongHorMetrics;
private int unitsPerEm;
private int[] glyphWidths;
public TrueTypeFontContainer(PDFont fd) {
super(fd);
}
void setWidthsArray(List<?> widthsArray) {
this.widthsArray = widthsArray;
}
void setFirstCharInWidthsArray(int firstCharInWidthsArray) {
this.firstCharInWidthsArray = firstCharInWidthsArray;
}
void setDefaultGlyphWidth(float defaultGlyphWidth) {
this.defaultGlyphWidth = defaultGlyphWidth;
}
void setFontObjectAndInitializeInnerFields(TrueTypeFont fontObject) {
this.fontObject = fontObject;
this.unitsPerEm = this.fontObject.getHeader().getUnitsPerEm();
this.glyphWidths = this.fontObject.getHorizontalMetrics().getAdvanceWidth();
// ---- In a Mono space font program, the length of the AdvanceWidth array must be one.
// ---- According to the TrueType font specification, the Last Value of the AdvanceWidth array
// ---- is apply to the subsequent glyphs. So if the GlyphId is greater than the length of the array
// ---- the last entry is used.
this.numberOfLongHorMetrics = this.fontObject.getHorizontalHeader().getNumberOfHMetrics();
}
void setCMap(CMAPEncodingEntry cmap) {
this.cmap = cmap;
}
@Override
public void checkCID(int cid) throws GlyphException {
if (isAlreadyComputedCid(cid)) {
return;
}
int indexOfWidth = (cid - firstCharInWidthsArray);
float widthProvidedByPdfDictionary = this.defaultGlyphWidth;
float widthInFontProgram ;
int innerFontCid = cid;
if (cmap.getPlatformEncodingId() == 1 && cmap.getPlatformId() == 3) {
try {
Encoding fontEncoding = this.font.getFontEncoding();
String character = fontEncoding.getCharacter(cid);
if (character == null) {
GlyphException e = new GlyphException(ValidationConstants.ERROR_FONTS_GLYPH_MISSING,
cid,
"The character \"" + cid
+ "\" in the font program \""
+ this.font.getBaseFont()
+ "\"is missing from the Charater Encoding.");
addKnownCidElement(new GlyphDetail(cid, e));
throw e;
}
char[] characterArray = character.toCharArray();
if (characterArray.length == 1 ) {
innerFontCid = (int)characterArray[0];
} else {
// TODO OD-PDFA-87 A faire?
innerFontCid = (int)characterArray[0];
for (int i = 1; i < characterArray.length; ++i) {
if (cmap.getGlyphId((int)characterArray[i]) == 0) {
GlyphException e = new GlyphException(ValidationConstants.ERROR_FONTS_GLYPH_MISSING,
cid,
"A glyph for the character \"" + cid
+ "\" in the font program \""
+ this.font.getBaseFont()
+ "\"is missing. There are " + characterArray.length + " glyph used by this character...");
addKnownCidElement(new GlyphDetail(cid, e));
throw e;
}
}
}
} catch (IOException ioe) {
GlyphException e = new GlyphException(ValidationConstants.ERROR_FONTS_ENCODING_IO,
cid,
"Unable to get the encoding object from the PDFont object during the validation of cid \"" + cid
+ "\" in the font program \""
+ this.font.getBaseFont()
+ "\".");
addKnownCidElement(new GlyphDetail(cid, e));
throw e;
}
}
// search glyph
int glyphId = cmap.getGlyphId(innerFontCid);
if (glyphId == 0) {
GlyphException e = new GlyphException(ValidationConstants.ERROR_FONTS_GLYPH_MISSING,
cid,
"Glyph for the character \"" + cid
+ "\" in the font program \""
+ this.font.getBaseFont()
+ "\"is missing.");
addKnownCidElement(new GlyphDetail(cid, e));
throw e;
}
// compute glyph width
float glypdWidth = glyphWidths[numberOfLongHorMetrics - 1];
if (glyphId < numberOfLongHorMetrics) {
glypdWidth = glyphWidths[glyphId];
}
widthInFontProgram = ((glypdWidth * 1000) / unitsPerEm);
// search width in the PDF file
if (indexOfWidth >= 0 && indexOfWidth < this.widthsArray.size()) {
COSInteger w = (COSInteger)this.widthsArray.get(indexOfWidth);
widthProvidedByPdfDictionary = w.intValue();
}
checkWidthsConsistency(cid, widthProvidedByPdfDictionary, widthInFontProgram);
addKnownCidElement(new GlyphDetail(cid));
}
}