com.adobe.fontengine.font.cff.NameKeyedFont Maven / Gradle / Ivy
Show all versions of aem-sdk-api Show documentation
/*
* File: NameKeyedFont.java
*
* ADOBE CONFIDENTIAL
* ___________________
*
* Copyright 2004-2006 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains the property of
* Adobe Systems Incorporated and its suppliers, if any. The intellectual
* and technical concepts contained herein are proprietary to Adobe Systems
* Incorporated and its suppliers and may be covered by U.S. and Foreign
* Patents, patents in process, and are protected by trade secret or
* copyright law. Dissemination of this information or reproduction of this
* material is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*/
/*
* Adobe Patent and/or Adobe Patent Pending invention included within this file:
*
* Adobe patent application tracking # P376,
* entitled 'Method for calculating CJK emboxes in fonts',
* invented by Nathaniel McCully
* Issued US Patent 7,071,941 on July 4, 2006.
*
* Adobe patent application tracking # P376,
* entitled 'A LINE COMPOSITION CONTROLLABLE DTP SYSTEM, A LINE
* COMPOSITION CONTROLLING METHOD, A LINE COMPOSITION CONTROL
* PROGRAM AND A RECORDING MEDIUM STORING THE SAME',
* invented by Nathaniel McCully
* Issued Japanese Patent 3708828 on August 12, 2005.
*
* Adobe patent application tracking # P377,
* entitled 'LINE PREEMPT CONTROLLABLE DTP SYSTEM, A LINE
* PREEMPT CONTROL METHOD, A LINE PREEMPT CONTROL PROGRAM
* AND A RECORDING MEDIUM STORING THE SAME'
* invented by Nathaniel McCully
* Issued Japanese Patent 3598070 on September 17, 2004.
*/
package com.adobe.fontengine.font.cff;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.adobe.fontengine.font.CodePage;
import com.adobe.fontengine.font.Font;
import com.adobe.fontengine.font.InvalidFontException;
import com.adobe.fontengine.font.LineMetrics;
import com.adobe.fontengine.font.Matrix;
import com.adobe.fontengine.font.OrigFontType;
import com.adobe.fontengine.font.OutlineConsumer;
import com.adobe.fontengine.font.PDFFontDescription;
import com.adobe.fontengine.font.Permission;
import com.adobe.fontengine.font.ROS;
import com.adobe.fontengine.font.Rect;
import com.adobe.fontengine.font.Subset;
import com.adobe.fontengine.font.SubsetDefaultImpl;
import com.adobe.fontengine.font.SubsetSimpleTrueType;
import com.adobe.fontengine.font.SubsetSimpleType1;
import com.adobe.fontengine.font.UnsupportedFontException;
import com.adobe.fontengine.font.XDCFontDescription;
import com.adobe.fontengine.font.cff.CFFByteArray.CFFByteArrayBuilder;
import com.adobe.fontengine.font.cff.Dict.Key;
import com.adobe.fontengine.font.cff.Dict.StringValue;
import com.adobe.fontengine.font.postscript.GlyphNamesAccessor;
import com.adobe.fontengine.font.postscript.NameHeuristics;
import com.adobe.fontengine.font.postscript.PostscriptTokenParser;
import com.adobe.fontengine.font.postscript.UnicodeCmap;
/** Represents a name-keyed font.
*/
final public class NameKeyedFont extends CFFFont {
/** Our private Dict
. */
protected final Dict privateDict;
/** Our Charset
. */
protected final Charset charset;
/** Our Encoding
. */
protected final Encoding encoding;
/** Our char strings. */
protected final CharStrings charStrings;
/** Our local subroutines. */
protected final CharStrings localSubrs;
private final XDCFontDescription xdcDescription;
/** Construct a NameKeyedFont
.
* @param stringIndex the StringIndex for this font
* @param globalSubrs the global subroutines for this font
* @param name the name of this font
* @param topDict the top Dict
of this font.
* @param data the underlying bytes from which the structures pointed
* by the top dict will be parsed
* @param digest the digest for the container of this font
*/
public NameKeyedFont (StringIndex stringIndex, CharStrings globalSubrs,
String name, Dict topDict, CFFByteArray data,
byte[] digest)
throws IOException, InvalidFontException, UnsupportedFontException {
super (stringIndex, globalSubrs, topDict, name, digest);
xdcDescription = new NameKeyedFontXDCFontDescription();
//Dict.initDefaultDict();
{ Dict.OffsetValue o = topDict.get (Key.CharStrings, false);
if (o == null) {
throw new InvalidFontException ("missing TopDICT/CharStrings"); }
this.charStrings = new CharStrings (data, o.offset); }
{ int numGlyphs = charStrings.getCount ();
Dict.OffsetValue o = topDict.get (Key.charset, true);
this.charset = new Charset (data, o.offset, numGlyphs); }
{ Dict.OffsetValue o = topDict.get (Key.Encoding, true);
this.encoding = new Encoding (data, o.offset); }
{ Dict privateDict = null;
CharStrings localSubrs = null;
Dict.OffsetSizeValue o = topDict.get (Key.Private, false);
if (o != null) {
privateDict = new Dict (data, o.offset, o.size, stringIndex);
Dict.OffsetValue o2 = privateDict.get (Key.Subrs, false);
if (o2 != null) {
localSubrs = new CharStrings (data, o.offset + o2.offset); }}
this.privateDict = privateDict;
this.localSubrs = localSubrs; }
}
/**
* Create a somewhat lobotimized name keyed font for subsetting a type1 font to CFF
*/
public NameKeyedFont(String fontName, Dict topDict, CharStrings charStrings, Dict privateDict)
throws InvalidFontException, UnsupportedFontException
{
super(null, CharStrings.createEmptyCharstrings(), topDict, fontName, null);
xdcDescription = new NameKeyedFontXDCFontDescription();
this.charStrings = charStrings;
this.privateDict = privateDict;
this.localSubrs = null;
this.encoding = null;
this.charset = null;
//Dict.initDefaultDict();
}
/**
* Create an extended lobotimized name keyed font for subsetting a TrueType font to CFF with subroutines
*/
public NameKeyedFont(String fontName, Dict topDict, CharStrings charStrings, Dict privateDict, CharStrings lSubrs, CharStrings gSubrs)
throws InvalidFontException, UnsupportedFontException
{
super(null, (gSubrs != null) ? gSubrs : CharStrings.createEmptyCharstrings(), topDict, fontName, null);
xdcDescription = new NameKeyedFontXDCFontDescription();
this.charStrings = charStrings;
this.privateDict = privateDict;
this.localSubrs = lSubrs;
this.encoding = null;
this.charset = null;
//Dict.initDefaultDict();
}
//--------------------------------------------------------- general access ---
public int getNumGlyphs () {
return charStrings.getCount ();
}
public int glyphName2gid (String glyphName)
throws InvalidFontException, UnsupportedFontException
{
for (int i = 0; i < getNumGlyphs(); i++)
{
if (glyphName.equals(stringIndex.getString (charset.gid2sid (i))))
return i;
}
return 0;
}
public int charCode2gid (int charCode)
throws InvalidFontException, UnsupportedFontException {
return encoding.charCode2gid (charCode, charset);
}
/** Return the name of glyph gid
.
*/
public String getGlyphName (int gid)
throws InvalidFontException, UnsupportedFontException {
return stringIndex.getString (charset.gid2sid (gid));
}
public ROS getROS () {
return null;
}
public int getGlyphCid (int glyphID) {
return -1;
}
/** Get the outline of glyph gid
.
* @param gid the glyph id of the glyph
* @param consumer the OutlineConsumer to receive the outline
*/
public void getGlyphOutline (int gid, OutlineConsumer consumer)
throws InvalidFontException, UnsupportedFontException {
getOutline (gid, new Type2OutlineParser (false), consumer);
}
/** Get the outline of glyph gid
, using a specified parser.
* @param gid the glyph id of the glyph
* @param parser the Type2OutlineParser parser to use
* @param consumer the OutlineConsumer to receive the outline
*/
public void getOutline (int gid, Type2OutlineParser parser, OutlineConsumer consumer)
throws InvalidFontException, UnsupportedFontException {
parser.parse (charStrings, gid, localSubrs, globalSubrs, consumer, getFontMatrix(), this);
}
public double getStemVForGlyph (int gid) {
Dict.NumbersValue value = privateDict.get(Dict.NumbersKey.StdVW, false);
if (value != null)
return value.getFirstValueAsDouble();
value = privateDict.get(Dict.NumbersKey.StemSnapV, false);
if (value!=null) {
return value.getFirstValueAsDouble(); }
return 0;
}
static class WidthConsumer extends Type2ConsumerDefaultImpl {
public double width;
public boolean widthSeen = false;
public boolean width (double w) {
widthSeen = true;
width = w;
return false; // we had enough
}
}
public double getHorizontalAdvance (int gid)
throws InvalidFontException, UnsupportedFontException {
Type2Parser parser = new Type2Parser ();
WidthConsumer consumer = new WidthConsumer ();
parser.parse (charStrings, gid, localSubrs, globalSubrs, consumer, this);
if (consumer.widthSeen) {
Dict.NumbersValue v = privateDict.get (Dict.Key.nominalWidthX, true);
return v.getFirstValueAsDouble () + consumer.width; }
else {
Dict.NumbersValue v = privateDict.get (Dict.Key.defaultWidthX, true);
return v.getFirstValueAsDouble (); }
}
/** {@inheritDoc} */
public Matrix getFontMatrix () {
return new Matrix (topDict.get (Dict.Key.FontMatrix, true).getValuesAsDouble ());
}
// This matrix allows us to convert point in the font space to the
// metric space.
private Matrix getFontToMetricsMatrix () throws InvalidFontException, UnsupportedFontException {
Matrix m = getFontMatrix ();
double x = getUnitsPerEmX ();
double y = getUnitsPerEmY ();
return new Matrix (x * m.a, y * m.b, x * m.c, y * m.d, x * m.tx, y * m.ty);
}
double getItalicAngle () {
Dict.NumbersValue k = topDict.get(Dict.NumbersKey.ItalicAngle, false);
if (k != null) {
return k.getFirstValueAsDouble(); }
return 0;
}
Rect getRawFontBBox () {
Dict.NumbersValue v = topDict.get (Dict.NumbersKey.FontBBox, false);
if (v != null && v.values.length == 4) {
return new Rect(v.getValuesAsDouble()); }
return null;
}
//----------------------------------------------- line metrics computation ---
public Rect getFontBBox () throws InvalidFontException, UnsupportedFontException {
Rect rawBBox = getRawFontBBox ();
if (rawBBox == null) {
return null; }
return rawBBox.applyMatrix (getFontToMetricsMatrix ());
}
public Rect getCoolTypeRawFontBBox ()
throws InvalidFontException, UnsupportedFontException {
return getFontBBox ();
}
/** Emulates the CoolType API CTFontDict:GetHorizontalMetrics CoolType API.
*
* The metrics are expressed in the design space of the font,
* i.e. they need to be converted through the metrics matrix.
*
*
This methods never returns null.
*
*
See also the {@link #getLineMetrics()} method.
*
* @throws UnsupportedFontException
* @throws InvalidFontException
*/
public LineMetrics getCoolTypeLineMetrics ()
throws UnsupportedFontException, InvalidFontException {
return getCoolTypeLineMetricsFromFontBbox ();
}
public int getFirstChar() throws InvalidFontException, UnsupportedFontException {
synchronized (cmapMutex) {
initCmap();
return cmap.getFirstSupportedChar(); }
}
public int getLastChar() throws InvalidFontException, UnsupportedFontException {
synchronized (cmapMutex) {
initCmap();
return cmap.getLastSupportedChar(); }
}
//------------------------------------------------------------------- cmap ---
boolean isDingbat () {
Dict.StringValue v = topDict.get (Dict.StringKey.FullName, true);
return NameHeuristics.fullNameIndicatesDingbats (v != null ? v.value : null);
}
// The cmap object is constructed once on demand, and is protected
// by the cmapMutex mutex.
UnicodeCmap cmap = null;
Object cmapMutex = new Object ();
private void initCmap() throws InvalidFontException, UnsupportedFontException
{
if (cmap == null) {
cmap = UnicodeCmap.computeCmapFromGlyphNames
(getNumGlyphs (),
isDingbat (),
new GlyphNamesAccessor ()
{ public String getAGlyphName (int gid)
throws UnsupportedFontException, InvalidFontException {
return getGlyphName (gid); }} ); }
}
/** {@inheritDoc} */
public int getGlyphForChar (int usv)
throws InvalidFontException, UnsupportedFontException {
synchronized (cmapMutex) {
initCmap();
return cmap.getGlyphForChar(usv); }
}
//----------------------------------------------------------------------------
int[] getXUID () {
Dict.NumbersValue v = topDict.get(Key.XUID, true);
return v == null ? null: v.getValuesAsInt();
}
String getNotice () {
StringValue value = topDict.get(Key.Notice, true);
return value == null ? null: value.value;
}
String getCopyright() {
StringValue value = topDict.get(Key.Copyright, true);
return value == null ? null: value.value;
}
String getFullName() {
StringValue value = topDict.get(Key.FullName, true);
return value == null ? null: value.value;
}
Integer getFSType () {
return topDict.getFSType();
}
OrigFontType getOrigFontType () {
return topDict.getOrigFontType();
}
double getDefaultWidthForFD (int fd) {
return privateDict.get(Dict.Key.defaultWidthX, true).getFirstValueAsDouble();
}
double getNominalWidthForFD (int fd) {
return privateDict.get(Dict.Key.nominalWidthX, true).getFirstValueAsDouble();
}
int getFDForGlyph (int fullGid) throws InvalidFontException {
return 0;
}
CharStrings getLocalSubrsForFD (int fd) {
return localSubrs;
}
int getNumFDs () {
return 1;
}
CharStrings getCharStrings () {
return charStrings;
}
//----------------------------------------------- subsetting and streaming ---
public Permission getEmbeddingPermission(boolean wasEmbedded) {
return getEmbeddingPermissionGivenFT(wasEmbedded, OrigFontType.kTYPE1);
}
CIDKeyedFont toCID (Subset subset)
throws InvalidFontException, UnsupportedFontException {
Dict.NumbersValue nv;
Dict.StringValue sv;
Map m = new LinkedHashMap (20,1);
m.put (Key.ROS, new Dict.ROSValue ("Adobe", "Identity", 0));
m.put (Key.CIDCount, new Dict.IntegerValue (subset.getNumGlyphs()));
sv = topDict.get (Key.Notice, false);
if (sv != null) {
m.put (Key.Notice, sv); }
sv = topDict.get (Key.FullName, false);
if (sv != null) {
m.put (Key.FullName, sv); }
m.put (Key.FontName, new Dict.StringValue(getName()));
sv = topDict.get (Key.FamilyName, false);
if (sv != null) {
m.put (Key.FamilyName, sv); }
sv = topDict.get (Key.Weight, false);
if (sv != null) {
m.put (Key.Weight, sv); }
nv = topDict.get (Key.FontBBox, false);
if (nv != null) {
m.put (Key.FontBBox, nv); }
sv = topDict.get (Key.Copyright, false);
if (sv != null) {
m.put (Key.Copyright, sv); }
nv = topDict.get (Key.isFixedPitch, false);
if (nv != null) {
m.put (Key.isFixedPitch, nv); }
nv = topDict.get (Key.ItalicAngle, false);
if (nv != null) {
m.put (Key.ItalicAngle, nv); }
nv = topDict.get (Key.UnderlinePosition, false);
if (nv != null) {
m.put (Key.UnderlinePosition, nv); }
nv = topDict.get (Key.UnderlineThickness, false);
if (nv != null) {
m.put (Key.UnderlineThickness, nv); }
nv = topDict.get (Key.PaintType, false);
if (nv != null) {
m.put (Key.PaintType, nv); }
nv = topDict.get (Key.CharstringType, false);
if (nv != null) {
m.put (Key.CharstringType, nv); }
nv = topDict.get (Key.StrokeWidth, false);
if (nv != null) {
m.put (Key.StrokeWidth, nv); }
sv = topDict.get (Key.PostScript, false);
if (sv != null) {
OrigFontType oft = PostscriptTokenParser.getOrigFontType(sv.value);
if (oft != null) {
m.put (Key.PostScript, sv); }
else {
m.put(Key.PostScript, new Dict.StringValue("/OrigFontType /Type1 def " + sv.value)); }}
else {
m.put (Key.PostScript, new Dict.StringValue("/OrigFontType /Type1 def")); }
nv = topDict.get (Key.CIDFontType, false);
if (nv != null) {
m.put (Key.CIDFontType, nv); }
nv = topDict.get (Key.UIDBase, false);
if (nv != null) {
m.put (Key.UIDBase, nv); }
Dict CIDtopDict = new Dict (m);
m = new LinkedHashMap ();
nv = topDict.get (Key.FontMatrix, false);
if (nv != null) {
m.put (Key.FontMatrix, nv); }
Dict CIDfontDict = new Dict (m);
// we simply use our privateDict for the component privateDict
CIDComponentFont [] components = new CIDComponentFont [1];
components [0] = new CIDComponentFont (CIDfontDict, privateDict, null);
return new CIDKeyedFont (null /*stringIndex, not used in this font*/,
null, name, CIDtopDict, this.createSubsetCharstringIndex(subset, false),
Charset.identityCharset(subset.getNumGlyphs()),
components,
FdSelect.singleFont(subset.getNumGlyphs()));
}
/** Subset and stream this font for PDF use.
* The stream is a CID-keyed CFF stream.
* @param out the OutputStream to which the bytes are streamed
*/
public void subsetAndStream (Subset subset, OutputStream out, boolean preserveROS, Integer fsType)
throws InvalidFontException, UnsupportedFontException, IOException {
toCID(subset).subsetAndStream (new SubsetDefaultImpl(subset.getNumGlyphs(), false), out, false, fsType);
}
/**
* Added new subsetAndStream method as part of changes to force DF4 output to be Identity-CID always.
*/
public void subsetAndStream(Subset subset, OutputStream out, boolean preserveROS, Integer fsType, boolean enableSubrizer)
throws InvalidFontException, UnsupportedFontException, IOException
{
toCID(subset).subsetAndStream(new SubsetDefaultImpl(subset.getNumGlyphs(), false), out, false, fsType, enableSubrizer);
}
final static Key[] topDictKeysForSubset = {
Key.Notice,
Key.FullName,
Key.FamilyName,
Key.FontName,
Key.BaseFontName,
Key.BaseFontBlend,
Key.Weight,
Key.FontBBox,
Key.Copyright,
Key.isFixedPitch,
Key.ItalicAngle,
Key.UnderlinePosition,
Key.UnderlineThickness,
Key.PaintType,
Key.CharstringType,
Key.StrokeWidth,
Key.UniqueID,
Key.XUID,
Key.UIDBase,
Key.FontMatrix
};
final static Key[] privateDictKeysForSubset = {
Key.BlueValues,
Key.OtherBlues,
Key.FamilyBlues,
Key.FamilyOtherBlues,
Key.StdHW,
Key.StdVW,
Key.defaultWidthX,
Key.nominalWidthX,
Key.BlueScale,
Key.BlueShift,
Key.BlueFuzz,
Key.StemSnapH,
Key.StemSnapV,
Key.ForceBold,
Key.ForceBoldThreshold,
Key.LanguageGroup,
Key.ExpansionFactor,
Key.initialRandomSeed
};
private void setPSString(CFFByteArrayBuilder bb, Integer fsType, List strings)
{
String psString = null;
if (fsType == null)
fsType = topDict.getFSType();
if (fsType != null)
psString = "/FSType " + fsType.toString() + " def ";
OrigFontType oft = topDict.getOrigFontType();
if (oft != null) {
if (psString != null)
psString = psString + " /OrigFontType /" + oft.toString() + " def";
else
psString = "/OrigFontType /" + oft.toString() + " def";
}
if (psString != null) {
if (strings.indexOf(psString) == -1)
strings.add(psString);
Dict.streamKeyVal(bb, Key.PostScript, psString, strings);
}
}
public static abstract class GlyphNameFetcher {
public abstract String getGlyphName(Subset s, int i);
}
public void stream(OutputStream out, Integer fsType)
throws InvalidFontException, UnsupportedFontException, IOException
{
Subset subset = new SubsetDefaultImpl(getNumGlyphs(), false);
subsetAndStream(subset, out, fsType, false, null);
}
public void stream(OutputStream out, Integer fsType, GlyphNameFetcher fetcher)
throws InvalidFontException, UnsupportedFontException, IOException
{
Subset subset = new SubsetDefaultImpl(getNumGlyphs(), false);
subsetAndStream(subset, out, fsType, false, fetcher);
}
/**
* Builds up an array that maps glyphIDs to string ids. If a glyphname isn't in
* the strings list, buildCharsetData creates adds it to the list.
*/
private int[] buildCharsetData(Subset subset, GlyphNameFetcher fetcher, List strings)
throws InvalidFontException, UnsupportedFontException
{
int[] glyphSids = null;
glyphSids = new int[subset.getNumGlyphs()];
for (int i = 0; i < glyphSids.length; i++) {
String glyphName;
if (fetcher == null)
{
int fullGid = subset.getFullGid(i);
glyphName = getGlyphName(fullGid);
}
else
glyphName = fetcher.getGlyphName(subset, i);
int sid = strings.indexOf(glyphName);
if (sid < 0) {
strings.add(glyphName); // Glyph name not on strings list
sid = strings.size() - 1; // Assign new SID
}
glyphSids[i] = sid;
}
return glyphSids;
}
private static final int MAX_CFF_SIZE_FOR_SUBRIZE = 614400;
private boolean checkSubrizeLimit(Subset subset)
throws InvalidFontException, UnsupportedFontException
{
int cffSize = charStrings.data.getSize();;
if (cffSize <= MAX_CFF_SIZE_FOR_SUBRIZE)
return true;
if (subset == null)
return false;
if ((double)cffSize * subset.getNumGlyphs() <= (double)MAX_CFF_SIZE_FOR_SUBRIZE * getNumGlyphs())
return true;
return false;
}
/**
* Create a subset name-keyed cff based on the given parameters
* @param subset The set of glyphs to include in the subset
* @param out The OutputStream to which we will write the new font
* @param fsType The fsType to include in the new font
* @param rebuildCharstrings Tells if the charstrings in the current font already take into account the Subset. If they do, then we don't need to recreate
* the charstrings. Otherwise, we do.
* @param fetcher Provides a way to get from gid to glyphName for cases where there is no charset (for example, because this NameKeyedFont
* is a temporary font converted from Type1). Can be null if this's charset and string index are valid.
* @throws InvalidFontException
* @throws UnsupportedFontException
* @throws IOException
*/
public void subsetAndStream(Subset subset, OutputStream out, Integer fsType, boolean rebuildCharstrings, GlyphNameFetcher fetcher)
throws InvalidFontException, UnsupportedFontException, IOException
{
subsetAndStream(subset, out, fsType, rebuildCharstrings, fetcher, false);
}
public void subsetAndStream(Subset subset, OutputStream out, Integer fsType, boolean rebuildCharstrings, GlyphNameFetcher fetcher, boolean enableSubrizer)
throws InvalidFontException, UnsupportedFontException, IOException
{
List strings = StringIndex.collectPredefinedStrings(); // Base strings set
int[] glyphSids = null; // Subset GIDs to SIDs
glyphSids = buildCharsetData(subset, fetcher, strings);
topDict.collectStrings(strings); // Add strings from topDict
Dict.StringValue val;
if ((val = topDict.get(Dict.StringKey.PostScript, false)) != null) {
strings.remove(strings.indexOf(val.value)); // Toss current PostScript string if any
}
CFFByteArrayBuilder bb = CFFByteArray.getCFFByteArrayBuilderInstance(); // Our byte array object
Header.toBinary(bb); // Output the header
NameIndex.toBinary(bb, name); // Output font name index
Index.Cursor cursor = Index.startIndex(bb, 1); // Start of topDict index
topDict.stream(bb, strings, topDictKeysForSubset); // Output the main body of topDict
setPSString(bb, fsType, strings); // Output the PostScript string
int charsetMarker = Key.charset.streamDummyValue(bb); // Output dummy charset pointer
int charStringsMarker = Key.CharStrings.streamDummyValue(bb); // Output dummy CharStrings pointer
int privateMarker = Key.Private.streamDummyValue(bb); // Output dummy PrivateDict size and pointer
cursor = Index.elementEntered(bb, cursor); // End of topDict index
StringIndex.toBinary(bb, strings); // Output string index
CharStrings subsetCharstrings = null;
CharStrings lSubrStrings = null;
CharStrings gSubrStrings = null;
if (rebuildCharstrings) {
if (enableSubrizer)
enableSubrizer = checkSubrizeLimit(subset);
subsetCharstrings = createSubsetCharstringIndex(subset, enableSubrizer);
if (enableSubrizer) {
CFFSubrize subrizer = new CFFSubrize();
subsetCharstrings = subrizer.subrize(subsetCharstrings);
lSubrStrings = subrizer.getLSubrs();
gSubrStrings = subrizer.getGSubrs();
if (gSubrStrings == null)
gSubrStrings = CharStrings.createEmptyCharstrings();
gSubrStrings.stream(bb);
} else {
bb.addCard16(0);
}
} else {
subsetCharstrings = this.charStrings;
globalSubrs.stream(bb); // otherwise, copy global subrs to the result because the existing charstrings may use them.
}
Key.charset.fixOffset(bb, charsetMarker, bb.getSize()); // Start of charset
Charset.streamCharSet(bb, glyphSids); // Output charset
Key.CharStrings.fixOffset(bb, charStringsMarker, bb.getSize()); // Start of CharStrings
subsetCharstrings.stream(bb); // Output resulting subset
int start = bb.getSize();
Key.Private.fixOffset(bb, privateMarker, start); // Start of PrivateDict
privateDict.stream(bb, strings, privateDictKeysForSubset); // Output PrivateDict
int localSubrsMarker = 0;
if ((rebuildCharstrings && lSubrStrings != null) || (!rebuildCharstrings && localSubrs != null)) {
localSubrsMarker = Key.Subrs.streamDummyValue(bb);
} // write local subrs offset in the private dict
Key.Private.fixSize(bb, privateMarker, bb.getSize() - start); // Fix up PrivateDict size
if ((rebuildCharstrings && lSubrStrings != null) || (!rebuildCharstrings && localSubrs != null)) {
Key.Subrs.fixOffset (bb, localSubrsMarker, bb.getSize() - start);
if (rebuildCharstrings)
lSubrStrings.stream(bb);
else
localSubrs.stream(bb);
}
CFFByteArray byteArray = bb.toCFFByteArray(); // Generate byte array
byteArray.write(out); // And write it out
}
private class NameKeyedFontXDCFontDescription extends CFFFontXDCFontDescription {
public void subsetAndStream(Subset subset, OutputStream out, boolean preserveROS)
throws InvalidFontException, UnsupportedFontException, IOException
{
NameKeyedFont.this.subsetAndStream(subset, out, preserveROS);
}
public void subsetAndStream(SubsetSimpleType1 t1Subset, OutputStream out)
throws InvalidFontException, UnsupportedFontException, IOException
{
NameKeyedSubset subset = (NameKeyedSubset)NameKeyedFont.this.createSubset();
subset.addGlyphs(NameKeyedFont.this, t1Subset.getGlyphNames());
NameKeyedFont.this.subsetAndStream(subset, out, getFSType(), true, null);
}
public void subsetAndStream(SubsetSimpleTrueType ttSubset, OutputStream out)
throws UnsupportedFontException
{
throw new UnsupportedFontException("Not a TrueType font");
}
public void stream(OutputStream out, boolean openTypeOK)
throws InvalidFontException, UnsupportedFontException, IOException
{
NameKeyedFont.this.stream(out, null);
}
public CodePage[] getXDCCodePages()
throws InvalidFontException, UnsupportedFontException
{
HashSet codePageSet = new HashSet();
if (glyphName2gid("ecircumflex") > 0)
codePageSet.add(CodePage.ROMAN1);
if (glyphName2gid("Ccaron") > 0 || glyphName2gid("ncaron") > 0)
codePageSet.add(CodePage.ROMAN2);
if (glyphName2gid("akatakana") > 0)
codePageSet.add(CodePage.JAPANESE);
CodePage[] retVal = new CodePage[codePageSet.size()];
Iterator iter = codePageSet.iterator();
int index = 0;
while (iter.hasNext())
retVal[index++] = (CodePage)iter.next();
return retVal;
}
public int getCIDCount()
{
return -1;
}
}
public PDFFontDescription getPDFFontDescription(Font font)
throws UnsupportedFontException, InvalidFontException
{
return xdcDescription;
}
public XDCFontDescription getXDCFontDescription(Font font)
throws UnsupportedFontException, InvalidFontException
{
return xdcDescription;
}
/** Create a subset for this font. */
public Subset createSubset() throws InvalidFontException, UnsupportedFontException {
Subset s = new NameKeyedSubset(getNumGlyphs (), true);
s.getSubsetGid(0); // add notdef
return s;
}
}