001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.svggen.font.table;
020:
021: import java.io.IOException;
022: import java.io.RandomAccessFile;
023:
024: /**
025: * @version $Id: CmapFormat4.java 501844 2007-01-31 13:54:05Z dvholten $
026: * @author <a href="mailto:david@steadystate.co.uk">David Schweinsberg</a>
027: */
028: public class CmapFormat4 extends CmapFormat {
029:
030: public int language;
031: private int segCountX2;
032: private int searchRange;
033: private int entrySelector;
034: private int rangeShift;
035: private int[] endCode;
036: private int[] startCode;
037: private int[] idDelta;
038: private int[] idRangeOffset;
039: private int[] glyphIdArray;
040: private int segCount;
041: private int first, last;
042:
043: protected CmapFormat4(RandomAccessFile raf) throws IOException {
044: super (raf);
045: format = 4;
046: segCountX2 = raf.readUnsignedShort();
047: segCount = segCountX2 / 2;
048: endCode = new int[segCount];
049: startCode = new int[segCount];
050: idDelta = new int[segCount];
051: idRangeOffset = new int[segCount];
052: searchRange = raf.readUnsignedShort();
053: entrySelector = raf.readUnsignedShort();
054: rangeShift = raf.readUnsignedShort();
055: last = -1;
056: for (int i = 0; i < segCount; i++) {
057: endCode[i] = raf.readUnsignedShort();
058: if (endCode[i] > last)
059: last = endCode[i];
060: }
061: raf.readUnsignedShort(); // reservePad
062: for (int i = 0; i < segCount; i++) {
063: startCode[i] = raf.readUnsignedShort();
064: if ((i == 0) || (startCode[i] < first))
065: first = startCode[i];
066: }
067: for (int i = 0; i < segCount; i++) {
068: idDelta[i] = raf.readUnsignedShort();
069: }
070: for (int i = 0; i < segCount; i++) {
071: idRangeOffset[i] = raf.readUnsignedShort();
072: }
073:
074: // Whatever remains of this header belongs in glyphIdArray
075: int count = (length - 16 - (segCount * 8)) / 2;
076: glyphIdArray = new int[count];
077: for (int i = 0; i < count; i++) {
078: glyphIdArray[i] = raf.readUnsignedShort();
079: }
080: }
081:
082: public int getFirst() {
083: return first;
084: }
085:
086: public int getLast() {
087: return last;
088: }
089:
090: public int mapCharCode(int charCode) {
091: try {
092: /*
093: Quoting :
094: http://developer.apple.com/fonts/TTRefMan/RM06/Chap6cmap.html#Surrogates
095:
096: The original architecture of the Unicode Standard
097: allowed for all encoded characters to be represented
098: using sixteen bit code points. This allowed for up to
099: 65,354 characters to be encoded. (Unicode code points
100: U+FFFE and U+FFFF are reserved and unavailable to
101: represent characters. For more details, see The Unicode
102: Standard.)
103:
104: My comment : Isn't there a typo here ? Shouldn't we
105: rather read 65,534 ?
106: */
107: if ((charCode < 0) || (charCode >= 0xFFFE))
108: return 0;
109:
110: for (int i = 0; i < segCount; i++) {
111: if (endCode[i] >= charCode) {
112: if (startCode[i] <= charCode) {
113: if (idRangeOffset[i] > 0) {
114: return glyphIdArray[idRangeOffset[i] / 2
115: + (charCode - startCode[i])
116: - (segCount - i)];
117: } else {
118: return (idDelta[i] + charCode) % 65536;
119: }
120: } else {
121: break;
122: }
123: }
124: }
125: } catch (ArrayIndexOutOfBoundsException e) {
126: System.err.println("error: Array out of bounds - "
127: + e.getMessage());
128: }
129: return 0;
130: }
131:
132: public String toString() {
133: return new StringBuffer(80).append(super .toString()).append(
134: ", segCountX2: ").append(segCountX2).append(
135: ", searchRange: ").append(searchRange).append(
136: ", entrySelector: ").append(entrySelector).append(
137: ", rangeShift: ").append(rangeShift).append(
138: ", endCode: ").append(intToStr(endCode)).append(
139: ", startCode: ").append(intToStr(startCode)).append(
140: ", idDelta: ").append(intToStr(idDelta)).append(
141: ", idRangeOffset: ").append(intToStr(idRangeOffset))
142: .toString();
143: }
144:
145: /**
146: * local helper method to convert an int-array to String.
147: * Intended for debugging, format may change.
148: *
149: * @param array of int to convert
150: * @return a String in the form "[val,val,val ... ]"
151: */
152: private static String intToStr(int[] array) {
153: int nSlots = array.length;
154: StringBuffer workBuff = new StringBuffer(nSlots * 8);
155: workBuff.append('[');
156: for (int i = 0; i < nSlots; i++) {
157: workBuff.append(array[i]);
158: if (i < nSlots - 1) {
159: workBuff.append(',');
160: }
161: }
162: workBuff.append(']');
163: return workBuff.toString();
164: }
165: }
|