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

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

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





© 2015 - 2025 Weber Informatics LLC | Privacy Policy