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

com.adobe.fontengine.font.postscript.UnicodeCmap Maven / Gradle / Ivy

/*
 * File: UnicodeCmap.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.postscript;


import com.adobe.fontengine.CharUtil;
import com.adobe.fontengine.font.InvalidFontException;
import com.adobe.fontengine.font.UnsupportedFontException;
import com.adobe.fontengine.font.opentype.GlyphNames;

/** A UnicodeCmap is the equivalent, in the PostScript world, of an
 * OpenType 'cmap' table. 
 */
final public class UnicodeCmap {

  // We represent a cmap by a three level array: the first index is the plane,
  // the second is the row and the third is the cell. This structure is
  // well-adapted to relatively dense groups of contiguous values in an
  // overall sparse map. We do not benefit from contiguous values for 
  // contiguous entries (e.g. if the gid for A is n and the gid for B is
  // n+1), but then we gain fast access.

  int [][][] cmap = null;
  
  public int getGlyphForChar (int usv) 
      throws InvalidFontException, UnsupportedFontException {
    
    // It may be faster to simply do cmap[x][y][y] and to catch
    // null pointer and array out of bounds exceptions; the 
    // common case is to succeed.
    
    if ((usv >> 16) >= cmap.length) {
      return -1; }     
    int[][] c2 = cmap [usv >> 16];
    if (c2 == null) {
      return 0; }
    int[] c3 = c2 [(usv >> 8) & 0xff];
    if (c3 == null) {
      return 0; }
    return c3 [usv & 0xff];
  }
  
  public int getFirstSupportedChar()
  {
	  for (int i = 0; i < cmap.length; i++) {
		  if (cmap[i] != null) {
			  for (int j = 0; j < cmap[i].length; j++) {
				  if (cmap[i][j] != null) {
					  for (int k = 0; k < cmap[i][j].length; k++)  {
						  if (cmap[i][j][k] != 0) {
							  return ((i << 16) | (j << 8 ) | k); }}}}}}
	  
	  return Integer.MAX_VALUE;
  }
  
  public int getLastSupportedChar()
  {
	  for (int i = cmap.length-1; i >= 0; i--) {
		  if (cmap[i] != null) {
			  for (int j = cmap[i].length-1; j >= 0; j--) {
				  if (cmap[i][j] != null) {
					  for (int k = cmap[i][j].length-1; k >= 0; k--) {
						  if (cmap[i][j][k] != 0) {
							  return ((i << 16) | (j << 8) | k); }}}}}}
	  
	  return 0;
  }

  //---------------------------------------------------------- building cmap ---

  static public UnicodeCmap computeCmapFromGlyphNames (int numGlyphs, 
                            boolean isDingbat, GlyphNamesAccessor names) 
  throws InvalidFontException, UnsupportedFontException {
    int[][][] mapping = new int [numGlyphs][][];  
    
    // figure out what each glyph represents
    for (int gid = 1; gid < numGlyphs; gid++) {
      String name = names.getAGlyphName (gid);
      mapping [gid] = characterizeGlyphName (name, isDingbat); }
    
    // populate the cmap with each glyph in turn, keeping only the best mapping
    return buildCmap (mapping);
  }

  static private int[][] characterizeGlyphName (String name, boolean isDingbat) {
    int[] usvs = GlyphNames.resolveAGNCNameIntoArray (name, isDingbat);
    int nbUsvs = usvs.length;
    
    boolean isSuffixed = (GlyphNames.getAGNCNameSuffix(name) != null);
    
    int[][] x;
    
    int[] usvs2 =  CharUtil.mapStringFrom (usvs, 0, nbUsvs);
    if (usvs2.length == 0) {
      if (nbUsvs == 1) {
        x = new int [][] { {usvs [0], isSuffixed ? 1 : 0} }; }
      else {
        x = new int [0][]; }}
    else {
      x = new int [usvs2.length][];
      for (int i = 0; i < usvs2.length; i++) {
        x [i] = new int [] {usvs2 [i], isSuffixed ? 1 : 0}; }}
    
    return x;
  }
  
  
  static public abstract class GlyphCidAccessor {
    abstract public int getAGlyphCid (int gid) 
      throws InvalidFontException, UnsupportedFontException; 
  }
  
  static public UnicodeCmap computeCmapFromCids (int numGlyphs,
                                                 GlyphCidAccessor cids, 
                                                 String registry, String ordering)         
     throws InvalidFontException, UnsupportedFontException {

    int[][][] mapping = new int [numGlyphs][][];  
    
    CIDtoUnicode m = CIDtoUnicode.get (registry, ordering);
    
    // figure out what each glyph represents
    for (int gid = 0; gid < numGlyphs; gid++) {
      int cid = cids.getAGlyphCid (gid);
      mapping [gid] = characterizeCid (m, cid); }
    
    // populate the cmap with each glyph in turn, keeping only the best mapping
    return buildCmap (mapping);
  }
  
  static int[][] characterizeCid (CIDtoUnicode m, int cid) {
    int usv = m.cid2usv (cid);
    if (usv == -1) {
      return new int[0][]; }
    else {
      return new int [][] {{usv, 0}}; }
  }
  
  
  
  
  // mapping is indexed by gid, then by ?, then by 0 = usv, 1 = penalty
  private static UnicodeCmap buildCmap (int[][][] mapping) {
    UnicodeCmap cmap = new UnicodeCmap ();
    cmap.cmap = new int [17][][];
    int [][][] actualPenalties = new int [17][][];
 
    for (int gid = 1; gid < mapping.length; gid++) {
      for (int i = 0; i < mapping [gid].length; i++) {
        int usv = mapping [gid][i][0];
        int penalty = mapping [gid][i][1];
        
        int plane = usv >> 16;
        int row = (usv >> 8) & 0xff;
        int cell = usv & 0xff;
        
        if (cmap.cmap [plane] == null) {
          cmap.cmap [plane] = new int [256][];
          actualPenalties [plane] = new int [256][]; }
        if (cmap.cmap [plane][row] == null) {
          cmap.cmap [plane][row] = new int [256]; 
          actualPenalties [plane][row] = new int [256];
          for (int c = 0; c < 256; c++) {
            cmap.cmap [plane][row][c] = 0; 
            actualPenalties [plane][row][c] = Integer.MAX_VALUE; }}
        
        if (penalty < actualPenalties [plane][row][cell]) {
          cmap.cmap [plane][row][cell] = gid;
          actualPenalties [plane][row][cell] = penalty; }}}
    
    return cmap;
  }  
}
  




© 2015 - 2025 Weber Informatics LLC | Privacy Policy