com.adobe.fontengine.font.cff.CIDKeyedFont Maven / Gradle / Ivy
Show all versions of aem-sdk-api Show documentation
/*
* File: CIDKeyedFont.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.List;
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.ROSValue;
import com.adobe.fontengine.font.cff.Dict.StringValue;
import com.adobe.fontengine.font.postscript.UnicodeCmap;
/** Represents a CID-keyed font.
*/
final public class CIDKeyedFont extends CFFFont {
/** Our charstrings. */
protected final CharStrings charStrings;
/** Our charset, which maps gids to CIDs. */
protected final Charset charset;
/** Our FdSelect
. */
protected final FdSelect fdSelect;
/** Our CIDComponentFont
s. */
protected final CIDComponentFont[] components;
private final XDCFontDescription xdcDescription;
/** Create a subset for this font. */
public Subset createSubset() throws InvalidFontException, UnsupportedFontException {
Subset s = new SubsetDefaultImpl (getNumGlyphs (), true);
s.getSubsetGid(0); // add notdef
return s;
}
/** Construct a CIDKeyedFont
.
* @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
*/
CIDKeyedFont (StringIndex stringIndex,
CharStrings globalSubrs, String name, Dict topDict,
CFFByteArray data, byte[] digest)
throws InvalidFontException, UnsupportedFontException {
super (stringIndex, globalSubrs, topDict, name, digest);
xdcDescription = new CIDKeyedFontXDCFontDescription();
{ Dict.OffsetValue o = topDict.get (Dict.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 (Dict.Key.charset, false);
if (o != null) {
this.charset = new Charset (data, o.offset, numGlyphs); }
else {
this.charset = new Charset (null, -1, 0); }}
{ CIDComponentFont[] components = null;
Dict.OffsetValue o = topDict.get (Dict.Key.FDArray, false);
if (o != null) {
Index fontDictIndex = new Index (data, o.offset);
components = new CIDComponentFont [fontDictIndex.getCount ()];
for (int i = 0; i < components.length; i++) {
components [i] = new CIDComponentFont (data,
fontDictIndex.offsetOf (i),
fontDictIndex.sizeOf (i),
stringIndex); }}
this.components = components; }
{ FdSelect fdSelect = null;
Dict.OffsetValue v = topDict.get (Dict.Key.FDSelect, false);
if (v != null) {
fdSelect = new FdSelect (data, v.offset, numGlyphs); }
this.fdSelect = fdSelect; }
}
CIDKeyedFont (StringIndex stringIndex, CharStrings globalSubrs, String name, Dict topDict,
CharStrings charStrings, Charset charset, CIDComponentFont[] components, FdSelect fdSelect)
throws UnsupportedFontException, InvalidFontException
{
super (stringIndex, globalSubrs, topDict, name, null);
xdcDescription = new CIDKeyedFontXDCFontDescription();
this.charStrings = charStrings;
this.charset = charset;
this.components = (components.clone ());
this.fdSelect = fdSelect;
}
public CIDKeyedFont (String name, Dict topDict,
CharStrings charStrings, int numGlyphs,
Dict ciddict, Dict privateDict)
throws InvalidFontException, UnsupportedFontException {
super (null, CharStrings.createEmptyCharstrings(), topDict, name, null);
xdcDescription = new CIDKeyedFontXDCFontDescription();
CIDComponentFont [] components = new CIDComponentFont[1];
components[0] = new CIDComponentFont (ciddict,
privateDict,
CharStrings.createEmptyCharstrings());
this.charStrings = charStrings;
this.charset = Charset.identityCharset (numGlyphs);
this.components = components;
this.fdSelect = FdSelect.singleFont (numGlyphs);
}
/**
* This constructor is called from Glyf.subsetAndStreamForCFF
* and is by the new TT->CFF-IdentityCID code for DF4.
*/
public CIDKeyedFont(String name, Dict topDict, CharStrings charStrings, int numGlyphs, Dict cidDict, Dict privateDict, CharStrings lSubrs, CharStrings gSubrs)
throws InvalidFontException, UnsupportedFontException
{
super(null, gSubrs, topDict, name, null);
xdcDescription = new CIDKeyedFontXDCFontDescription();
CIDComponentFont[] components = new CIDComponentFont[1];
components[0] = new CIDComponentFont(cidDict, privateDict, lSubrs);
this.charStrings = charStrings;
this.charset = Charset.identityCharset(numGlyphs);
this.components = components;
this.fdSelect = FdSelect.singleFont(numGlyphs);
}
//--------------------------------------------------------- general access ---
public int getNumGlyphs () {
return charStrings.getCount ();
}
/** Return the name of glyph gid
.
* Since glyphs in CID-keyed font don't have names, we return null.
*/
public String getGlyphName (int gid) {
return null;
}
public ROS getROS() {
return topDict.getROS();
}
public int getCIDCount()
{
return topDict.get(Dict.Key.CIDCount, true).value;
}
/** Return the CID of the glyph gid
.
*/
public int getGlyphCid (int gid)
throws InvalidFontException, UnsupportedFontException {
return charset.gid2sid (gid);
}
public int cid2gid (int cid)
throws InvalidFontException, UnsupportedFontException {
return charset.sid2gid (cid);
}
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();
}
/** 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 {
if (topDict.get(Dict.Key.CharstringType, true).getFirstValueAsDouble() == 2)
getOutline (gid, new Type2OutlineParser (false), consumer);
else
throw new InvalidFontException("Unsupported Charstring type");
}
/** 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
*/
/** Return the outline of glyph gid
.
*/
public void getOutline (int gid, Type2OutlineParser parser, OutlineConsumer consumer)
throws InvalidFontException, UnsupportedFontException {
components [fdSelect.componentOf (gid)].getOutline (charStrings, gid,
globalSubrs, parser, consumer, topDict.get (Dict.Key.FontMatrix, false));
}
public double getStemVForGlyph (int gid)
throws InvalidFontException {
return components [fdSelect.componentOf (gid)].getStemV();
}
public Matrix getFontMatrix () {
return new Matrix (topDict.get (Dict.Key.FontMatrix, true).getValuesAsDouble ());
}
/**
* Allows recover of concatenated font matrix from a CID component.
*/
public Matrix getFontMatrix(int component)
{
Dict.NumbersValue topMatrix = topDict.get(Dict.Key.FontMatrix, false);
Matrix matrix;
if (component >= 0 && component < components.length)
matrix = components[component].getOutlineMatrix(topMatrix);
else
matrix = new Matrix(topMatrix.getValuesAsDouble());
return matrix;
}
// 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);
}
/** {@inheritDoc} */
public double getHorizontalAdvance (int gid)
throws InvalidFontException, UnsupportedFontException {
return components [fdSelect.componentOf (gid)].getHorizontalAdvance (charStrings, gid, globalSubrs);
}
double getItalicAngle () {
Dict.NumbersValue v = topDict.get(Dict.NumbersKey.ItalicAngle, false);
if (v != null) {
return v.getFirstValueAsDouble (); }
return 0;
}
public 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 ---
private double getCoolTypeLineGapForCJK ()
throws UnsupportedFontException, InvalidFontException {
return getUnitsPerEmY () / 2;
}
private LineMetrics getCoolTypeLineMetricsFromTypicalCharacters (double linegap)
throws UnsupportedFontException, InvalidFontException {
int dGid = getCoolTypeGlyphForChar ('d');
int pGid = getCoolTypeGlyphForChar ('p');
if (dGid != 0 && pGid != 0) {
double ascender = getGlyphBBox (dGid).ymax;
double descender = getGlyphBBox (pGid).ymin;
if (descender < ascender) {
return new LineMetrics (ascender, descender, linegap); }}
return null;
}
private LineMetrics getCoolTypeLineMetricsFromICFBox (double linegap)
throws UnsupportedFontException, InvalidFontException {
Rect icfBox = getCoolTypeIcfBox ();
return new LineMetrics (icfBox.ymax, icfBox.ymax - getUnitsPerEmY (), linegap);
}
public Rect getFontBBox () throws InvalidFontException, UnsupportedFontException {
Rect rawBBox = getRawFontBBox ();
if (rawBBox == null) {
return null; }
return rawBBox.applyMatrix (getFontToMetricsMatrix ());
}
protected 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 {
LineMetrics lm;
if (useCoolTypeCJKHeuristics ()) {
double linegap = getCoolTypeLineGapForCJK ();
if ((lm = getCoolTypeLineMetricsFromTypicalCharacters (linegap)) != null) {
return lm; }
return getCoolTypeLineMetricsFromICFBox (linegap); }
return getCoolTypeLineMetricsFromFontBbox ();
}
//------------------------------------------------------------------- cmap ---
// The cmap object is constructed once on demand, and is protected
// by the cmapMutex mutex.
UnicodeCmap cmap = null;
Object cmapMutex = new Object ();
public int getFirstChar() throws InvalidFontException, UnsupportedFontException {
synchronized (cmapMutex) {
initCmap();
return cmap.getFirstSupportedChar(); }
}
public int getLastChar() throws InvalidFontException, UnsupportedFontException {
synchronized (cmapMutex) {
initCmap();
return cmap.getLastSupportedChar(); }
}
private void initCmap() throws InvalidFontException, UnsupportedFontException {
if (cmap == null) {
ROSValue ros = topDict.get (Dict.ROSKey.ROS, true);
cmap = UnicodeCmap.computeCmapFromCids
(getNumGlyphs (),
new UnicodeCmap.GlyphCidAccessor ()
{ public int getAGlyphCid (int gid)
throws UnsupportedFontException, InvalidFontException {
return charset.gid2sid (gid); }},
ros.ros.registry, ros.ros.ordering); }
}
/** {@inheritDoc} */
public int getGlyphForChar (int usv)
throws InvalidFontException, UnsupportedFontException {
synchronized (cmapMutex) {
initCmap();
return cmap.getGlyphForChar(usv); }
}
//----------------------------------------------- subsetting and streaming ---
public Permission getEmbeddingPermission(boolean wasEmbedded)
{
return getEmbeddingPermissionGivenFT(wasEmbedded, OrigFontType.kCID);
}
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.CIDFontType};
final static Key[] fontDictKeysForSubset = {
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};
int getNumFDs() {
return components.length;
}
CharStrings getCharStrings() {
return charStrings;
}
CharStrings getLocalSubrsForFD(int fd) {
return components[fd].localSubrs;
}
double getDefaultWidthForFD(int fd) {
return this.components[fd].privateDict.get(Dict.NumbersKey.defaultWidthX, true).getFirstValueAsDouble();
}
double getNominalWidthForFD(int fd) {
return this.components[fd].privateDict.get(Dict.NumbersKey.nominalWidthX, true).getFirstValueAsDouble();
}
int getFDForGlyph(int fullGid)
throws InvalidFontException {
return this.fdSelect.componentOf(fullGid);
}
/** Modify cidcount and stream it to the new top dict. */
private void setCIDCount(boolean preserveROS,
CFFByteArrayBuilder bb,
Subset subset,
boolean doSubset,
List strings)
throws InvalidFontException, UnsupportedFontException {
if (!preserveROS) {
Dict.streamKeyVal (bb, Key.CIDCount, subset.getNumGlyphs ()); }
else if (doSubset) {
int maxcid = -1;
for (int i = 0; i < subset.getNumGlyphs(); i++) {
int fullGid = subset.getFullGid(i);
int cid = charset.gid2sid(fullGid);
if (cid > maxcid) {
maxcid = cid; }}
Dict.streamKeyVal(bb, Key.CIDCount, maxcid+1); }
else {
topDict.streamValue(bb, strings, Key.CIDCount); }
}
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); }
}
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;
}
public void subsetAndStream(Subset subset, OutputStream out, boolean preserveROS, Integer fsType)
throws InvalidFontException, UnsupportedFontException, IOException
{
subsetAndStream(subset, out, preserveROS, fsType, false, true);
}
public void subsetAndStream(Subset subset, OutputStream out, boolean preserveROS, Integer fsType, boolean enableSubrizer)
throws InvalidFontException, UnsupportedFontException, IOException
{
subsetAndStream(subset, out, preserveROS, fsType, enableSubrizer, true);
}
/**
* Added yet another boolean to make this code serve on the new TT->CFF-IdentityCID path for DF4.
* TODO: The addition of the "rebuildCharstrings" boolean makes this code too ugly and complicated
* to be left like this. It needs to be re-worked, somehow.
*/
public void subsetAndStream(Subset subset, OutputStream out, boolean preserveROS, Integer fsType, boolean enableSubrizer, boolean rebuildCharstrings)
throws InvalidFontException, UnsupportedFontException, IOException
{
// if we aren't subsetting, don't modify the charstrings at all.
boolean doSubset = !(subset instanceof SubsetDefaultImpl) || ((SubsetDefaultImpl)subset).doSubset() || enableSubrizer;
List /**/ strings = StringIndex.collectPredefinedStrings();
topDict.collectStrings(strings);
// don't put the postscript string in the strings list. It will be generated later.
Dict.StringValue val;
if ((val = topDict.get(Dict.StringKey.PostScript, false)) != null) {
strings.remove(strings.indexOf(val.value));
}
for (int i = 0; i < components.length; i++) {
components [i].collectStrings(strings);
}
CFFByteArrayBuilder bb = CFFByteArray.getCFFByteArrayBuilderInstance();
Header.toBinary(bb);
NameIndex.toBinary(bb, name);
// TOP DICT INDEX
Index.Cursor cursor = Index.startIndex(bb, 1);
if (preserveROS || !rebuildCharstrings) {
topDict.streamValue(bb, strings, Key.ROS);
} else {
ROSValue ros = new ROSValue("Adobe", "Identity", 1);
ros.collectStrings(strings);
ros.stream(bb, strings);
Key.ROS.stream(bb);
}
topDict.stream(bb, strings, topDictKeysForSubset);
setCIDCount(preserveROS, bb, subset, doSubset, strings);
setPSString(bb, fsType, strings);
int fdArrayMarker = Key.FDArray.streamDummyValue(bb);
int fdSelectMarker = Key.FDSelect.streamDummyValue(bb);
int predefinedCharset = charset.predefinedOffset();
int charsetMarker;
if (doSubset || !preserveROS) {
charsetMarker = Key.charset.streamDummyValue(bb);
} else {
if (predefinedCharset != -1) {
new Dict.IntegerValue(predefinedCharset).stream(bb, null);
charsetMarker = -1;
} else {
charsetMarker = Key.charset.streamDummyValue(bb);
}
}
int charStringsMarker = Key.CharStrings.streamDummyValue(bb);
cursor = Index.elementEntered(bb, cursor);
StringIndex.toBinary(bb, strings);
CFFSubrize subrizer = null;
CharStrings subsetCharstrings = null;
CharStrings gSubrStrings = null;
if (!doSubset || !rebuildCharstrings) {
if (globalSubrs != null) {
globalSubrs.stream(bb);
} else {
bb.addCard16(0);
}
} else {
if (enableSubrizer)
enableSubrizer = checkSubrizeLimit(subset);
subsetCharstrings = createSubsetCharstringIndex(subset, enableSubrizer);
if (enableSubrizer) {
byte fdIndex[] = new byte[subset.getNumGlyphs()];
for (int i = 0; i < subset.getNumGlyphs(); i++)
fdIndex[i] = (byte)getFDForGlyph(subset.getFullGid(i));
subrizer = new CFFSubrize();
subsetCharstrings = subrizer.subrize(subsetCharstrings, fdIndex);
gSubrStrings = subrizer.getGSubrs();
if (gSubrStrings == null)
gSubrStrings = CharStrings.createEmptyCharstrings();
gSubrStrings.stream(bb);
} else {
bb.addCard16(0);
}
}
Key.FDArray.fixOffset(bb, fdArrayMarker, bb.getSize());
int [] privateMarkers = new int [components.length];
cursor = Index.startIndex(bb, components.length);
for (int i = 0; i < components.length; i++) {
components [i].fontDict.stream(bb, strings, fontDictKeysForSubset);
privateMarkers [i] = Key.Private.streamDummyValue(bb);
cursor = Index.elementEntered(bb, cursor);
}
// XXX_lmb optimization: remove unneeded components.
for (int i = 0; i < components.length; i++) {
CharStrings lSubrStrings = null;
if (subrizer != null) {
lSubrStrings = subrizer.getLSubrs(i);
if (lSubrStrings == null) {
lSubrStrings = CharStrings.createEmptyCharstrings();
}
}
Key.Private.fixOffset(bb, privateMarkers [i], bb.getSize());
int start = bb.getSize();
components [i].privateDict.stream(bb, strings, privateDictKeysForSubset);
int localSubrsMarker = 0;
if (lSubrStrings != null || ((!doSubset || !rebuildCharstrings) && components [i].localSubrs != null)) {
localSubrsMarker = Key.Subrs.streamDummyValue(bb);
}
int size = bb.getSize() - start;
Key.Private.fixSize(bb, privateMarkers [i], size);
if (lSubrStrings != null || ((!doSubset || !rebuildCharstrings) && components [i].localSubrs != null)) {
Key.Subrs.fixOffset(bb, localSubrsMarker, bb.getSize() - start);
if (lSubrStrings != null) {
lSubrStrings.stream(bb);
} else {
components [i].localSubrs.stream(bb);
}
}
}
Key.FDSelect.fixOffset(bb, fdSelectMarker, bb.getSize());
if (!doSubset || !rebuildCharstrings) {
fdSelect.stream(bb);
} else {
if (components.length > 1) {
FdSelect.fdSelectFromSubset(fdSelect, subset).stream(bb);
} else {
FdSelect.singleFont(subset.getNumGlyphs()).stream(bb);
}
}
if (charsetMarker != -1) {
Key.charset.fixOffset(bb, charsetMarker, bb.getSize());
if ((!doSubset && preserveROS) || !rebuildCharstrings) {
charset.stream(bb);
} else if (!preserveROS) {
Charset.identityCharset(subset.getNumGlyphs()).stream(bb);
} else {
Charset.charSetFromSubset(charset, subset).stream(bb);
}
}
Key.CharStrings.fixOffset(bb, charStringsMarker, bb.getSize());
if (!doSubset || !rebuildCharstrings) {
charStrings.stream(bb);
} else {
subsetCharstrings.stream(bb);
}
CFFByteArray byteArray = bb.toCFFByteArray();
byteArray.write(out);
// useful when testing
// try {
// bb.stream(new java.io.FileOutputStream("xx.cff"));
// } catch (Exception e) {}
}
private class CIDKeyedFontXDCFontDescription extends CFFFontXDCFontDescription {
public void subsetAndStream(Subset subset, OutputStream out, boolean preserveROS)
throws InvalidFontException, UnsupportedFontException, IOException
{
CIDKeyedFont.this.subsetAndStream(subset, out, preserveROS);
}
public void stream(OutputStream out, boolean openTypeOk)
throws InvalidFontException, UnsupportedFontException, IOException
{
CIDKeyedFont.this.stream(out, null);
}
public void subsetAndStream(SubsetSimpleType1 t1Subset, OutputStream out)
throws UnsupportedFontException
{
throw new UnsupportedFontException("Not a name-keyed font");
}
public void subsetAndStream(SubsetSimpleTrueType ttSubset, OutputStream out)
throws UnsupportedFontException
{
throw new UnsupportedFontException("Not a TrueType font");
}
public CodePage[] getXDCCodePages()
throws InvalidFontException, UnsupportedFontException
{
HashSet codePageSet = new HashSet();
ROS ros = getROS();
if (ros != null && ros.registry.equals("Adobe")) {
if (ros.ordering.equals("Japan1") || ros.ordering.equals("Japan2"))
codePageSet.add(CodePage.JAPANESE);
else if (ros.ordering.equals("Korea1"))
codePageSet.add(CodePage.KOREAN);
else if (ros.ordering.equals("GB1"))
codePageSet.add(CodePage.SIMPLIFIED_CHINESE);
else if (ros.ordering.equals("CNS1"))
codePageSet.add(CodePage.TRADITIONAL_CHINESE);
}
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 CIDKeyedFont.this.getCIDCount();
}
}
public PDFFontDescription getPDFFontDescription(Font font) throws UnsupportedFontException, InvalidFontException {
return xdcDescription;
}
public XDCFontDescription getXDCFontDescription(Font font) throws UnsupportedFontException, InvalidFontException {
return xdcDescription;
}
public void stream(OutputStream out, Integer fsType) throws InvalidFontException, UnsupportedFontException, IOException {
Subset fakeSubset = new SubsetDefaultImpl(getNumGlyphs(), false);
CIDKeyedFont.this.subsetAndStream(fakeSubset, out, true, fsType);
}
}