Revision: 11897
http://sourceforge.net/p/foray/code/11897
Author: victormote
Date: 2021-02-07 23:16:58 +0000 (Sun, 07 Feb 2021)
Log Message:
-----------
Convert subsetting logic from char[] to IntArrayBuilder.
Modified Paths:
--------------
trunk/foray/foray-font/src/main/java/org/foray/font/Subset.java
Modified: trunk/foray/foray-font/src/main/java/org/foray/font/Subset.java
===================================================================
--- trunk/foray/foray-font/src/main/java/org/foray/font/Subset.java 2021-02-07 19:56:45 UTC (rev 11896)
+++ trunk/foray/foray-font/src/main/java/org/foray/font/Subset.java 2021-02-07 23:16:58 UTC (rev 11897)
@@ -29,7 +29,7 @@
package org.foray.font;
import org.foray.common.WellKnownConstants;
-import org.foray.common.primitive.StringUtils;
+import org.foray.common.sequence.IntArrayBuilder;
import org.axsl.ps.Encoding;
@@ -36,11 +36,6 @@
/**
* Keeps track of which glyphs are included in a subset, and provides methods to convert indexes back and forth between
* the original complete font and the subset font.
- *
- * <p>Design Note: Although the internals of this class will only handle
- * 16-bit font indexes, the API deliberately uses ints (31 unsigned bits)
- * instead of chars. This way the internals can be expanded in the future if
- * necessary, without changing the API.</p>
*/
public class Subset {
@@ -61,34 +56,28 @@
* The index is used as a key to retrieve the related subset index from {@link #subsetByOriginal}.
* This array is sorted in parallel with {@link #subsetByOriginal}.
*/
- private char[] originalByOriginal;
+ private IntArrayBuilder originalByOriginal;
/**
* Array whose elements are the glyph indices for the subset font, and whose index is used as a key that corresponds
* to the same index in {@link #originalByOriginal}.
*/
- private char[] subsetByOriginal;
+ private IntArrayBuilder subsetByOriginal;
/**
* Array whose elements are the actually-used glyph indices for the original full font, sorted by subset index.
*/
- private char[] originalBySubset;
+ private IntArrayBuilder originalBySubset;
/**
- * The number of subset glyphs used so far. It should be incremented after
- * creating new subset glyphs.
- */
- private int qtyGlyphs = 0;
-
- /**
* Constructor.
* @param consumerFont The parent ConsumerFont instance.
*/
public Subset(final ConsumerFont4a consumerFont) {
this.consumerFont = consumerFont;
- this.originalByOriginal = new char[this.arraySizeIncrement];
- this.subsetByOriginal = new char[this.arraySizeIncrement];
- this.originalBySubset = new char[this.arraySizeIncrement];
+ this.originalByOriginal = new IntArrayBuilder(this.arraySizeIncrement);
+ this.subsetByOriginal = new IntArrayBuilder(this.arraySizeIncrement);
+ this.originalBySubset = new IntArrayBuilder(this.arraySizeIncrement);
if (this.consumerFont.getFOrayFont() instanceof FsTrueTypeFont) {
// Make sure that the 3 first glyphs are included
this.encodeSubsetIndex((char) 0);
@@ -104,13 +93,11 @@
* @return The index into the subsetted glyphs.
*/
public int encodeSubsetIndex(final int fontGlyphIndex) {
- final int index = StringUtils.indexOfSortedCharArray(
- this.originalByOriginal, (char) fontGlyphIndex, 0,
- this.numGlyphsUsed() - 1);
+ final int index = this.originalByOriginal.binarySearch(fontGlyphIndex);
if (index < 0) {
return addMapping(fontGlyphIndex);
}
- return this.subsetByOriginal[index];
+ return this.subsetByOriginal.intAt(index);
}
/**
@@ -121,10 +108,10 @@
*/
public int decodeSubsetIndex(final int subsetGlyphIndex) {
if (subsetGlyphIndex < 0
- || subsetGlyphIndex > this.qtyGlyphs) {
+ || subsetGlyphIndex > this.originalByOriginal.length()) {
return Character.MAX_VALUE;
}
- return this.originalBySubset[subsetGlyphIndex];
+ return this.originalBySubset.intAt(subsetGlyphIndex);
}
/**
@@ -133,40 +120,29 @@
* @return The subset index for the new glyph.
*/
private char addMapping(final int glyphIndex) {
- if (this.qtyGlyphs >= this.originalByOriginal.length) {
- this.addCapacity(this.arraySizeIncrement);
- }
- final int newIndex = this.qtyGlyphs;
-
- final int insertionPoint = findInsertionPoint((char) glyphIndex);
- /* Move all past the insertion point to the next higher index. */
- for (int i = newIndex; i > insertionPoint; i--) {
- this.originalByOriginal[i] = this.originalByOriginal[i - 1];
- this.subsetByOriginal[i] = this.subsetByOriginal[i - 1];
- }
- /* Now move the new items into place. */
- this.originalByOriginal[insertionPoint] = (char) glyphIndex;
- this.subsetByOriginal[insertionPoint] = (char) newIndex;
-
- this.originalBySubset[newIndex] = (char) glyphIndex;
-
- this.qtyGlyphs ++;
+ final int newIndex = this.originalByOriginal.length();
+ this.originalByOriginal.append(glyphIndex);
+ this.subsetByOriginal.append(newIndex);
+ this.originalBySubset.append(glyphIndex);
+ sortByOriginal();
return (char) newIndex;
}
- /**
- * Finds the index in {@link #originalByOriginal} where the new item should
- * be inserted in order to keep it sorted properly.
- * @param glyphIndex The index that is being added.
- * @return The index where the new item should be inserted.
- */
- private int findInsertionPoint(final char glyphIndex) {
- for (int i = 0; i < this.numGlyphsUsed(); i++) {
- if (glyphIndex < this.originalByOriginal[i]) {
- return i;
+ private void sortByOriginal() {
+ /* Since these arrays are always sorted, and since we appended the new entries, if we start at the end and
+ * work backwards, this should require only one pass. */
+ boolean stillSorting = true;
+ while (stillSorting) {
+ stillSorting = false;
+ for (int i = this.originalByOriginal.length() - 1; i > 0; i--) {
+ if (this.originalByOriginal.intAt(i) < this.originalByOriginal.intAt(i - 1)) {
+ /* The are out of order. Swap them. */
+ this.originalByOriginal.swap(i, i - 1);
+ this.subsetByOriginal.swap(i, i - 1);
+ stillSorting = true;
+ }
}
}
- return this.numGlyphsUsed();
}
/**
@@ -199,9 +175,7 @@
stillSorting = true;
/* First, switch the originalBySubset array. */
- final char saveChar = this.originalBySubset[i];
- this.originalBySubset[i] = this.originalBySubset[i - 1];
- this.originalBySubset[i - 1] = saveChar;
+ this.originalBySubset.swap(i, i - 1);
/* Second, note that the originalByOriginal array needs
* no changes. */
@@ -208,17 +182,13 @@
/* Third, change the subsetByOriginal array element for
* the previous element. */
- int commonIndex = StringUtils.indexOfSortedCharArray(
- this.originalByOriginal, previousOriginalIndex, 0,
- this.numGlyphsUsed() - 1);
- this.subsetByOriginal[commonIndex] = i;
+ int commonIndex = this.originalByOriginal.binarySearch(previousOriginalIndex);
+ this.subsetByOriginal.setIntAt(commonIndex, i); // [commonIndex] = i;
/* Fourth, change the subsetByOriginal array element for
* the current element. */
- commonIndex = StringUtils.indexOfSortedCharArray(
- this.originalByOriginal, currentOriginalIndex, 0,
- this.numGlyphsUsed() - 1);
- this.subsetByOriginal[commonIndex] = (char) (i - 1);
+ commonIndex = this.originalByOriginal.binarySearch(currentOriginalIndex);
+ this.subsetByOriginal.setIntAt(commonIndex, i - 1); // [commonIndex] = (char) (i - 1);
}
}
}
@@ -229,51 +199,16 @@
* @return The number of glyphs in this subset.
*/
public int numGlyphsUsed() {
- return this.qtyGlyphs;
+ return this.originalByOriginal.length();
}
/**
- * Increases the size of the arrays by {@code capacityToAdd}.
- * @param capacityToAdd The number of elements to add to each of the
- * parallel arrays.
- */
- private void addCapacity(final int capacityToAdd) {
- // Can add, but not subtract.
- if (capacityToAdd < 1) {
- return;
- }
- final int newCapacity = this.originalByOriginal.length + capacityToAdd;
-
- // Increase size of originalByOriginal
- char[] newChars = new char[newCapacity];
- System.arraycopy(this.originalByOriginal, 0, newChars, 0,
- this.originalByOriginal.length);
- this.originalByOriginal = newChars;
-
- // Increase size of subsetByOriginal
- newChars = new char[newCapacity];
- System.arraycopy(this.subsetByOriginal, 0, newChars, 0,
- this.subsetByOriginal.length);
- this.subsetByOriginal = newChars;
-
- // Increase size of originalBySubset
- newChars = new char[newCapacity];
- System.arraycopy(this.originalBySubset, 0, newChars, 0,
- this.originalBySubset.length);
- this.originalBySubset = newChars;
-
- }
-
- /**
* Indicates whether a given glyph is in this subset.
- * @param originalGlyphIndex The original (full font) glyph index that is
- * being checked.
+ * @param originalGlyphIndex The original (full font) glyph index that is being checked.
* @return True iff originalGlyphIndex exists in this subset.
*/
public boolean glyphUsed(final int originalGlyphIndex) {
- final int index = StringUtils.indexOfSortedCharArray(
- this.originalByOriginal, (char) originalGlyphIndex, 0,
- this.numGlyphsUsed() - 1);
+ final int index = this.originalByOriginal.binarySearch(originalGlyphIndex);
return index > -1;
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|