KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > awt > font > TextJustifier


1 /*
2  * @(#)TextJustifier.java 1.19 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 /*
9  * (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
10  * (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
11  *
12  * The original version of this source code and documentation is
13  * copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
14  * of IBM. These materials are provided under terms of a License
15  * Agreement between Taligent and Sun. This technology is protected
16  * by multiple US and International patents.
17  *
18  * This notice and attribution to Taligent may not be removed.
19  * Taligent is a registered trademark of Taligent, Inc.
20  *
21  */

22
23 package java.awt.font;
24
25 /*
26  * one info for each side of each glyph
27  * separate infos for grow and shrink case
28  * !!! this doesn't really need to be a separate class. If we keep it
29  * separate, probably the newJustify code from TextLayout belongs here as well.
30  */

31
32 class TextJustifier {
33     private GlyphJustificationInfo JavaDoc[] info;
34     private int start;
35     private int limit;
36
37     static boolean DEBUG = false;
38
39     /**
40      * Initialize the justifier with an array of infos corresponding to each
41      * glyph. Start and limit indicate the range of the array to examine.
42      */

43     TextJustifier(GlyphJustificationInfo JavaDoc[] info, int start, int limit) {
44         this.info = info;
45         this.start = start;
46         this.limit = limit;
47
48         if (DEBUG) {
49             System.out.println("start: " + start + ", limit: " + limit);
50             for (int i = start; i < limit; i++) {
51                 GlyphJustificationInfo JavaDoc gji = info[i];
52                 System.out.println("w: " + gji.weight + ", gp: " +
53                                    gji.growPriority + ", gll: " +
54                                    gji.growLeftLimit + ", grl: " +
55                                    gji.growRightLimit);
56             }
57         }
58     }
59
60     public static final int MAX_PRIORITY = 3;
61
62     /**
63      * Return an array of deltas twice as long as the original info array,
64      * indicating the amount by which each side of each glyph should grow
65      * or shrink.
66      *
67      * Delta should be positive to expand the line, and negative to compress it.
68      */

69     public float[] justify(float delta) {
70         float[] deltas = new float[info.length * 2];
71
72         boolean grow = delta > 0;
73
74         if (DEBUG)
75             System.out.println("delta: " + delta);
76
77         // make separate passes through glyphs in order of decreasing priority
78
// until justifyDelta is zero or we run out of priorities.
79
int fallbackPriority = -1;
80         for (int p = 0; delta != 0; p++) {
81             /*
82              * special case 'fallback' iteration, set flag and recheck
83              * highest priority
84              */

85             boolean lastPass = p > MAX_PRIORITY;
86             if (lastPass)
87                 p = fallbackPriority;
88
89             // pass through glyphs, first collecting weights and limits
90
float weight = 0;
91             float gslimit = 0;
92             float absorbweight = 0;
93             for (int i = start; i < limit; i++) {
94                 GlyphJustificationInfo JavaDoc gi = info[i];
95                 if ((grow ? gi.growPriority : gi.shrinkPriority) == p) {
96                     if (fallbackPriority == -1) {
97                         fallbackPriority = p;
98                     }
99
100                     if (i != start) { // ignore left of first character
101
weight += gi.weight;
102                         if (grow) {
103                             gslimit += gi.growLeftLimit;
104                             if (gi.growAbsorb) {
105                                 absorbweight += gi.weight;
106                             }
107                         } else {
108                             gslimit += gi.shrinkLeftLimit;
109                             if (gi.shrinkAbsorb) {
110                                 absorbweight += gi.weight;
111                             }
112                         }
113                     }
114
115                     if (i + 1 != limit) { // ignore right of last character
116
weight += gi.weight;
117                         if (grow) {
118                             gslimit += gi.growRightLimit;
119                             if (gi.growAbsorb) {
120                                 absorbweight += gi.weight;
121                             }
122                         } else {
123                             gslimit += gi.shrinkRightLimit;
124                             if (gi.shrinkAbsorb) {
125                                 absorbweight += gi.weight;
126                             }
127                         }
128                     }
129                 }
130             }
131
132             // did we hit the limit?
133
if (!grow) {
134                 gslimit = -gslimit; // negative for negative deltas
135
}
136             boolean hitLimit = (weight == 0) || (!lastPass && ((delta < 0) == (delta < gslimit)));
137             boolean absorbing = hitLimit && absorbweight > 0;
138
139             // predivide delta by weight
140
float weightedDelta = delta / weight; // not used if weight == 0
141

142             float weightedAbsorb = 0;
143             if (hitLimit && absorbweight > 0) {
144                 weightedAbsorb = (delta - gslimit) / absorbweight;
145             }
146
147             if (DEBUG) {
148                 System.out.println("pass: " + p +
149                     ", d: " + delta +
150                     ", l: " + gslimit +
151                     ", w: " + weight +
152                     ", aw: " + absorbweight +
153                     ", wd: " + weightedDelta +
154                     ", wa: " + weightedAbsorb +
155                     ", hit: " + (hitLimit ? "y" : "n"));
156             }
157
158             // now allocate this based on ratio of weight to total weight
159
int n = start * 2;
160             for (int i = start; i < limit; i++) {
161                 GlyphJustificationInfo JavaDoc gi = info[i];
162                 if ((grow ? gi.growPriority : gi.shrinkPriority) == p) {
163                     if (i != start) { // ignore left
164
float d;
165                         if (hitLimit) {
166                             // factor in sign
167
d = grow ? gi.growLeftLimit : -gi.shrinkLeftLimit;
168                             if (absorbing) {
169                                 // sign factored in already
170
d += gi.weight * weightedAbsorb;
171                             }
172                         } else {
173                             // sign factored in already
174
d = gi.weight * weightedDelta;
175                         }
176
177                         deltas[n] += d;
178                     }
179                     n++;
180
181                     if (i + 1 != limit) { // ignore right
182
float d;
183                         if (hitLimit) {
184                             d = grow ? gi.growRightLimit : -gi.shrinkRightLimit;
185                             if (absorbing) {
186                                 d += gi.weight * weightedAbsorb;
187                             }
188                         } else {
189                             d = gi.weight * weightedDelta;
190                         }
191
192                         deltas[n] += d;
193                     }
194                     n++;
195                 } else {
196                     n += 2;
197                 }
198             }
199
200             if (!lastPass && hitLimit && !absorbing) {
201                 delta -= gslimit;
202             } else {
203                 delta = 0; // stop iteration
204
}
205         }
206
207         if (DEBUG) {
208             float total = 0;
209             for (int i = 0; i < deltas.length; i++) {
210                 total += deltas[i];
211                 System.out.print(deltas[i] + ", ");
212                 if (i % 20 == 9) {
213                     System.out.println();
214                 }
215             }
216             System.out.println("\ntotal: " + total);
217             System.out.println();
218         }
219
220         return deltas;
221     }
222 }
223
Popular Tags