123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894 |
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /* $Id$ */
-
- package org.apache.fop.fonts.truetype;
-
- import java.io.IOException;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
-
-
- /**
- * Reads a TrueType file and generates a subset
- * that can be used to embed a TrueType CID font.
- * TrueType tables needed for embedded CID fonts are:
- * "head", "hhea", "loca", "maxp", "cvt ", "prep", "glyf", "hmtx" and "fpgm".
- * The TrueType spec can be found at the Microsoft
- * Typography site: http://www.microsoft.com/truetype/
- */
- public class TTFSubSetFile extends TTFFile {
-
- private byte[] output = null;
- private int realSize = 0;
- private int currentPos = 0;
-
- /*
- * Offsets in name table to be filled out by table.
- * The offsets are to the checkSum field
- */
- private int cvtDirOffset = 0;
- private int fpgmDirOffset = 0;
- private int glyfDirOffset = 0;
- private int headDirOffset = 0;
- private int hheaDirOffset = 0;
- private int hmtxDirOffset = 0;
- private int locaDirOffset = 0;
- private int maxpDirOffset = 0;
- private int prepDirOffset = 0;
-
- private int checkSumAdjustmentOffset = 0;
- private int locaOffset = 0;
-
- /**
- * Initalize the output array
- */
- private void init(int size) {
- output = new byte[size];
- realSize = 0;
- currentPos = 0;
-
- // createDirectory()
- }
-
- private int determineTableCount() {
- int numTables = 4; //4 req'd tables: head,hhea,hmtx,maxp
- if (isCFF()) {
- throw new UnsupportedOperationException(
- "OpenType fonts with CFF glyphs are not supported");
- } else {
- numTables += 2; //1 req'd table: glyf,loca
- if (hasCvt()) {
- numTables++;
- }
- if (hasFpgm()) {
- numTables++;
- }
- if (hasPrep()) {
- numTables++;
- }
- }
- return numTables;
- }
-
- /**
- * Create the directory table
- */
- private void createDirectory() {
- int numTables = determineTableCount();
- // Create the TrueType header
- writeByte((byte)0);
- writeByte((byte)1);
- writeByte((byte)0);
- writeByte((byte)0);
- realSize += 4;
-
- writeUShort(numTables);
- realSize += 2;
-
- // Create searchRange, entrySelector and rangeShift
- int maxPow = maxPow2(numTables);
- int searchRange = maxPow * 16;
- writeUShort(searchRange);
- realSize += 2;
-
- writeUShort(maxPow);
- realSize += 2;
-
- writeUShort((numTables * 16) - searchRange);
- realSize += 2;
-
- // Create space for the table entries
- if (hasCvt()) {
- writeString("cvt ");
- cvtDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
- }
-
- if (hasFpgm()) {
- writeString("fpgm");
- fpgmDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
- }
-
- writeString("glyf");
- glyfDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
-
- writeString("head");
- headDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
-
- writeString("hhea");
- hheaDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
-
- writeString("hmtx");
- hmtxDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
-
- writeString("loca");
- locaDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
-
- writeString("maxp");
- maxpDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
-
- if (hasPrep()) {
- writeString("prep");
- prepDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
- }
- }
-
-
- /**
- * Copy the cvt table as is from original font to subset font
- */
- private boolean createCvt(FontFileReader in) throws IOException {
- TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("cvt ");
- if (entry != null) {
- pad4();
- seekTab(in, "cvt ", 0);
- System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
- 0, output, currentPos, (int)entry.getLength());
-
- int checksum = getCheckSum(currentPos, (int)entry.getLength());
- writeULong(cvtDirOffset, checksum);
- writeULong(cvtDirOffset + 4, currentPos);
- writeULong(cvtDirOffset + 8, (int)entry.getLength());
- currentPos += (int)entry.getLength();
- realSize += (int)entry.getLength();
- return true;
- } else {
- return false;
- //throw new IOException("Can't find cvt table");
- }
- }
-
- private boolean hasCvt() {
- return dirTabs.containsKey("cvt ");
- }
-
- private boolean hasFpgm() {
- return dirTabs.containsKey("fpgm");
- }
-
- private boolean hasPrep() {
- return dirTabs.containsKey("prep");
- }
-
- /**
- * Copy the fpgm table as is from original font to subset font
- */
- private boolean createFpgm(FontFileReader in) throws IOException {
- TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("fpgm");
- if (entry != null) {
- pad4();
- seekTab(in, "fpgm", 0);
- System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
- 0, output, currentPos, (int)entry.getLength());
- int checksum = getCheckSum(currentPos, (int)entry.getLength());
- writeULong(fpgmDirOffset, checksum);
- writeULong(fpgmDirOffset + 4, currentPos);
- writeULong(fpgmDirOffset + 8, (int)entry.getLength());
- currentPos += (int)entry.getLength();
- realSize += (int)entry.getLength();
- return true;
- } else {
- return false;
- }
- }
-
-
-
- /**
- * Create an empty loca table without updating checksum
- */
- private void createLoca(int size) throws IOException {
- pad4();
- locaOffset = currentPos;
- writeULong(locaDirOffset + 4, currentPos);
- writeULong(locaDirOffset + 8, size * 4 + 4);
- currentPos += size * 4 + 4;
- realSize += size * 4 + 4;
- }
-
-
- /**
- * Copy the maxp table as is from original font to subset font
- * and set num glyphs to size
- */
- private void createMaxp(FontFileReader in, int size) throws IOException {
- TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("maxp");
- if (entry != null) {
- pad4();
- seekTab(in, "maxp", 0);
- System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
- 0, output, currentPos, (int)entry.getLength());
- writeUShort(currentPos + 4, size);
-
- int checksum = getCheckSum(currentPos, (int)entry.getLength());
- writeULong(maxpDirOffset, checksum);
- writeULong(maxpDirOffset + 4, currentPos);
- writeULong(maxpDirOffset + 8, (int)entry.getLength());
- currentPos += (int)entry.getLength();
- realSize += (int)entry.getLength();
- } else {
- throw new IOException("Can't find maxp table");
- }
- }
-
-
- /**
- * Copy the prep table as is from original font to subset font
- */
- private boolean createPrep(FontFileReader in) throws IOException {
- TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("prep");
- if (entry != null) {
- pad4();
- seekTab(in, "prep", 0);
- System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
- 0, output, currentPos, (int)entry.getLength());
-
- int checksum = getCheckSum(currentPos, (int)entry.getLength());
- writeULong(prepDirOffset, checksum);
- writeULong(prepDirOffset + 4, currentPos);
- writeULong(prepDirOffset + 8, (int)entry.getLength());
- currentPos += (int)entry.getLength();
- realSize += (int)entry.getLength();
- return true;
- } else {
- return false;
- }
- }
-
-
- /**
- * Copy the hhea table as is from original font to subset font
- * and fill in size of hmtx table
- */
- private void createHhea(FontFileReader in, int size) throws IOException {
- TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hhea");
- if (entry != null) {
- pad4();
- seekTab(in, "hhea", 0);
- System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
- 0, output, currentPos, (int)entry.getLength());
- writeUShort((int)entry.getLength() + currentPos - 2, size);
-
- int checksum = getCheckSum(currentPos, (int)entry.getLength());
- writeULong(hheaDirOffset, checksum);
- writeULong(hheaDirOffset + 4, currentPos);
- writeULong(hheaDirOffset + 8, (int)entry.getLength());
- currentPos += (int)entry.getLength();
- realSize += (int)entry.getLength();
- } else {
- throw new IOException("Can't find hhea table");
- }
- }
-
-
- /**
- * Copy the head table as is from original font to subset font
- * and set indexToLocaFormat to long and set
- * checkSumAdjustment to 0, store offset to checkSumAdjustment
- * in checkSumAdjustmentOffset
- */
- private void createHead(FontFileReader in) throws IOException {
- TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("head");
- if (entry != null) {
- pad4();
- seekTab(in, "head", 0);
- System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
- 0, output, currentPos, (int)entry.getLength());
-
- checkSumAdjustmentOffset = currentPos + 8;
- output[currentPos + 8] = 0; // Set checkSumAdjustment to 0
- output[currentPos + 9] = 0;
- output[currentPos + 10] = 0;
- output[currentPos + 11] = 0;
- output[currentPos + 50] = 0; // long locaformat
- output[currentPos + 51] = 1; // long locaformat
-
- int checksum = getCheckSum(currentPos, (int)entry.getLength());
- writeULong(headDirOffset, checksum);
- writeULong(headDirOffset + 4, currentPos);
- writeULong(headDirOffset + 8, (int)entry.getLength());
-
- currentPos += (int)entry.getLength();
- realSize += (int)entry.getLength();
- } else {
- throw new IOException("Can't find head table");
- }
- }
-
-
- /**
- * Create the glyf table and fill in loca table
- */
- private void createGlyf(FontFileReader in,
- Map glyphs) throws IOException {
- TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf");
- int size = 0;
- int start = 0;
- int endOffset = 0; // Store this as the last loca
- if (entry != null) {
- pad4();
- start = currentPos;
-
- /* Loca table must be in order by glyph index, so build
- * an array first and then write the glyph info and
- * location offset.
- */
- int[] origIndexes = new int[glyphs.size()];
-
- Iterator e = glyphs.keySet().iterator();
- while (e.hasNext()) {
- Integer origIndex = (Integer)e.next();
- Integer subsetIndex = (Integer)glyphs.get(origIndex);
- origIndexes[subsetIndex.intValue()] = origIndex.intValue();
- }
-
- for (int i = 0; i < origIndexes.length; i++) {
- int glyphLength = 0;
- int nextOffset = 0;
- int origGlyphIndex = origIndexes[i];
- if (origGlyphIndex >= (mtxTab.length - 1)) {
- nextOffset = (int)lastLoca;
- } else {
- nextOffset = (int)mtxTab[origGlyphIndex + 1].getOffset();
- }
- glyphLength = nextOffset - (int)mtxTab[origGlyphIndex].getOffset();
-
- // Copy glyph
- System.arraycopy(
- in.getBytes((int)entry.getOffset() + (int)mtxTab[origGlyphIndex].getOffset(),
- glyphLength), 0,
- output, currentPos,
- glyphLength);
-
-
- // Update loca table
- writeULong(locaOffset + i * 4, currentPos - start);
- if ((currentPos - start + glyphLength) > endOffset) {
- endOffset = (currentPos - start + glyphLength);
- }
-
- currentPos += glyphLength;
- realSize += glyphLength;
-
- }
-
- size = currentPos - start;
-
- int checksum = getCheckSum(start, size);
- writeULong(glyfDirOffset, checksum);
- writeULong(glyfDirOffset + 4, start);
- writeULong(glyfDirOffset + 8, size);
- currentPos += 12;
- realSize += 12;
-
- // Update loca checksum and last loca index
- writeULong(locaOffset + glyphs.size() * 4, endOffset);
-
- checksum = getCheckSum(locaOffset, glyphs.size() * 4 + 4);
- writeULong(locaDirOffset, checksum);
- } else {
- throw new IOException("Can't find glyf table");
- }
- }
-
-
- /**
- * Create the hmtx table by copying metrics from original
- * font to subset font. The glyphs Map contains an
- * Integer key and Integer value that maps the original
- * metric (key) to the subset metric (value)
- */
- private void createHmtx(FontFileReader in,
- Map glyphs) throws IOException {
- TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hmtx");
-
- int longHorMetricSize = glyphs.size() * 2;
- int leftSideBearingSize = glyphs.size() * 2;
- int hmtxSize = longHorMetricSize + leftSideBearingSize;
-
- if (entry != null) {
- pad4();
- //int offset = (int)entry.offset;
- Iterator e = glyphs.keySet().iterator();
- while (e.hasNext()) {
- Integer origIndex = (Integer)e.next();
- Integer subsetIndex = (Integer)glyphs.get(origIndex);
-
- writeUShort(currentPos + subsetIndex.intValue() * 4,
- mtxTab[origIndex.intValue()].getWx());
- writeUShort(currentPos + subsetIndex.intValue() * 4 + 2,
- mtxTab[origIndex.intValue()].getLsb());
- }
-
- int checksum = getCheckSum(currentPos, hmtxSize);
- writeULong(hmtxDirOffset, checksum);
- writeULong(hmtxDirOffset + 4, currentPos);
- writeULong(hmtxDirOffset + 8, hmtxSize);
- currentPos += hmtxSize;
- realSize += hmtxSize;
- } else {
- throw new IOException("Can't find hmtx table");
- }
- }
-
- /**
- * Returns a List containing the glyph itself plus all glyphs
- * that this composite glyph uses
- */
- private List<Integer> getIncludedGlyphs(FontFileReader in, int glyphOffset,
- Integer glyphIdx) throws IOException {
- List<Integer> ret = new java.util.ArrayList<Integer>();
- ret.add(glyphIdx);
- int offset = glyphOffset + (int)mtxTab[glyphIdx.intValue()].getOffset() + 10;
- Integer compositeIdx = null;
- int flags = 0;
- boolean moreComposites = true;
- while (moreComposites) {
- flags = in.readTTFUShort(offset);
- compositeIdx = Integer.valueOf(in.readTTFUShort(offset + 2));
- ret.add(compositeIdx);
-
- offset += 4;
- if ((flags & 1) > 0) {
- // ARG_1_AND_ARG_2_ARE_WORDS
- offset += 4;
- } else {
- offset += 2;
- }
-
- if ((flags & 8) > 0) {
- offset += 2; // WE_HAVE_A_SCALE
- } else if ((flags & 64) > 0) {
- offset += 4; // WE_HAVE_AN_X_AND_Y_SCALE
- } else if ((flags & 128) > 0) {
- offset += 8; // WE_HAVE_A_TWO_BY_TWO
- }
-
- if ((flags & 32) > 0) {
- moreComposites = true;
- } else {
- moreComposites = false;
- }
- }
-
- return ret;
- }
-
-
- /**
- * We need to remember which composites were already remapped because the value to be
- * remapped is being read from the TTF file and being replaced right there. Doing this
- * twice would create a bad map the second time.
- */
- private Set<Long> remappedComposites = null;
-
- /**
- * Rewrite all compositepointers in glyphindex glyphIdx
- */
- private void remapComposite(FontFileReader in, Map<Integer, Integer> glyphs,
- long glyphOffset,
- Integer glyphIdx) throws IOException {
- if (remappedComposites == null) {
- remappedComposites = new java.util.HashSet<Long>();
- }
- TTFMtxEntry mtxEntry = mtxTab[glyphIdx.intValue()];
- long offset = glyphOffset + mtxEntry.getOffset() + 10;
-
- //Avoid duplicate remapping (see javadoc for remappedComposites above)
- if (!remappedComposites.contains(offset)) {
- remappedComposites.add(offset);
- innerRemapComposite(in, glyphs, offset);
- }
- }
-
- private void innerRemapComposite(FontFileReader in, Map<Integer, Integer> glyphs, long offset)
- throws IOException {
- Integer compositeIdx = null;
- int flags = 0;
- boolean moreComposites = true;
-
- while (moreComposites) {
- flags = in.readTTFUShort(offset);
- compositeIdx = Integer.valueOf(in.readTTFUShort(offset + 2));
- Integer newIdx = glyphs.get(compositeIdx);
- if (newIdx == null) {
- // This errormessage would look much better
- // if the fontname was printed to
- //log.error("An embedded font "
- // + "contains bad glyph data. "
- // + "Characters might not display "
- // + "correctly.");
- moreComposites = false;
- continue;
- }
-
- in.writeTTFUShort((int)(offset + 2), newIdx.intValue());
-
- offset += 4;
-
- if ((flags & 1) > 0) {
- // ARG_1_AND_ARG_2_ARE_WORDS
- offset += 4;
- } else {
- offset += 2;
- }
-
- if ((flags & 8) > 0) {
- offset += 2; // WE_HAVE_A_SCALE
- } else if ((flags & 64) > 0) {
- offset += 4; // WE_HAVE_AN_X_AND_Y_SCALE
- } else if ((flags & 128) > 0) {
- offset += 8; // WE_HAVE_A_TWO_BY_TWO
- }
-
- if ((flags & 32) > 0) {
- moreComposites = true;
- } else {
- moreComposites = false;
- }
- }
- }
-
-
- /**
- * Scan all the original glyphs for composite glyphs and add those glyphs
- * to the glyphmapping also rewrite the composite glyph pointers to the new
- * mapping
- */
- private void scanGlyphs(FontFileReader in,
- Map<Integer, Integer> glyphs) throws IOException {
- TTFDirTabEntry glyfTable = (TTFDirTabEntry)dirTabs.get("glyf");
- Map<Integer, Integer> newComposites = null;
- Set<Integer> allComposites = new java.util.HashSet<Integer>();
-
- int newIndex = glyphs.size();
-
- if (glyfTable != null) {
- while (newComposites == null || newComposites.size() > 0) {
- // Inefficient to iterate through all glyphs
- newComposites = new java.util.HashMap<Integer, Integer>();
-
- for (int origIndex : glyphs.keySet()) {
- short numberOfContours = in.readTTFShort(glyfTable.getOffset()
- + mtxTab[origIndex].getOffset());
- if (numberOfContours < 0) {
- // origIndex is a composite glyph
- allComposites.add(origIndex);
- List<Integer> composites
- = getIncludedGlyphs(in, (int)glyfTable.getOffset(),
- origIndex);
-
- if (log.isTraceEnabled()) {
- log.trace("Glyph " + origIndex
- + " is a composite glyph using the following glyphs: "
- + composites);
- }
-
- // Iterate through all composites pointed to
- // by this composite and check if they exists
- // in the glyphs map, add them if not.
- for (int cIdx : composites) {
- if (glyphs.get(cIdx) == null
- && newComposites.get(cIdx) == null) {
- newComposites.put(cIdx, newIndex);
- newIndex++;
- }
- }
- }
- }
-
- // Add composites to glyphs
- for (int im : newComposites.keySet()) {
- glyphs.put(im, newComposites.get(im));
- }
- }
-
- // Iterate through all composites to remap their composite index
- for (int glyphIdx : allComposites) {
- remapComposite(in, glyphs, glyfTable.getOffset(), glyphIdx);
- }
-
- } else {
- throw new IOException("Can't find glyf table");
- }
- }
-
-
-
- /**
- * Returns a subset of the original font.
- *
- * @param in FontFileReader to read from
- * @param name Name to be checked for in the font file
- * @param glyphs Map of glyphs (glyphs has old index as (Integer) key and
- * new index as (Integer) value)
- * @return A subset of the original font
- * @throws IOException in case of an I/O problem
- */
- public byte[] readFont(FontFileReader in, String name,
- Map<Integer, Integer> glyphs) throws IOException {
-
- //Check if TrueType collection, and that the name exists in the collection
- if (!checkTTC(in, name)) {
- throw new IOException("Failed to read font");
- }
-
- //Copy the Map as we're going to modify it
- Map<Integer, Integer> subsetGlyphs = new java.util.HashMap<Integer, Integer>(glyphs);
-
- output = new byte[in.getFileSize()];
-
- readDirTabs(in);
- readFontHeader(in);
- getNumGlyphs(in);
- readHorizontalHeader(in);
- readHorizontalMetrics(in);
- readIndexToLocation(in);
-
- scanGlyphs(in, subsetGlyphs);
-
- createDirectory(); // Create the TrueType header and directory
-
- createHead(in);
- createHhea(in, subsetGlyphs.size()); // Create the hhea table
- createHmtx(in, subsetGlyphs); // Create hmtx table
- createMaxp(in, subsetGlyphs.size()); // copy the maxp table
-
- boolean optionalTableFound;
- optionalTableFound = createCvt(in); // copy the cvt table
- if (!optionalTableFound) {
- // cvt is optional (used in TrueType fonts only)
- log.debug("TrueType: ctv table not present. Skipped.");
- }
-
- optionalTableFound = createFpgm(in); // copy fpgm table
- if (!optionalTableFound) {
- // fpgm is optional (used in TrueType fonts only)
- log.debug("TrueType: fpgm table not present. Skipped.");
- }
-
- optionalTableFound = createPrep(in); // copy prep table
- if (!optionalTableFound) {
- // prep is optional (used in TrueType fonts only)
- log.debug("TrueType: prep table not present. Skipped.");
- }
-
- createLoca(subsetGlyphs.size()); // create empty loca table
- createGlyf(in, subsetGlyphs); //create glyf table and update loca table
-
- pad4();
- createCheckSumAdjustment();
-
- byte[] ret = new byte[realSize];
- System.arraycopy(output, 0, ret, 0, realSize);
-
- return ret;
- }
-
- /**
- * writes a ISO-8859-1 string at the currentPosition
- * updates currentPosition but not realSize
- * @return number of bytes written
- */
- private int writeString(String str) {
- int length = 0;
- try {
- byte[] buf = str.getBytes("ISO-8859-1");
- System.arraycopy(buf, 0, output, currentPos, buf.length);
- length = buf.length;
- currentPos += length;
- } catch (java.io.UnsupportedEncodingException e) {
- // This should never happen!
- }
-
- return length;
- }
-
- /**
- * Appends a byte to the output array,
- * updates currentPost but not realSize
- */
- private void writeByte(byte b) {
- output[currentPos++] = b;
- }
-
- /**
- * Appends a USHORT to the output array,
- * updates currentPost but not realSize
- */
- private void writeUShort(int s) {
- byte b1 = (byte)((s >> 8) & 0xff);
- byte b2 = (byte)(s & 0xff);
- writeByte(b1);
- writeByte(b2);
- }
-
- /**
- * Appends a USHORT to the output array,
- * at the given position without changing currentPos
- */
- private void writeUShort(int pos, int s) {
- byte b1 = (byte)((s >> 8) & 0xff);
- byte b2 = (byte)(s & 0xff);
- output[pos] = b1;
- output[pos + 1] = b2;
- }
-
- /**
- * Appends a ULONG to the output array,
- * updates currentPos but not realSize
- */
- private void writeULong(int s) {
- byte b1 = (byte)((s >> 24) & 0xff);
- byte b2 = (byte)((s >> 16) & 0xff);
- byte b3 = (byte)((s >> 8) & 0xff);
- byte b4 = (byte)(s & 0xff);
- writeByte(b1);
- writeByte(b2);
- writeByte(b3);
- writeByte(b4);
- }
-
- /**
- * Appends a ULONG to the output array,
- * at the given position without changing currentPos
- */
- private void writeULong(int pos, int s) {
- byte b1 = (byte)((s >> 24) & 0xff);
- byte b2 = (byte)((s >> 16) & 0xff);
- byte b3 = (byte)((s >> 8) & 0xff);
- byte b4 = (byte)(s & 0xff);
- output[pos] = b1;
- output[pos + 1] = b2;
- output[pos + 2] = b3;
- output[pos + 3] = b4;
- }
-
- /**
- * Read a signed short value at given position
- */
- private short readShort(int pos) {
- int ret = readUShort(pos);
- return (short)ret;
- }
-
- /**
- * Read a unsigned short value at given position
- */
- private int readUShort(int pos) {
- int ret = output[pos];
- if (ret < 0) {
- ret += 256;
- }
- ret = ret << 8;
- if (output[pos + 1] < 0) {
- ret |= output[pos + 1] + 256;
- } else {
- ret |= output[pos + 1];
- }
-
- return ret;
- }
-
- /**
- * Create a padding in the fontfile to align
- * on a 4-byte boundary
- */
- private void pad4() {
- int padSize = currentPos % 4;
- for (int i = 0; i < padSize; i++) {
- output[currentPos++] = 0;
- realSize++;
- }
- }
-
- /**
- * Returns the maximum power of 2 <= max
- */
- private int maxPow2(int max) {
- int i = 0;
- while (Math.pow(2, i) < max) {
- i++;
- }
-
- return (i - 1);
- }
-
- private int log2(int num) {
- return (int)(Math.log(num) / Math.log(2));
- }
-
-
- private int getCheckSum(int start, int size) {
- return (int)getLongCheckSum(start, size);
- }
-
- private long getLongCheckSum(int start, int size) {
- // All the tables here are aligned on four byte boundaries
- // Add remainder to size if it's not a multiple of 4
- int remainder = size % 4;
- if (remainder != 0) {
- size += remainder;
- }
-
- long sum = 0;
-
- for (int i = 0; i < size; i += 4) {
- int l = (output[start + i] << 24);
- l += (output[start + i + 1] << 16);
- l += (output[start + i + 2] << 16);
- l += (output[start + i + 3] << 16);
- sum += l;
- if (sum > 0xffffffff) {
- sum = sum - 0xffffffff;
- }
- }
-
- return sum;
- }
-
- private void createCheckSumAdjustment() {
- long sum = getLongCheckSum(0, realSize);
- int checksum = (int)(0xb1b0afba - sum);
- writeULong(checkSumAdjustmentOffset, checksum);
- }
-
- }
-
-
|