All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.fontengine.font.cff.CIDKeyedFont Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
/*
*	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 CIDComponentFonts. */
  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); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy