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

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

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
/*
*
*	File: FdSelect.java
*
*
*	ADOBE CONFIDENTIAL
*	___________________
*
*	Copyright 2004-2005 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.
*
*/
package com.adobe.fontengine.font.cff;

import com.adobe.fontengine.font.InvalidFontException;
import com.adobe.fontengine.font.Subset;
import com.adobe.fontengine.font.cff.CFFByteArray.CFFByteArrayBuilder;

/** Represents an FDSelect.
 */
final class FdSelect {
  
  /* Our strategy is to just keep our thumb on the underlying bytes,
   * and to interpret them when needed. */
  
  /** The container for our bytes. */
  protected final CFFByteArray data;
  
  /** The offset of our bytes in data. */
  protected final int offset;

  /** The number of bytes for our data, starting at offset. */
protected final int size;
  
  /** Construct a FDSelect from a CFFByteArray.
   * @param data the CFFByteArray to get data from
   * @param offset the offset of the first byte in data
   * @param numGlyphs the number of glyphs in this font.
   */
  public FdSelect (CFFByteArray data, int offset, int numGlyphs) throws InvalidFontException {
    this.data = data;
    this.offset = offset;
    this.size = size (numGlyphs);
  }
  
  /** Return a trivial FdSelect for a a single font with numGlyphs. */
  public static FdSelect singleFont (int numGlyphs) throws InvalidFontException {
	CFFByteArrayBuilder bb = CFFByteArray.getCFFByteArrayBuilderInstance(8);
    bb.addCard8 (3);  // format
    bb.addCard16 (1); // nb of ranges
    bb.addCard16 (0); // first gid
    bb.addCard8 (0);  // component 0
    bb.addCard16 (numGlyphs); // sentinel GID
    
    return new FdSelect (bb.toCFFByteArray(), 0, numGlyphs);
  }
  
  private static FdSelect format0Generator(FdSelect origSelect, Subset subset)
  throws InvalidFontException {
    CFFByteArrayBuilder bb = CFFByteArray.getCFFByteArrayBuilderInstance(1 + subset.getNumGlyphs());

    bb.addCard8(0);

    for (int i = 0; i < subset.getNumGlyphs(); i++)  {
      bb.addCard8(origSelect.componentOf(subset.getFullGid(i))); }

    return new FdSelect(bb.toCFFByteArray(), 0, subset.getNumGlyphs());
  }
  
  private static FdSelect format3Generator(FdSelect origSelect, Subset subset, int numRanges)
  throws InvalidFontException {

    CFFByteArrayBuilder bb = CFFByteArray.getCFFByteArrayBuilderInstance(5 + numRanges * 3);
    int fd = origSelect.componentOf(subset.getFullGid(0)); 

    bb.addCard8(3);
    bb.addCard16(numRanges);
    bb.addCard16(0);

    for (int i = 1; i < subset.getNumGlyphs(); i++) {
      int nextFD = origSelect.componentOf(subset.getFullGid(i));
      if (fd != nextFD) {
        bb.addCard8(fd);
        bb.addCard16(i);
        fd = nextFD; } }

    bb.addCard8(fd);
    bb.addCard16(subset.getNumGlyphs());

    return new FdSelect(bb.toCFFByteArray(), 0, subset.getNumGlyphs());
  }

  public static FdSelect fdSelectFromSubset(FdSelect origSelect, Subset subset)
  throws InvalidFontException {
    int fd = origSelect.componentOf(subset.getFullGid(0)); 
    int numRanges = 1;

    for (int i = 1; i < subset.getNumGlyphs(); i++) {
      int nextFD = origSelect.componentOf(subset.getFullGid(i));
      if (fd != nextFD) {
        numRanges++;
        fd = nextFD; } }

    int format0Size = subset.getNumGlyphs();
    int format3Size = 4 + numRanges * 3;

    if (format0Size <= format3Size) {
      return format0Generator(origSelect, subset); }

    return format3Generator(origSelect, subset, numRanges);
  }
  
  /** Return the index of the component font for a gid.
   * The result is undefined if gid is not
   * a valid gid.
   * 
   * @param gid the gid to lookup. The result is undefined if gid
   * is not a valid gid.
   * @return the index of component font for gid
   */
  public int componentOf (int gid) throws InvalidFontException {
    int o = offset;
    int format = data.getcard8 (o);
    o++;

    switch (format) {

      case 0: {
        // in this format, we have an array indexed by gid, mapping
        // to the target component font.
        return data.getcard8 (o + gid); }
     
      case 3: {
        // in this format, we have a bunch of ranges of gids, 
        // each one mapping to the target component font for the gids
        // in the range. The ranges are in increasing order, with the 
        // first range starting at gid 0; there is a sentinel which
        // acts as a virtual range starting at numGlyphs
        
        int nRanges = data.getcard16 (o);
        o += 2;

        int min = 0;
        int max = nRanges - 1;
        
        while (min <= max) {
          // Invariant: if gid is in a range, then the index of 
          // that range in [min, max]
          int s = (min + max) / 2;
          int firstGid = data.getcard16 (o + 3*s);
          int lastGid = data.getcard16 (o + 3*(s+1));

          if (gid < firstGid) {
            max = s - 1; }
          else if (lastGid <= gid) {
            min = s + 1; }
          else {
            return data.getcard8 (o + 3*s + 2); }}
        
        throw new InvalidFontException ("invalid fdSelect at offset " + offset); }
      
      default: {
        throw new InvalidFontException ("invalid fdSelect format at " + offset); }}
  }
  
  /** Compute the size, in bytes, of this FdSelect. */
  int size (int numGlyphs) throws InvalidFontException {
    int o = offset;
    int format = data.getcard8 (o);
    o++;

    switch (format) {

      case 0: {
        return 1 + numGlyphs; }
        
      case 3: {
        // in this format, we have a bunch of ranges of gids, 
        // each one mapping to the target component font for the gids
        // in the range. The ranges are in increasing order, with the 
        // first range starting at gid 0; there is a sentinel which
        // acts as a virtual range starting at numGlyphs
        
        int nRanges = data.getcard16 (o);
        return 1 /* format */ + 2 /* nRanges */ + 3 * nRanges + 2 /* sentinel */; }
 
      default: {
        throw new InvalidFontException ("invalid fdSelect format at " + offset); }}
  }
  
  /** Stream this charset at the end of a CFFByteArrayBuilder. */
  public void stream (CFFByteArrayBuilder bb) throws InvalidFontException {
    bb.addBytes (data, offset, size);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy