001: /*
002: * Copyright (c) 2007, intarsys consulting GmbH
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * - Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * - Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * - Neither the name of intarsys nor the names of its contributors may be used
015: * to endorse or promote products derived from this software without specific
016: * prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028: * POSSIBILITY OF SUCH DAMAGE.
029: */
030: package de.intarsys.pdf.encoding;
031:
032: import java.util.HashMap;
033: import java.util.Map;
034: import de.intarsys.pdf.cos.COSObject;
035:
036: /**
037: * A MappedEncoding is an explicit map from a codepoint to a name (and vice
038: * versa).
039: *
040: * <p>
041: * A MappedEncoding can be constructed individually (as in a DifferenceEncoding)
042: * or be one of the predefined well known encodings that are implemented using
043: * unique instances.
044: * </p>
045: */
046: public class MappedEncoding extends Encoding {
047: /**
048: * The number of 1:1 mappings from unicode to code points.
049: *
050: * <p>
051: * This is done for the first 256 bytes of unicode to cache the most often
052: * used chars.
053: * </p>
054: */
055: private static final int ARRAY_MAPPING_SIZE = 256;
056:
057: /** Maps unicode characters to byte codes */
058: private Map unicodeToByte = new HashMap();
059:
060: /** Maps names to byte codes */
061: private Map nameToByte = new HashMap();
062:
063: /** unicode to byte codes performance optimization */
064: private int[] asciiToByte = new int[ARRAY_MAPPING_SIZE];
065:
066: /** Maps byte codes to unicode characters */
067: private int[] byteToUnicode = new int[256];
068:
069: /**
070: * A map from a codepoint to a glyph name. This is for performance reasons
071: * as it is needed for computing a text's width.
072: */
073: private String[] byteToName = new String[256];
074: {
075: for (int i = 0; i < ARRAY_MAPPING_SIZE; i++) {
076: asciiToByte[i] = -1;
077: }
078: }
079: {
080: for (int i = 0; i < byteToUnicode.length; i++) {
081: byteToUnicode[i] = -1;
082: }
083: }
084: {
085: for (int i = 0; i < byteToName.length; i++) {
086: byteToName[i] = GlyphNameMap.GLYPH_NOTDEF;
087: }
088: }
089:
090: /**
091: * Create a MappedEncoding
092: */
093: public MappedEncoding() {
094: super ();
095: }
096:
097: /*
098: * (non-Javadoc)
099: *
100: * @see de.intarsys.pdf.encoding.Encoding#getByteCode(int)
101: */
102: public int getByteCode(int unicode) {
103: if ((unicode >= 0) && (unicode < ARRAY_MAPPING_SIZE)) {
104: return asciiToByte[unicode];
105: } else {
106: Integer ii = (Integer) getUnicodeToByte().get(
107: new Integer(unicode));
108: if (ii == null) {
109: return -1;
110: }
111: return ii.intValue();
112: }
113: }
114:
115: /*
116: * (non-Javadoc)
117: *
118: * @see de.intarsys.pdf.font.FontEncoding#getCode(java.lang.String)
119: */
120: public int getByteCode(String name) {
121: Integer codePoint = (Integer) getNameToByte().get(name);
122: if (codePoint == null) {
123: return -1;
124: } else {
125: return codePoint.intValue();
126: }
127: }
128:
129: /*
130: * (non-Javadoc)
131: *
132: * @see de.intarsys.pdf.encoding.Encoding#getCosObject(de.intarsys.pdf.cos.COSDocument)
133: */
134: public COSObject getCosObject() {
135: return null;
136: }
137:
138: /*
139: * (non-Javadoc)
140: *
141: * @see de.intarsys.pdf.font.FontEncoding#getName(int)
142: */
143: public String getGlyphName(int codePoint) {
144: if ((codePoint < 0) || (codePoint > 255)) {
145: return GlyphNameMap.GLYPH_NOTDEF;
146: }
147: return getByteToName()[codePoint];
148: }
149:
150: /*
151: * (non-Javadoc)
152: *
153: * @see de.intarsys.pdf.encoding.Encoding#getName()
154: */
155: public String getName() {
156: return "MappedEncoding";
157: }
158:
159: /*
160: * (non-Javadoc)
161: *
162: * @see de.intarsys.pdf.encoding.Encoding#getUnicode(int)
163: */
164: public int getUnicode(int byteValue) {
165: return getByteToUnicode()[byteValue];
166: }
167:
168: /*
169: * (non-Javadoc)
170: *
171: * @see de.intarsys.pdf.encoding.Encoding#getValidByteCode(int)
172: */
173: public int getValidByteCode(int unicode) {
174: int i = getByteCode(unicode);
175: if (i == -1) {
176: return ' ';
177: }
178: return i;
179: }
180:
181: /*
182: * (non-Javadoc)
183: *
184: * @see de.intarsys.pdf.encoding.Encoding#getValidByteCode(java.lang.String)
185: */
186: public int getValidByteCode(String name) {
187: Integer codePoint = (Integer) getNameToByte().get(name);
188: if (codePoint == null) {
189: return ' ';
190: } else {
191: return codePoint.intValue();
192: }
193: }
194:
195: /**
196: * When constructing manually, one can define a map from
197: * <code>codePoint</code> to <code>name</code> with this method.
198: *
199: * @param codePoint
200: * The codePoint from 0..255 where the character should be
201: * mapped.
202: * @param name
203: * The name of the character to be mapped.
204: */
205: public void addEncoding(int codePoint, String name) {
206: int unicode = GlyphNameMap.Standard.getUnicode(name);
207: defineEntry(codePoint, unicode, name);
208: }
209:
210: /**
211: * Add a known complete tuple. THis is used if we do not have a name/unicode
212: * standard map (for example in symbolic fonts).
213: *
214: * @param codePoint
215: * The codePoint from 0..255 where the character should be
216: * mapped.
217: * @param name
218: * The name of the character to be mapped.
219: * @param unicode
220: * The unicode value
221: */
222: public void addEncoding(int codePoint, String name, int unicode) {
223: defineEntry(codePoint, unicode, name);
224: }
225:
226: /**
227: * The internal representation of the map from codePoint to character name.
228: *
229: * @return The internal representation of the map from codePoint to
230: * character name.
231: */
232: protected String[] getByteToName() {
233: return byteToName;
234: }
235:
236: /**
237: * The internal representation of the map from byte code to unicode.
238: *
239: * @return The internal representation of the map from byte code to unicode.
240: */
241: protected int[] getByteToUnicode() {
242: return byteToUnicode;
243: }
244:
245: /**
246: * The internal representation of the map from names to byte value code
247: * point.
248: *
249: * @return The internal representation of the map from names to byte value
250: * code point.
251: */
252: protected Map getNameToByte() {
253: return nameToByte;
254: }
255:
256: /**
257: * The internal representation of the map from unicode code point to byte
258: * value code point.
259: *
260: * @return The internal representation of the map from unicode code point to
261: * byte value code point.
262: */
263: protected Map getUnicodeToByte() {
264: return unicodeToByte;
265: }
266:
267: /**
268: * Define an entry the establishes a relationship between byte code code
269: * point, unicode code point and Adobe glyph name.
270: *
271: * @param codePoint
272: * The byte code code point.
273: * @param unicode
274: * The unicode code point.
275: * @param name
276: * The Adobe glyph name.
277: */
278: protected void defineEntry(int codePoint, int unicode, String name) {
279: // byte/name association
280: byteToName[codePoint] = name;
281: Integer codePointInteger = new Integer(codePoint);
282: nameToByte.put(name, codePointInteger);
283: // byte unicode association
284: byteToUnicode[codePoint] = unicode;
285: unicodeToByte.put(new Integer(unicode), codePointInteger);
286: //
287: if ((unicode >= 0) && (unicode < ARRAY_MAPPING_SIZE)) {
288: asciiToByte[unicode] = codePoint;
289: }
290: }
291: }
|