TextJustifierpublic class TextJustifier extends Object
Fields Summary |
---|
private GlyphJustificationInfo[] | info | private int | start | private int | limit | static boolean | DEBUG | public static final int | MAX_PRIORITY |
Constructors Summary |
---|
TextJustifier(GlyphJustificationInfo[] info, int start, int limit)Initialize the justifier with an array of infos corresponding to each
glyph. Start and limit indicate the range of the array to examine.
this.info = info;
this.start = start;
this.limit = limit;
if (DEBUG) {
System.out.println("start: " + start + ", limit: " + limit);
for (int i = start; i < limit; i++) {
GlyphJustificationInfo gji = info[i];
System.out.println("w: " + gji.weight + ", gp: " +
gji.growPriority + ", gll: " +
gji.growLeftLimit + ", grl: " +
gji.growRightLimit);
}
}
|
Methods Summary |
---|
public float[] | justify(float delta)Return an array of deltas twice as long as the original info array,
indicating the amount by which each side of each glyph should grow
or shrink.
Delta should be positive to expand the line, and negative to compress it.
float[] deltas = new float[info.length * 2];
boolean grow = delta > 0;
if (DEBUG)
System.out.println("delta: " + delta);
// make separate passes through glyphs in order of decreasing priority
// until justifyDelta is zero or we run out of priorities.
int fallbackPriority = -1;
for (int p = 0; delta != 0; p++) {
/*
* special case 'fallback' iteration, set flag and recheck
* highest priority
*/
boolean lastPass = p > MAX_PRIORITY;
if (lastPass)
p = fallbackPriority;
// pass through glyphs, first collecting weights and limits
float weight = 0;
float gslimit = 0;
float absorbweight = 0;
for (int i = start; i < limit; i++) {
GlyphJustificationInfo gi = info[i];
if ((grow ? gi.growPriority : gi.shrinkPriority) == p) {
if (fallbackPriority == -1) {
fallbackPriority = p;
}
if (i != start) { // ignore left of first character
weight += gi.weight;
if (grow) {
gslimit += gi.growLeftLimit;
if (gi.growAbsorb) {
absorbweight += gi.weight;
}
} else {
gslimit += gi.shrinkLeftLimit;
if (gi.shrinkAbsorb) {
absorbweight += gi.weight;
}
}
}
if (i + 1 != limit) { // ignore right of last character
weight += gi.weight;
if (grow) {
gslimit += gi.growRightLimit;
if (gi.growAbsorb) {
absorbweight += gi.weight;
}
} else {
gslimit += gi.shrinkRightLimit;
if (gi.shrinkAbsorb) {
absorbweight += gi.weight;
}
}
}
}
}
// did we hit the limit?
if (!grow) {
gslimit = -gslimit; // negative for negative deltas
}
boolean hitLimit = (weight == 0) || (!lastPass && ((delta < 0) == (delta < gslimit)));
boolean absorbing = hitLimit && absorbweight > 0;
// predivide delta by weight
float weightedDelta = delta / weight; // not used if weight == 0
float weightedAbsorb = 0;
if (hitLimit && absorbweight > 0) {
weightedAbsorb = (delta - gslimit) / absorbweight;
}
if (DEBUG) {
System.out.println("pass: " + p +
", d: " + delta +
", l: " + gslimit +
", w: " + weight +
", aw: " + absorbweight +
", wd: " + weightedDelta +
", wa: " + weightedAbsorb +
", hit: " + (hitLimit ? "y" : "n"));
}
// now allocate this based on ratio of weight to total weight
int n = start * 2;
for (int i = start; i < limit; i++) {
GlyphJustificationInfo gi = info[i];
if ((grow ? gi.growPriority : gi.shrinkPriority) == p) {
if (i != start) { // ignore left
float d;
if (hitLimit) {
// factor in sign
d = grow ? gi.growLeftLimit : -gi.shrinkLeftLimit;
if (absorbing) {
// sign factored in already
d += gi.weight * weightedAbsorb;
}
} else {
// sign factored in already
d = gi.weight * weightedDelta;
}
deltas[n] += d;
}
n++;
if (i + 1 != limit) { // ignore right
float d;
if (hitLimit) {
d = grow ? gi.growRightLimit : -gi.shrinkRightLimit;
if (absorbing) {
d += gi.weight * weightedAbsorb;
}
} else {
d = gi.weight * weightedDelta;
}
deltas[n] += d;
}
n++;
} else {
n += 2;
}
}
if (!lastPass && hitLimit && !absorbing) {
delta -= gslimit;
} else {
delta = 0; // stop iteration
}
}
if (DEBUG) {
float total = 0;
for (int i = 0; i < deltas.length; i++) {
total += deltas[i];
System.out.print(deltas[i] + ", ");
if (i % 20 == 9) {
System.out.println();
}
}
System.out.println("\ntotal: " + total);
System.out.println();
}
return deltas;
|
|