
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