in fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java [550:713]
private CFFFont parseFont(DataInput input, String name, byte[] topDictIndex) throws IOException
{
// top dict
DataInputByteArray topDictInput = new DataInputByteArray(topDictIndex);
DictData topDict = readDictData(topDictInput);
// we don't support synthetic fonts
DictData.Entry syntheticBaseEntry = topDict.getEntry("SyntheticBase");
if (syntheticBaseEntry != null)
{
throw new IOException("Synthetic Fonts are not supported");
}
// determine if this is a Type 1-equivalent font or a CIDFont
CFFFont font;
CFFCIDFont cffCIDFont = parseROS(topDict);
// determine if this is a Type 1-equivalent font or a CIDFont
boolean isCIDFont = cffCIDFont != null;
if (cffCIDFont != null)
{
font = cffCIDFont;
}
else
{
font = new CFFType1Font();
}
// name
debugFontName = name;
font.setName(name);
// top dict
font.addValueToTopDict("version", getString(topDict, "version"));
font.addValueToTopDict("Notice", getString(topDict, "Notice"));
font.addValueToTopDict("Copyright", getString(topDict, "Copyright"));
font.addValueToTopDict("FullName", getString(topDict, "FullName"));
font.addValueToTopDict("FamilyName", getString(topDict, "FamilyName"));
font.addValueToTopDict("Weight", getString(topDict, "Weight"));
font.addValueToTopDict("isFixedPitch", topDict.getBoolean("isFixedPitch", false));
font.addValueToTopDict("ItalicAngle", topDict.getNumber("ItalicAngle", 0));
font.addValueToTopDict("UnderlinePosition", topDict.getNumber("UnderlinePosition", -100));
font.addValueToTopDict("UnderlineThickness", topDict.getNumber("UnderlineThickness", 50));
font.addValueToTopDict("PaintType", topDict.getNumber("PaintType", 0));
font.addValueToTopDict("CharstringType", topDict.getNumber("CharstringType", 2));
font.addValueToTopDict("FontMatrix", topDict.getArray("FontMatrix", List.of(
0.001, 0.0, 0.0, 0.001,
0.0, 0.0)));
font.addValueToTopDict("UniqueID", topDict.getNumber("UniqueID", null));
font.addValueToTopDict("FontBBox", topDict.getArray("FontBBox",
List.of(0, 0, 0, 0)));
font.addValueToTopDict("StrokeWidth", topDict.getNumber("StrokeWidth", 0));
font.addValueToTopDict("XUID", topDict.getArray("XUID", null));
// charstrings index
DictData.Entry charStringsEntry = topDict.getEntry("CharStrings");
if (charStringsEntry == null || !charStringsEntry.hasOperands())
{
throw new IOException("CharStrings is missing or empty");
}
int charStringsOffset = charStringsEntry.getNumber(0).intValue();
input.setPosition(charStringsOffset);
byte[][] charStringsIndex = readIndexData(input);
// charset
DictData.Entry charsetEntry = topDict.getEntry("charset");
CFFCharset charset;
if (charsetEntry != null && charsetEntry.hasOperands())
{
int charsetId = charsetEntry.getNumber(0).intValue();
if (!isCIDFont && charsetId == 0)
{
charset = CFFISOAdobeCharset.getInstance();
}
else if (!isCIDFont && charsetId == 1)
{
charset = CFFExpertCharset.getInstance();
}
else if (!isCIDFont && charsetId == 2)
{
charset = CFFExpertSubsetCharset.getInstance();
}
else if (charStringsIndex.length > 0)
{
input.setPosition(charsetId);
charset = readCharset(input, charStringsIndex.length, isCIDFont);
}
// that should not happen
else
{
LOG.debug("Couldn't read CharStrings index - returning empty charset instead");
charset = new EmptyCharsetType1();
}
}
else
{
if (isCIDFont)
{
// a CID font with no charset does not default to any predefined charset
charset = new EmptyCharsetCID(charStringsIndex.length);
}
else
{
charset = CFFISOAdobeCharset.getInstance();
}
}
font.setCharset(charset);
// charstrings dict
font.charStrings = charStringsIndex;
// format-specific dictionaries
if (isCIDFont)
{
// CharStrings index could be null if the index data couldn't be read
int numEntries = 0;
if (charStringsIndex.length == 0)
{
LOG.debug("Couldn't read CharStrings index - parsing CIDFontDicts with number of char strings set to 0");
}
else
{
numEntries = charStringsIndex.length;
}
parseCIDFontDicts(input, topDict, (CFFCIDFont) font, numEntries);
List<Map<String, Object>> fontDicts = ((CFFCIDFont) font).getFontDicts();
List<Number> privMatrix = null;
if (!fontDicts.isEmpty())
{
privMatrix = (List<Number>) fontDicts.get(0).getOrDefault("FontMatrix", null);
}
// some malformed fonts have FontMatrix in their Font DICT, seePDFBOX-2495
List<Number> matrix = topDict.getArray("FontMatrix", null);
if (matrix == null)
{
if (privMatrix != null)
{
font.addValueToTopDict("FontMatrix", privMatrix);
}
else
{
// default
font.addValueToTopDict("FontMatrix", topDict.getArray("FontMatrix",
List.of(0.001, 0.0, 0.0, 0.001, 0.0, 0.0)));
}
}
else if (privMatrix != null)
{
// we have to multiply the font matrix from the top directory with the font matrix
// from the private directory. This should be done for synthetic fonts only but in
// case of PDFBOX-3579 it's needed as well to get the right scaling
concatenateMatrix(matrix, privMatrix);
}
}
else
{
parseType1Dicts(input, topDict, (CFFType1Font) font, charset);
}
return font;
}