home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / awt / font / TextJustifier.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  7.8 KB  |  226 lines

  1. /*
  2.  * @(#)TextJustifier.java    1.11 98/03/18
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. /*
  16.  * (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
  17.  * (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
  18.  *
  19.  * The original version of this source code and documentation is
  20.  * copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
  21.  * of IBM. These materials are provided under terms of a License
  22.  * Agreement between Taligent and Sun. This technology is protected
  23.  * by multiple US and International patents.
  24.  *
  25.  * This notice and attribution to Taligent may not be removed.
  26.  * Taligent is a registered trademark of Taligent, Inc.
  27.  *
  28.  */
  29.  
  30. package java.awt.font;
  31.  
  32. /*
  33.  * one info for each side of each glyph
  34.  * separate infos for grow and shrink case
  35.  * !!! this doesn't really need to be a separate class.  If we keep it
  36.  * separate, probably the newJustify code from TextLayout belongs here as well.
  37.  */
  38.  
  39. class TextJustifier {
  40.     private GlyphJustificationInfo[] info;
  41.     private int start;
  42.     private int limit;
  43.  
  44.     static boolean DEBUG = false;
  45.  
  46.     /**
  47.      * Initialize the justifier with an array of infos corresponding to each
  48.      * glyph. Start and limit indicate the range of the array to examine.
  49.      */
  50.     TextJustifier(GlyphJustificationInfo[] info, int start, int limit) {
  51.         this.info = info;
  52.         this.start = start;
  53.         this.limit = limit;
  54.  
  55.         if (DEBUG) {
  56.             System.out.println("start: " + start + ", limit: " + limit);
  57.             for (int i = start; i < limit; i++) {
  58.                 GlyphJustificationInfo gji = info[i];
  59.                 System.out.println("w: " + gji.weight + ", gp: " +
  60.                                    gji.growPriority + ", gll: " +
  61.                                    gji.growLeftLimit + ", grl: " +
  62.                                    gji.growRightLimit);
  63.             }
  64.         }
  65.     }
  66.  
  67.     public static final int MAX_PRIORITY = 3;
  68.  
  69.     /**
  70.      * Return an array of deltas twice as long as the original info array,
  71.      * indicating the amount by which each side of each glyph should grow
  72.      * or shrink.
  73.      *
  74.      * Delta should be positive to expand the line, and negative to compress it.
  75.      */
  76.     public float[] justify(float delta) {
  77.         float[] deltas = new float[info.length * 2];
  78.  
  79.         boolean grow = delta > 0;
  80.  
  81.         if (DEBUG)
  82.             System.out.println("delta: " + delta);
  83.  
  84.         // make separate passes through glyphs in order of decreasing priority
  85.         // until justifyDelta is zero or we run out of priorities.
  86.         int fallbackPriority = -1;
  87.         for (int p = 0; delta != 0; p++) {
  88.             /*
  89.              * special case 'fallback' iteration, set flag and recheck
  90.              * highest priority
  91.              */
  92.             boolean lastPass = p > MAX_PRIORITY;
  93.             if (lastPass)
  94.                 p = fallbackPriority;
  95.  
  96.             // pass through glyphs, first collecting weights and limits
  97.             float weight = 0;
  98.             float gslimit = 0;
  99.             float absorbweight = 0;
  100.             for (int i = start; i < limit; i++) {
  101.                 GlyphJustificationInfo gi = info[i];
  102.                 if ((grow ? gi.growPriority : gi.shrinkPriority) == p) {
  103.                     if (fallbackPriority == -1) {
  104.                         fallbackPriority = p;
  105.                     }
  106.  
  107.                     if (i != start) { // ignore left of first character
  108.                         weight += gi.weight;
  109.                         if (grow) {
  110.                             gslimit += gi.growLeftLimit;
  111.                             if (gi.growAbsorb) {
  112.                                 absorbweight += weight;
  113.                             }
  114.                         } else {
  115.                             gslimit += gi.shrinkLeftLimit;
  116.                             if (gi.shrinkAbsorb) {
  117.                                 absorbweight += weight;
  118.                             }
  119.                         }
  120.                     }
  121.  
  122.                     if (i + 1 != limit) { // ignore right of last character
  123.                         weight += gi.weight;
  124.                         if (grow) {
  125.                             gslimit += gi.growRightLimit;
  126.                             if (gi.growAbsorb) {
  127.                                 absorbweight += weight;
  128.                             }
  129.                         } else {
  130.                             gslimit += gi.shrinkRightLimit;
  131.                             if (gi.shrinkAbsorb) {
  132.                                 absorbweight += weight;
  133.                             }
  134.                         }
  135.                     }
  136.                 }
  137.             }
  138.  
  139.             // did we hit the limit?
  140.             if (!grow) {
  141.                 gslimit = -gslimit; // negative for negative deltas
  142.             }
  143.             boolean hitLimit = !lastPass && ((delta < 0) == (delta < gslimit));
  144.             boolean absorbing = hitLimit && absorbweight > 0;
  145.  
  146.             // predivide delta by weight
  147.             float weightedDelta = delta / weight;
  148.  
  149.             float weightedAbsorb = 0;
  150.             if (hitLimit && absorbweight > 0) {
  151.                 weightedAbsorb = (delta - gslimit) / absorbweight;
  152.             }
  153.  
  154.             if (DEBUG) {
  155.                 System.out.println("pass: " + p +
  156.                     ", w: " + weight +
  157.                     ", l: " + gslimit +
  158.                     ", hit: " + (hitLimit ? "y" : "n"));
  159.             }
  160.  
  161.             // now allocate this based on ratio of weight to total weight
  162.             int n = start * 2;
  163.             for (int i = start; i < limit; i++) {
  164.                 GlyphJustificationInfo gi = info[i];
  165.                 if ((grow ? gi.growPriority : gi.shrinkPriority) == p) {
  166.                     if (i != start) { // ignore left
  167.                         float d;
  168.                         if (hitLimit) {
  169.                             // factor in sign
  170.                             d = grow ? gi.growLeftLimit : -gi.shrinkLeftLimit; 
  171.                             if (absorbing) {
  172.                                 // sign factored in already
  173.                                d += gi.weight * weightedAbsorb; 
  174.                             }
  175.                         } else {
  176.                             // sign factored in already
  177.                             d = gi.weight * weightedDelta; 
  178.                         }
  179.  
  180.                         deltas[n] += d;
  181.                     }
  182.                     n++;
  183.  
  184.                     if (i + 1 != limit) { // ignore right
  185.                         float d;
  186.                         if (hitLimit) {
  187.                             d = grow ? gi.growRightLimit : -gi.shrinkRightLimit;
  188.                             if (absorbing) {
  189.                                 d += gi.weight * weightedAbsorb;
  190.                             }
  191.                         } else {
  192.                             d = gi.weight * weightedDelta;
  193.                         }
  194.  
  195.                         deltas[n] += d;
  196.                     }
  197.                     n++;
  198.                 } else {
  199.                     n += 2;
  200.                 }
  201.             }
  202.  
  203.             if (hitLimit && !absorbing) {
  204.                 delta -= gslimit;
  205.             } else {
  206.                 delta = 0; // stop iteration
  207.             }
  208.         }
  209.  
  210.         if (DEBUG) {
  211.             float total = 0;
  212.             for (int i = 0; i < deltas.length; i++) {
  213.                 total += deltas[i];
  214.                 System.out.print(deltas[i] + ", ");
  215.                 if (i % 20 == 9) {
  216.                     System.out.println();
  217.                 }
  218.             }
  219.             System.out.println("\ntotal: " + total);
  220.             System.out.println();
  221.         }
  222.  
  223.         return deltas;
  224.     }
  225. }
  226.