com.adobe.fontengine.font.cff.Charset Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
The 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
}