FileDocCategorySizeDatePackage
TextJustifier.javaAPI DocJava SE 5 API7975Fri Aug 26 14:56:52 BST 2005java.awt.font

TextJustifier

public 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;