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

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

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

package com.adobe.fontengine.font.cff;

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

/** Represents a charset.
 * 
 * 

Contrary to what could be infered from the CFF specifcation, * a charset is conceptually an array of integers, indexed by glyphID, * with one entry per glyph, and the entry for gid 0 is always 0.

* *

In name-keyed fonts, the integers can be * interpreted as SIDs, to get the name of the glyphs.

* *

In CID-keyed fonts, the integer is the CID of the glyph.

* *

In this class, we always use the term "SID".

*/ final class Charset { /* Our strategy is to just keep our thumb on the underlying bytes, * and to interpret them when needed. */ /** The container for our bytes, if the charset is not predefined. * If the charset is predefined, than data is null. */ public final CFFByteArray data; /** The offset of our bytes in data if the charset is * not predefined. * If the charset is predefined, than data is null * and offset is 0, 1, or 2. * Note that the value 0 is ambiguous, as it can be either the isoAdobe * predefined charset (if data is null) or an offset in data (if data is * not null). */ public final int offset; /** The number of bytes for our data, starting at offset * if the charset is not predefined, undefined otherwise. */ public final int size; /** Construct a Charset from a CFFByteArray. * offset is interpreted to handle the predefined charsets; * in other words, clients do not have to worry about those. * * @param data the CFFByteArray to get data from, if offset is * not -1, 0, 1 or 2 * @param offset if 0, this is the isoAdobe predefined charset; if 1, this is * the expertSet predefined charset; if 2, this is the expertSubset predefined * charset. if -1 charset is undefined but may still return minimal information * such as for CID 0. otherwise, the bytes of data starting at * offset are used. * @param numGlyphs the number of glyphs in this Charset. Ignored for predefined * charsets. */ Charset (CFFByteArray data, int offset, int numGlyphs) throws InvalidFontException { if (offset < 3) { this.data = null; } else { this.data = data; } this.offset = offset; this.size = size (numGlyphs); } /** Construct a Charset from a CFFByteArray. */ Charset (CFFByteArray data) { this.data = data; this.offset = 0; this.size = data.getSize (); } /** Return the identity charset for numGlyphs glyphs. */ static Charset identityCharset (int numGlyphs) { CFFByteArrayBuilder bb; numGlyphs -= 2; // gid 0 is not represented, count is remaining after gid 1 if (numGlyphs > 255) { bb = CFFByteArray.getCFFByteArrayBuilderInstance(5); bb.addCard8 (2); bb.addCard16 (1); bb.addCard16 (numGlyphs); } else { bb = CFFByteArray.getCFFByteArrayBuilderInstance(4); bb.addCard8 (1); bb.addCard16 (1); bb.addCard8 (numGlyphs); } return new Charset (bb.toCFFByteArray()); } /** * Generate a format 0 Charset that maps from subset gids to the same sid that * the corresponding full gid mapped to. * * @param sourceCharset The charset containing the full gid to sid mapping. * @param subset The mapping from subset gid to full gid. * @return The new format 0 charset. * @throws UnsupportedFontException * @throws InvalidFontException */ private static Charset format0Generator(Charset sourceCharset, Subset subset) throws UnsupportedFontException, InvalidFontException { CFFByteArrayBuilder bb = CFFByteArray.getCFFByteArrayBuilderInstance(1 + 2 * (subset.getNumGlyphs()-1)); bb.addCard8(0); for (int i = 1; i < subset.getNumGlyphs();i++) { bb.addCard16(sourceCharset.gid2sid(subset.getFullGid(i))); } return new Charset(bb.toCFFByteArray()); } /** * Generate a format 1 Charset that maps from subset gids to the same sid that * the corresponding full gid mapped to. * * @param sourceCharset The charset containing the full gid to sid mapping. * @param subset The mapping from subset gid to full gid. * @return The new format 1 charset. * @throws UnsupportedFontException * @throws InvalidFontException */ private static Charset format1Generator(Charset sourceCharset, Subset subset, int numRanges) throws UnsupportedFontException, InvalidFontException { CFFByteArrayBuilder bb = CFFByteArray.getCFFByteArrayBuilderInstance(1 + 3 * numRanges); bb.addCard8(1); int currEntries = 0; int lastSid = sourceCharset.gid2sid(subset.getFullGid(1)); bb.addCard16(lastSid); for (int i = 2; i < subset.getNumGlyphs(); i++) { int thisSid = sourceCharset.gid2sid(subset.getFullGid(i)); if (currEntries == 255 || thisSid != lastSid+1) { bb.addCard8(currEntries); currEntries = 0; bb.addCard16(thisSid); } else { currEntries++; } lastSid = thisSid; } bb.addCard8(currEntries); return new Charset(bb.toCFFByteArray()); } /** * Generate a format 2 Charset that maps from subset gids to the same sid that * the corresponding full gid mapped to. * * @param sourceCharset The charset containing the full gid to sid mapping. * @param subset The mapping from subset gid to full gid. * @return The new format 2 charset. * @throws UnsupportedFontException * @throws InvalidFontException */ private static Charset format2Generator(Charset sourceCharset, Subset subset, int numRanges) throws UnsupportedFontException, InvalidFontException { CFFByteArrayBuilder bb = CFFByteArray.getCFFByteArrayBuilderInstance(1 + 3 * numRanges); bb.addCard8(2); int currEntries = 0; int lastSid = sourceCharset.gid2sid(subset.getFullGid(1)); bb.addCard16(lastSid); for (int i = 2; i < subset.getNumGlyphs(); i++) { int thisSid = sourceCharset.gid2sid(subset.getFullGid(i)); if (thisSid != lastSid+1) { bb.addCard16(currEntries); currEntries = 0; bb.addCard16(thisSid); } else { currEntries++; } lastSid = thisSid; } bb.addCard8(currEntries); return new Charset(bb.toCFFByteArray()); } /** * Generate the smallest possible Charset that maps from subset gids to the same sid that * the corresponding full gid mapped to. * * @param sourceCharset The charset containing the full gid to sid mapping. * @param subset The mapping from subset gid to full gid. * @return The new format 2 charset. * @throws UnsupportedFontException * @throws InvalidFontException */ static Charset charSetFromSubset(Charset sourceCharset, Subset subset) throws InvalidFontException, UnsupportedFontException { int i; int numGlyphs = subset.getNumGlyphs(); int format0Size = 2 * numGlyphs; int numRange1 = 1; int numRange2 = 1; int currRange1Entries = 0; if (numGlyphs > 1) { int lastSid = sourceCharset.gid2sid (subset.getFullGid(1)); for (i = 2; i < numGlyphs; i++) { int thisSid = sourceCharset.gid2sid (subset.getFullGid(i)); if (currRange1Entries == 255 || thisSid != lastSid+1) { numRange1++; currRange1Entries=0;} else { currRange1Entries++; } if (thisSid != lastSid+1) { numRange2++; } lastSid = thisSid; }} int format1Size = 3 * numRange1; int format2Size = 4 * numRange2; if (format0Size <= format1Size) { if (format0Size <= format2Size) { return format0Generator(sourceCharset, subset); } else { return format2Generator(sourceCharset, subset, numRange2); }} else if (format1Size <= format2Size) { return format1Generator(sourceCharset, subset, numRange1); } return format2Generator(sourceCharset, subset, numRange2); } /** Return the sid of the glyph with a given gid. * * @param gid the gid to lookup. The result is undefined if gid * is not a valid gid. * @return the integer mapped from gid */ public int gid2sid (int gid) throws InvalidFontException, UnsupportedFontException { if (gid == 0) { return 0; } if (data == null) { if (offset == 0) { return isoAdobeCharset [gid]; } if (offset == 1) { return expertCharset [gid]; } if (offset == 2) { return expertSubsetCharset [gid]; } throw new InvalidFontException ("invalid charset offset (" + offset + ")"); } int o = offset; int format = data.getcard8 (o); o++; switch (format) { case 0: { return data.getcard16 (o + 2 * (gid - 1)); } case 1: { int currentGid = 1; while (o < offset + size) { int currentSID = data.getcard16 (o); o += 2; int nLeft = data.getcard8 (o); o ++; if (currentGid <= gid && gid <= currentGid + nLeft) { return currentSID + (gid - currentGid); } currentGid += nLeft + 1; } return -1; } case 2: { int currentGid = 1; while (o < offset + size) { int currentSID = data.getcard16 (o); o += 2; int nLeft = data.getcard16 (o); o += 2; if (currentGid <= gid && gid <= currentGid + nLeft) { return currentSID + (gid - currentGid); } currentGid += nLeft + 1; } return -1; } default: { throw new UnsupportedFontException ("CFF charset in format " + format); }} } /** Return the gid of the glyph with a given sid. * * @param sid the sid to lookup. The result is undefined if no glyph has this sid. * @return the gid with that sid */ public int sid2gid (int sid) throws InvalidFontException, UnsupportedFontException { if (sid == 0) { return 0; } if (data == null) { if (offset == 0) { for (int gid = 0; gid < isoAdobeCharset.length; gid++) { if (isoAdobeCharset [gid] == sid) { return gid; }} return -1; } if (offset == 1) { for (int gid = 0; gid < expertCharset.length; gid++) { if (expertCharset [gid] == sid) { return gid; }} return -1; } if (offset == 2) { for (int gid = 0; gid < expertSubsetCharset.length; gid++) { if (expertSubsetCharset [gid] == sid) { return gid; }} return -1; } throw new InvalidFontException ("invalid charset offset (" + offset + ")"); } int o = offset; int format = data.getcard8 (o); o++; switch (format) { case 0: { int gid = 1; while (o < offset + size) { if (data.getcard16 (o) == sid) { return gid; } o += 2; gid++; } return -1; } case 1: { int currentGid = 1; while (o < offset + size) { int currentSid = data.getcard16 (o); o += 2; int nLeft = data.getcard8 (o); o ++; if (currentSid <= sid && sid <= currentSid + nLeft) { return currentGid + (sid - currentSid); } currentGid += nLeft + 1; } return -1; } case 2: { int currentGid = 1; while (o < offset + size) { int currentSid = data.getcard16 (o); o += 2; int nLeft = data.getcard16 (o); o += 2; if (currentSid <= sid && sid <= currentSid + nLeft) { return currentGid + (sid - currentSid); } currentGid += nLeft + 1; } return -1; } default: { throw new UnsupportedFontException ("CFF charset in format " + format); }} } /** Return the size, in bytes, of this Charset, given the number of glyphs * in it. */ int size (int numGlyphs) throws InvalidFontException { if (offset < 3) { return 0; } int o = offset; int format = data.getcard8 (o); o++; switch (format) { case 0: { return 1 + 2 * numGlyphs; } case 1: { int currentGlyphID = 1; while (currentGlyphID < numGlyphs) { o += 2; int nLeft = data.getcard8 (o); o ++; currentGlyphID += nLeft + 1; } break; } case 2: { int currentGlyphID = 1; while (currentGlyphID < numGlyphs) { o += 2; int nLeft = data.getcard16 (o); o += 2; currentGlyphID += nLeft + 1; } break; }} return o - offset; } /** If this is a predefined charset, then return the special offset * value for it; otherwise, returns -1. */ public int predefinedOffset () { if (data == null) { return offset; } return -1; } /** Stream this charset at the end of a CFFByteArrayBuilder, if it is * not predefined. */ public void stream (CFFByteArrayBuilder bb) throws InvalidFontException { if (data != null) { bb.addBytes (data, offset, size); } } /** * Output a charset from a SID array. Either format 2 or format 0 is used, * depending on the resultant size. */ static void streamCharSet(CFFByteArrayBuilder bb, int[] glyphSids) { int i, j; final int format0Size = (glyphSids.length-1) * 2; int format2Size = 0; // determine the size of a format 2 charset for (i = 1; i < glyphSids.length; ) { format2Size += 4; if (format2Size >= format0Size) break; for (j = i+1; j < glyphSids.length && glyphSids[j] == glyphSids[j-1]+1; j++) { ; // keep counting. } i = j; } if (format2Size < format0Size) { // format 2 is smaller. Use it. bb.addCard8(2); // The format. for (i = 1; i < glyphSids.length;) { int nleft = 0; bb.addCard16(glyphSids[i]); // Starting SID. for (j = i+1; j < glyphSids.length && glyphSids[j] == glyphSids[j-1]+1; j++) { nleft++; } bb.addCard16(nleft); // Remaining SIDs in this range. i = j; } } else { // format 0 is smaller. Use it. bb.addCard8(0); // The format for (i = 1; i < glyphSids.length; i++) bb.addCard16(glyphSids[i]); // SIDS, excluding .notdef } } /** The 'isoAdobe' predefined charset. */ private static final int[] isoAdobeCharset = { 0, // .notdef 1, // space 2, // exclam 3, // quotedbl 4, // numbersign 5, // dollar 6, // percent 7, // ampersand 8, // quoteright 9, // parenleft 10, // parenright 11, // asterisk 12, // plus 13, // comma 14, // hyphen 15, // period 16, // slash 17, // zero 18, // one 19, // two 20, // three 21, // four 22, // five 23, // six 24, // seven 25, // eight 26, // nine 27, // colon 28, // semicolon 29, // less 30, // equal 31, // greater 32, // question 33, // at 34, // A 35, // B 36, // C 37, // D 38, // E 39, // F 40, // G 41, // H 42, // I 43, // J 44, // K 45, // L 46, // M 47, // N 48, // O 49, // P 50, // Q 51, // R 52, // S 53, // T 54, // U 55, // V 56, // W 57, // X 58, // Y 59, // Z 60, // bracketleft 61, // backslash 62, // bracketright 63, // asciicircum 64, // underscore 65, // quoteleft 66, // a 67, // b 68, // c 69, // d 70, // e 71, // f 72, // g 73, // h 74, // i 75, // j 76, // k 77, // l 78, // m 79, // n 80, // o 81, // p 82, // q 83, // r 84, // s 85, // t 86, // u 87, // v 88, // w 89, // x 90, // y 91, // z 92, // braceleft 93, // bar 94, // braceright 95, // asciitilde 96, // exclamdown 97, // cent 98, // sterling 99, // fraction 100, // yen 101, // florin 102, // section 103, // currency 104, // quotesingle 105, // quotedblleft 106, // guillemotleft 107, // guilsinglleft 108, // guilsinglright 109, // fi 110, // fl 111, // endash 112, // dagger 113, // daggerdbl 114, // periodcentered 115, // paragraph 116, // bullet 117, // quotesinglbase 118, // quotedblbase 119, // quotedblright 120, // guillemotright 121, // ellipsis 122, // perthousand 123, // questiondown 124, // grave 125, // acute 126, // circumflex 127, // tilde 128, // macron 129, // breve 130, // dotaccent 131, // dieresis 132, // ring 133, // cedilla 134, // hungarumlaut 135, // ogonek 136, // caron 137, // emdash 138, // AE 139, // ordfeminine 140, // Lslash 141, // Oslash 142, // OE 143, // ordmasculine 144, // ae 145, // dotlessi 146, // lslash 147, // oslash 148, // oe 149, // germandbls 150, // onesuperior 151, // logicalnot 152, // mu 153, // trademark 154, // Eth 155, // onehalf 156, // plusminus 157, // Thorn 158, // onequarter 159, // divide 160, // brokenbar 161, // degree 162, // thorn 163, // threequarters 164, // twosuperior 165, // registered 166, // minus 167, // eth 168, // multiply 169, // threesuperior 170, // copyright 171, // Aacute 172, // Acircumflex 173, // Adieresis 174, // Agrave 175, // Aring 176, // Atilde 177, // Ccedilla 178, // Eacute 179, // Ecircumflex 180, // Edieresis 181, // Egrave 182, // Iacute 183, // Icircumflex 184, // Idieresis 185, // Igrave 186, // Ntilde 187, // Oacute 188, // Ocircumflex 189, // Odieresis 190, // Ograve 191, // Otilde 192, // Scaron 193, // Uacute 194, // Ucircumflex 195, // Udieresis 196, // Ugrave 197, // Yacute 198, // Ydieresis 199, // Zcaron 200, // aacute 201, // acircumflex 202, // adieresis 203, // agrave 204, // aring 205, // atilde 206, // ccedilla 207, // eacute 208, // ecircumflex 209, // edieresis 210, // egrave 211, // iacute 212, // icircumflex 213, // idieresis 214, // igrave 215, // ntilde 216, // oacute 217, // ocircumflex 218, // odieresis 219, // ograve 220, // otilde 221, // scaron 222, // uacute 223, // ucircumflex 224, // udieresis 225, // ugrave 226, // yacute 227, // ydieresis 228}; // zcaron /** The 'expert' predefined charset. */ private static final int[] expertCharset = { 0, // .notdef 1, // space 229, // exclamsmall 230, // Hungarumlautsmall 231, // dollaroldstyle 232, // dollarsuperior 233, // ampersandsmall 234, // Acutesmall 235, // parenleftsuperior 236, // parenrightsuperior 237, // twodotenleader 238, // onedotenleader 27, // colon 28, // semicolon 13, // comma 14, // hyphen 15, // period 99, // fraction 239, // zerooldstyle 240, // oneoldstyle 241, // twooldstyle 242, // threeoldstyle 243, // fouroldstyle 244, // fiveoldstyle 245, // sixoldstyle 246, // sevenoldstyle 247, // eightoldstyle 248, // nineoldstyle 249, // commasuperior 250, // threequartersemdash 251, // periodsuperior 252, // questionsmall 253, // asuperior 254, // bsuperior 255, // centsuperior 256, // dsuperior 257, // esuperior 258, // isuperior 259, // lsuperior 260, // msuperior 261, // nsuperior 262, // osuperior 263, // rsuperior 264, // ssuperior 265, // tsuperior 266, // ff 109, // fi 110, // fl 267, // ffi 268, // ffl 269, // parenleftinferior 270, // parenrightinferior 271, // Circumflexsmall 272, // hyphensuperior 273, // Gravesmall 274, // Asmall 275, // Bsmall 276, // Csmall 277, // Dsmall 278, // Esmall 279, // Fsmall 280, // Gsmall 281, // Hsmall 282, // Ismall 283, // Jsmall 284, // Ksmall 285, // Lsmall 286, // Msmall 287, // Nsmall 288, // Osmall 289, // Psmall 290, // Qsmall 291, // Rsmall 292, // Ssmall 293, // Tsmall 294, // Usmall 295, // Vsmall 296, // Wsmall 297, // Xsmall 298, // Ysmall 299, // Zsmall 300, // colonmonetary 301, // onefitted 302, // rupiah 303, // Tildesmall 304, // exclamdownsmall 305, // centoldstyle 306, // Lslashsmall 307, // Scaronsmall 308, // Zcaronsmall 309, // Dieresissmall 310, // Brevesmall 311, // Caronsmall 312, // Dotaccentsmall 313, // Macronsmall 314, // figuredash 315, // hypheninferior 316, // Ogoneksmall 317, // Ringsmall 318, // Cedillasmall 158, // onequarter 155, // onehalf 163, // threequarters 319, // questiondownsmall 320, // oneeighth 321, // threeeighths 322, // fiveeighths 323, // seveneighths 324, // onethird 325, // twothirds 326, // zerosuperior 150, // onesuperior 164, // twosuperior 169, // threesuperior 327, // foursuperior 328, // fivesuperior 329, // sixsuperior 330, // sevensuperior 331, // eightsuperior 332, // ninesuperior 333, // zeroinferior 334, // oneinferior 335, // twoinferior 336, // threeinferior 337, // fourinferior 338, // fiveinferior 339, // sixinferior 340, // seveninferior 341, // eightinferior 342, // nineinferior 343, // centinferior 344, // dollarinferior 345, // periodinferior 346, // commainferior 347, // Agravesmall 348, // Aacutesmall 349, // Acircumflexsmall 350, // Atildesmall 351, // Adieresissmall 352, // Aringsmall 353, // AEsmall 354, // Ccedillasmall 355, // Egravesmall 356, // Eacutesmall 357, // Ecircumflexsmall 358, // Edieresissmall 359, // Igravesmall 360, // Iacutesmall 361, // Icircumflexsmall 362, // Idieresissmall 363, // Ethsmall 364, // Ntildesmall 365, // Ogravesmall 366, // Oacutesmall 367, // Ocircumflexsmall 368, // Otildesmall 369, // Odieresissmall 370, // OEsmall 371, // Oslashsmall 372, // Ugravesmall 373, // Uacutesmall 374, // Ucircumflexsmall 375, // Udieresissmall 376, // Yacutesmall 377, // Thornsmall 378}; // Ydieresissmall /** The 'expertSubset' predefined charset. */ private static final int[] expertSubsetCharset = { 0, // .notdef 1, // space 231, // dollaroldstyle 232, // dollarsuperior 235, // parenleftsuperior 236, // parenrightsuperior 237, // twodotenleader 238, // onedotenleader 13, // comma 14, // hyphen 15, // period 99, // fraction 239, // zerooldstyle 240, // oneoldstyle 241, // twooldstyle 242, // threeoldstyle 243, // fouroldstyle 244, // fiveoldstyle 245, // sixoldstyle 246, // sevenoldstyle 247, // eightoldstyle 248, // nineoldstyle 27, // colon 28, // semicolon 249, // commasuperior 250, // threequartersemdash 251, // periodsuperior 253, // asuperior 254, // bsuperior 255, // centsuperior 256, // dsuperior 257, // esuperior 258, // isuperior 259, // lsuperior 260, // msuperior 261, // nsuperior 262, // osuperior 263, // rsuperior 264, // ssuperior 265, // tsuperior 266, // ff 109, // fi 110, // fl 267, // ffi 268, // ffl 269, // parenleftinferior 270, // parenrightinferior 272, // hyphensuperior 300, // colonmonetary 301, // onefitted 302, // rupiah 305, // centoldstyle 314, // figuredash 315, // hypheninferior 158, // onequarter 155, // onehalf 163, // threequarters 320, // oneeighth 321, // threeeighths 322, // fiveeighths 323, // seveneighths 324, // onethird 325, // twothirds 326, // zerosuperior 150, // onesuperior 164, // twosuperior 169, // threesuperior 327, // foursuperior 328, // fivesuperior 329, // sixsuperior 330, // sevensuperior 331, // eightsuperior 332, // ninesuperior 333, // zeroinferior 334, // oneinferior 335, // twoinferior 336, // threeinferior 337, // fourinferior 338, // fiveinferior 339, // sixinferior 340, // seveninferior 341, // eightinferior 342, // nineinferior 343, // centinferior 344, // dollarinferior 345, // periodinferior 346}; // commainferior }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy