KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * @(#)TextMeasurer.java 1.39 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 import java.awt.Font JavaDoc;
26
27 import java.text.AttributedCharacterIterator JavaDoc;
28 import java.text.AttributedString JavaDoc;
29 import java.text.Bidi JavaDoc;
30 import java.text.BreakIterator JavaDoc;
31 import java.text.CharacterIterator JavaDoc;
32
33 import java.awt.font.FontRenderContext JavaDoc;
34
35 import java.util.Hashtable JavaDoc;
36 import java.util.Map JavaDoc;
37
38 import sun.font.BidiUtils;
39 import sun.font.TextLineComponent;
40 import sun.font.TextLabelFactory;
41 import sun.font.FontResolver;
42
43 /**
44  * The <code>TextMeasurer</code> class provides the primitive operations
45  * needed for line break: measuring up to a given advance, determining the
46  * advance of a range of characters, and generating a
47  * <code>TextLayout</code> for a range of characters. It also provides
48  * methods for incremental editing of paragraphs.
49  * <p>
50  * A <code>TextMeasurer</code> object is constructed with an
51  * {@link java.text.AttributedCharacterIterator AttributedCharacterIterator}
52  * representing a single paragraph of text. The value returned by the
53  * {@link AttributedCharacterIterator#getBeginIndex() getBeginIndex}
54  * method of <code>AttributedCharacterIterator</code>
55  * defines the absolute index of the first character. The value
56  * returned by the
57  * {@link AttributedCharacterIterator#getEndIndex() getEndIndex}
58  * method of <code>AttributedCharacterIterator</code> defines the index
59  * past the last character. These values define the range of indexes to
60  * use in calls to the <code>TextMeasurer</code>. For example, calls to
61  * get the advance of a range of text or the line break of a range of text
62  * must use indexes between the beginning and end index values. Calls to
63  * {@link #insertChar(java.text.AttributedCharacterIterator, int) insertChar}
64  * and
65  * {@link #deleteChar(java.text.AttributedCharacterIterator, int) deleteChar}
66  * reset the <code>TextMeasurer</code> to use the beginning index and end
67  * index of the <code>AttributedCharacterIterator</code> passed in those calls.
68  * <p>
69  * Most clients will use the more convenient <code>LineBreakMeasurer</code>,
70  * which implements the standard line break policy (placing as many words
71  * as will fit on each line).
72  *
73  * @author John Raley
74  * @version 1.31, 04/20/01
75  * @see LineBreakMeasurer
76  * @since 1.3
77  */

78
79 public final class TextMeasurer implements Cloneable JavaDoc {
80
81     // Number of lines to format to.
82
private static float EST_LINES = (float) 2.1;
83
84     /*
85     static {
86         String s = System.getProperty("estLines");
87         if (s != null) {
88             try {
89                 Float f = new Float(s);
90                 EST_LINES = f.floatValue();
91             }
92             catch(NumberFormatException e) {
93             }
94         }
95         //System.out.println("EST_LINES="+EST_LINES);
96     }
97     */

98
99     private FontRenderContext JavaDoc fFrc;
100
101     private int fStart;
102
103     // characters in source text
104
private char[] fChars;
105
106     // Bidi for this paragraph
107
private Bidi JavaDoc fBidi;
108
109     // Levels array for chars in this paragraph - needed to reorder
110
// trailing counterdirectional whitespace
111
private byte[] fLevels;
112
113     // line components in logical order
114
private TextLineComponent[] fComponents;
115     
116     // index where components begin
117
private int fComponentStart;
118     
119     // index where components end
120
private int fComponentLimit;
121     
122     private boolean haveLayoutWindow;
123     
124     // used to find valid starting points for line components
125
private BreakIterator JavaDoc fLineBreak = null;
126     private CharArrayIterator JavaDoc charIter = null;
127     int layoutCount = 0;
128     int layoutCharCount = 0;
129     
130     // paragraph, with resolved fonts and styles
131
private StyledParagraph JavaDoc fParagraph;
132
133     // paragraph data - same across all layouts
134
private boolean fIsDirectionLTR;
135     private byte fBaseline;
136     private float[] fBaselineOffsets;
137     private float fJustifyRatio = 1;
138
139     /**
140      * Constructs a <code>TextMeasurer</code> from the source text.
141      * The source text should be a single entire paragraph.
142      * @param text the source paragraph. Cannot be null.
143      * @param frc the information about a graphics device which is needed
144      * to measure the text correctly. Cannot be null.
145      */

146     public TextMeasurer(AttributedCharacterIterator JavaDoc text, FontRenderContext JavaDoc frc) {
147
148         fFrc = frc;
149         initAll(text);
150     }
151     
152     protected Object JavaDoc clone() {
153         TextMeasurer JavaDoc other;
154         try {
155             other = (TextMeasurer JavaDoc) super.clone();
156         }
157         catch(CloneNotSupportedException JavaDoc e) {
158             throw new Error JavaDoc();
159         }
160         if (fComponents != null) {
161             other.fComponents = (TextLineComponent[]) fComponents.clone();
162         }
163         return other;
164     }
165     
166     private void invalidateComponents() {
167         fComponentStart = fComponentLimit = fChars.length;
168         fComponents = null;
169         haveLayoutWindow = false;
170     }
171
172     /**
173      * Initialize state, including fChars array, direction, and
174      * fBidi.
175      */

176     private void initAll(AttributedCharacterIterator JavaDoc text) {
177
178         fStart = text.getBeginIndex();
179
180         // extract chars
181
fChars = new char[text.getEndIndex() - fStart];
182
183         int n = 0;
184         for (char c = text.first(); c != text.DONE; c = text.next()) {
185             fChars[n++] = c;
186         }
187         
188         text.first();
189                 
190         fBidi = new Bidi JavaDoc(text);
191     if (fBidi.isLeftToRight()) {
192         fBidi = null;
193     }
194
195         text.first();
196         Map JavaDoc paragraphAttrs = text.getAttributes();
197         if (paragraphAttrs != null) {
198             try {
199                 NumericShaper JavaDoc shaper = (NumericShaper JavaDoc)paragraphAttrs.get(TextAttribute.NUMERIC_SHAPING);
200                 if (shaper != null) {
201                     shaper.shape(fChars, 0, fChars.length);
202                 }
203             }
204             catch (ClassCastException JavaDoc e) {
205             }
206         }
207
208         fParagraph = new StyledParagraph JavaDoc(text, fChars);
209         
210         // set paragraph attributes
211
{
212             // If there's an embedded graphic at the start of the
213
// paragraph, look for the first non-graphic character
214
// and use it and its font to initialize the paragraph.
215
// If not, use the first graphic to initialize.
216
fJustifyRatio = TextLine.getJustifyRatio(paragraphAttrs);
217             
218             boolean haveFont = TextLine.advanceToFirstFont(text);
219
220             if (haveFont) {
221                 Font JavaDoc defaultFont = TextLine.getFontAtCurrentPos(text);
222                 int charsStart = text.getIndex() - text.getBeginIndex();
223                 LineMetrics JavaDoc lm = defaultFont.getLineMetrics(fChars, charsStart, charsStart+1, fFrc);
224                 fBaseline = (byte) lm.getBaselineIndex();
225                 fBaselineOffsets = lm.getBaselineOffsets();
226             }
227             else {
228                 // hmmm what to do here? Just try to supply reasonable
229
// values I guess.
230

231                 GraphicAttribute JavaDoc graphic = (GraphicAttribute JavaDoc)
232                                 paragraphAttrs.get(TextAttribute.CHAR_REPLACEMENT);
233                 fBaseline = TextLayout.getBaselineFromGraphic(graphic);
234                 Font JavaDoc dummyFont = new Font JavaDoc(new Hashtable JavaDoc(5, (float)0.9));
235                 LineMetrics JavaDoc lm = dummyFont.getLineMetrics(" ", 0, 1, fFrc);
236                 fBaselineOffsets = lm.getBaselineOffsets();
237             }
238             fBaselineOffsets = TextLine.getNormalizedOffsets(fBaselineOffsets, fBaseline);
239         }
240         
241         invalidateComponents();
242     }
243     
244     /**
245      * Generate components for the paragraph. fChars, fBidi should have been
246      * initialized already.
247      */

248     private void generateComponents(int startingAt, int endingAt) {
249         
250         if (collectStats) {
251             formattedChars += (endingAt-startingAt);
252         }
253     int layoutFlags = 0; // no extra info yet, bidi determines run and line direction
254
TextLabelFactory factory = new TextLabelFactory(fFrc, fChars, fBidi, layoutFlags);
255
256         int[] charsLtoV = null;
257         
258         if (fBidi != null) {
259             fLevels = BidiUtils.getLevels(fBidi);
260         int[] charsVtoL = BidiUtils.createVisualToLogicalMap(fLevels);
261             charsLtoV = BidiUtils.createInverseMap(charsVtoL);
262             fIsDirectionLTR = fBidi.baseIsLeftToRight();
263         }
264         else {
265             fLevels = null;
266             fIsDirectionLTR = true;
267         }
268         
269         try {
270             fComponents = TextLine.getComponents(
271                 fParagraph, fChars, startingAt, endingAt, charsLtoV, fLevels, factory);
272         }
273         catch(IllegalArgumentException JavaDoc e) {
274             System.out.println("startingAt="+startingAt+"; endingAt="+endingAt);
275             System.out.println("fComponentLimit="+fComponentLimit);
276             throw e;
277         }
278         
279         fComponentStart = startingAt;
280         fComponentLimit = endingAt;
281         //debugFormatCount += (endingAt-startingAt);
282
}
283     
284     private int calcLineBreak(final int pos, final float maxAdvance) {
285
286         // either of these statements removes the bug:
287
//generateComponents(0, fChars.length);
288
//generateComponents(pos, fChars.length);
289

290         int startPos = pos;
291         float width = maxAdvance;
292         
293         int tlcIndex;
294         int tlcStart = fComponentStart;
295
296         for (tlcIndex = 0; tlcIndex < fComponents.length; tlcIndex++) {
297             int gaLimit = tlcStart + fComponents[tlcIndex].getNumCharacters();
298             if (gaLimit > startPos) {
299                 break;
300             }
301             else {
302                 tlcStart = gaLimit;
303             }
304         }
305         
306         // tlcStart is now the start of the tlc at tlcIndex
307

308         for (; tlcIndex < fComponents.length; tlcIndex++) {
309             
310             TextLineComponent tlc = fComponents[tlcIndex];
311             int numCharsInGa = tlc.getNumCharacters();
312
313             int lineBreak = tlc.getLineBreakIndex(startPos - tlcStart, width);
314             if (lineBreak == numCharsInGa && tlcIndex < fComponents.length) {
315                 width -= tlc.getAdvanceBetween(startPos - tlcStart, lineBreak);
316                 tlcStart += numCharsInGa;
317                 startPos = tlcStart;
318             }
319             else {
320                 return tlcStart + lineBreak;
321             }
322         }
323
324         if (fComponentLimit < fChars.length) {
325             // format more text and try again
326
//if (haveLayoutWindow) {
327
// outOfWindow++;
328
//}
329

330             generateComponents(pos, fChars.length);
331             return calcLineBreak(pos, maxAdvance);
332         }
333         
334         return fChars.length;
335     }
336
337     /**
338      * According to the Unicode Bidirectional Behavior specification
339      * (Unicode Standard 2.0, section 3.11), whitespace at the ends
340      * of lines which would naturally flow against the base direction
341      * must be made to flow with the line direction, and moved to the
342      * end of the line. This method returns the start of the sequence
343      * of trailing whitespace characters to move to the end of a
344      * line taken from the given range.
345      */

346     private int trailingCdWhitespaceStart(int startPos, int limitPos) {
347
348         if (fLevels != null) {
349             // Back up over counterdirectional whitespace
350
final byte baseLevel = (byte) (fIsDirectionLTR? 0 : 1);
351             for (int cdWsStart = limitPos; --cdWsStart >= startPos;) {
352                 if ((fLevels[cdWsStart] % 2) == baseLevel ||
353                         Character.getDirectionality(fChars[cdWsStart]) != Character.DIRECTIONALITY_WHITESPACE) {
354                     return ++cdWsStart;
355                 }
356             }
357         }
358
359         return startPos;
360     }
361
362     private TextLineComponent[] makeComponentsOnRange(int startPos,
363                                                       int limitPos) {
364
365         // sigh I really hate to do this here since it's part of the
366
// bidi algorithm.
367
// cdWsStart is the start of the trailing counterdirectional
368
// whitespace
369
final int cdWsStart = trailingCdWhitespaceStart(startPos, limitPos);
370
371         int tlcIndex;
372         int tlcStart = fComponentStart;
373
374         for (tlcIndex = 0; tlcIndex < fComponents.length; tlcIndex++) {
375             int gaLimit = tlcStart + fComponents[tlcIndex].getNumCharacters();
376             if (gaLimit > startPos) {
377                 break;
378             }
379             else {
380                 tlcStart = gaLimit;
381             }
382         }
383
384         // tlcStart is now the start of the tlc at tlcIndex
385

386         int componentCount;
387         {
388             boolean split = false;
389             int compStart = tlcStart;
390             int lim=tlcIndex;
391             for (boolean cont=true; cont; lim++) {
392                 int gaLimit = compStart + fComponents[lim].getNumCharacters();
393                 if (cdWsStart > Math.max(compStart, startPos)
394                             && cdWsStart < Math.min(gaLimit, limitPos)) {
395                     split = true;
396                 }
397                 if (gaLimit >= limitPos) {
398                     cont=false;
399                 }
400                 else {
401                     compStart = gaLimit;
402                 }
403             }
404             componentCount = lim-tlcIndex;
405             if (split) {
406                 componentCount++;
407             }
408         }
409
410         TextLineComponent[] components = new TextLineComponent[componentCount];
411         int newCompIndex = 0;
412         int linePos = startPos;
413
414         int breakPt = cdWsStart;
415
416         int subsetFlag;
417         if (breakPt == startPos) {
418             subsetFlag = fIsDirectionLTR? TextLineComponent.LEFT_TO_RIGHT :
419                                           TextLineComponent.RIGHT_TO_LEFT;
420             breakPt = limitPos;
421         }
422         else {
423             subsetFlag = TextLineComponent.UNCHANGED;
424         }
425
426         while (linePos < limitPos) {
427             
428             int compLength = fComponents[tlcIndex].getNumCharacters();
429             int tlcLimit = tlcStart + compLength;
430
431             int start = Math.max(linePos, tlcStart);
432             int limit = Math.min(breakPt, tlcLimit);
433             
434             components[newCompIndex++] = fComponents[tlcIndex].getSubset(
435                                                                 start-tlcStart,
436                                                                 limit-tlcStart,
437                                                                 subsetFlag);
438             linePos += (limit-start);
439             if (linePos == breakPt) {
440                 breakPt = limitPos;
441                 subsetFlag = fIsDirectionLTR? TextLineComponent.LEFT_TO_RIGHT :
442                                               TextLineComponent.RIGHT_TO_LEFT;
443             }
444             if (linePos == tlcLimit) {
445                 tlcIndex++;
446                 tlcStart = tlcLimit;
447             }
448         }
449
450         return components;
451     }
452
453     private TextLine JavaDoc makeTextLineOnRange(int startPos, int limitPos) {
454
455         int[] charsLtoV = null;
456         byte[] charLevels = null;
457
458         if (fBidi != null) {
459             Bidi JavaDoc lineBidi = fBidi.createLineBidi(startPos, limitPos);
460             charLevels = BidiUtils.getLevels(lineBidi);
461         int[] charsVtoL = BidiUtils.createVisualToLogicalMap(charLevels);
462             charsLtoV = BidiUtils.createInverseMap(charsVtoL);
463         }
464
465         TextLineComponent[] components = makeComponentsOnRange(startPos, limitPos);
466
467         return new TextLine JavaDoc(components,
468                             fBaselineOffsets,
469                             fChars,
470                             startPos,
471                             limitPos,
472                             charsLtoV,
473                             charLevels,
474                             fIsDirectionLTR);
475
476     }
477     
478     private void ensureComponents(int start, int limit) {
479         
480         if (start < fComponentStart || limit > fComponentLimit) {
481             generateComponents(start, limit);
482         }
483     }
484     
485     private void makeLayoutWindow(int localStart) {
486         
487         int compStart = localStart;
488         int compLimit = fChars.length;
489         
490         // If we've already gone past the layout window, format to end of paragraph
491
if (layoutCount > 0 && !haveLayoutWindow) {
492             float avgLineLength = Math.max(layoutCharCount / layoutCount, 1);
493             compLimit = Math.min(localStart + (int)(avgLineLength*EST_LINES), fChars.length);
494         }
495         
496         if (localStart > 0 || compLimit < fChars.length) {
497             if (charIter == null) {
498                 charIter = new CharArrayIterator JavaDoc(fChars);
499             }
500             else {
501                 charIter.reset(fChars);
502             }
503             if (fLineBreak == null) {
504                 fLineBreak = BreakIterator.getLineInstance();
505             }
506             fLineBreak.setText(charIter);
507             if (localStart > 0) {
508                 if (!fLineBreak.isBoundary(localStart)) {
509                     compStart = fLineBreak.preceding(localStart);
510                 }
511             }
512             if (compLimit < fChars.length) {
513                 if (!fLineBreak.isBoundary(compLimit)) {
514                     compLimit = fLineBreak.following(compLimit);
515                 }
516             }
517         }
518
519         ensureComponents(compStart, compLimit);
520         haveLayoutWindow = true;
521     }
522
523     /**
524      * Returns the index of the first character which will not fit on
525      * on a line beginning at <code>start</code> and possible
526      * measuring up to <code>maxAdvance</code> in graphical width.
527      *
528      * @param start the character index at which to start measuring.
529      * <code>start</code> is an absolute index, not relative to the
530      * start of the paragraph
531      * @param maxAdvance the graphical width in which the line must fit
532      * @return the index after the last character that will fit
533      * on a line beginning at <code>start</code>, which is not longer
534      * than <code>maxAdvance</code> in graphical width
535      * @throws IllegalArgumentException if <code>start</code> is
536      * less than the beginning of the paragraph.
537      */

538     public int getLineBreakIndex(int start, float maxAdvance) {
539         
540         int localStart = start - fStart;
541
542         if (!haveLayoutWindow ||
543                 localStart < fComponentStart ||
544                 localStart >= fComponentLimit) {
545             makeLayoutWindow(localStart);
546         }
547         
548         return calcLineBreak(localStart, maxAdvance) + fStart;
549     }
550
551     /**
552      * Returns the graphical width of a line beginning at <code>start</code>
553      * and including characters up to <code>limit</code>.
554      * <code>start</code> and <code>limit</code> are absolute indices,
555      * not relative to the start of the paragraph.
556      *
557      * @param start the character index at which to start measuring
558      * @param limit the character index at which to stop measuring
559      * @return the graphical width of a line beginning at <code>start</code>
560      * and including characters up to <code>limit</code>
561      * @throws IndexOutOfBoundsException if <code>limit</code> is less
562      * than <code>start</code>
563      * @throws IllegalArgumentException if <code>start</code> or
564      * <code>limit</code> is not between the beginning of
565      * the paragraph and the end of the paragraph.
566      */

567     public float getAdvanceBetween(int start, int limit) {
568         
569         int localStart = start - fStart;
570         int localLimit = limit - fStart;
571         
572         ensureComponents(localStart, localLimit);
573         TextLine JavaDoc line = makeTextLineOnRange(localStart, localLimit);
574         return line.getMetrics().advance;
575         // could cache line in case getLayout is called with same start, limit
576
}
577
578     /**
579      * Returns a <code>TextLayout</code> on the given character range.
580      *
581      * @param start the index of the first character
582      * @param limit the index after the last character. Must be greater
583      * than <code>start</code>
584      * @return a <code>TextLayout</code> for the characters beginning at
585      * <code>start</code> up to (but not including) <code>limit</code>
586      * @throws IndexOutOfBoundsException if <code>limit</code> is less
587      * than <code>start</code>
588      * @throws IllegalArgumentException if <code>start</code> or
589      * <code>limit</code> is not between the beginning of
590      * the paragraph and the end of the paragraph.
591      */

592     public TextLayout JavaDoc getLayout(int start, int limit) {
593         
594         int localStart = start - fStart;
595         int localLimit = limit - fStart;
596         
597         ensureComponents(localStart, localLimit);
598         TextLine JavaDoc textLine = makeTextLineOnRange(localStart, localLimit);
599
600         if (localLimit < fChars.length) {
601             layoutCharCount += limit-start;
602             layoutCount++;
603         }
604         
605         return new TextLayout JavaDoc(textLine,
606                               fBaseline,
607                               fBaselineOffsets,
608                               fJustifyRatio);
609     }
610
611     private int formattedChars = 0;
612     private static boolean wantStats = false;/*"true".equals(System.getProperty("collectStats"));*/
613     private boolean collectStats = false;
614     
615     private void printStats() {
616         System.out.println("formattedChars: " + formattedChars);
617         //formattedChars = 0;
618
collectStats = false;
619     }
620     
621     /**
622      * Updates the <code>TextMeasurer</code> after a single character has
623      * been inserted
624      * into the paragraph currently represented by this
625      * <code>TextMeasurer</code>. After this call, this
626      * <code>TextMeasurer</code> is equivalent to a new
627      * <code>TextMeasurer</code> created from the text; however, it will
628      * usually be more efficient to update an existing
629      * <code>TextMeasurer</code> than to create a new one from scratch.
630      *
631      * @param newParagraph the text of the paragraph after performing
632      * the insertion. Cannot be null.
633      * @param insertPos the position in the text where the character was
634      * inserted. Must not be less than the start of
635      * <code>newParagraph</code>, and must be less than the end of
636      * <code>newParagraph</code>.
637      * @throws IndexOutOfBoundsException if <code>insertPos</code> is less
638      * than the start of <code>newParagraph</code> or greater than
639      * or equal to the end of <code>newParagraph</code>
640      * @throws NullPointerException if <code>newParagraph</code> is
641      * <code>null</code>
642      */

643     public void insertChar(AttributedCharacterIterator JavaDoc newParagraph, int insertPos) {
644
645         if (collectStats) {
646             printStats();
647         }
648         if (wantStats) {
649             collectStats = true;
650         }
651         
652         fStart = newParagraph.getBeginIndex();
653         int end = newParagraph.getEndIndex();
654         if (end - fStart != fChars.length+1) {
655             initAll(newParagraph);
656         }
657         
658         char[] newChars = new char[end-fStart];
659         int newCharIndex = insertPos - fStart;
660         System.arraycopy(fChars, 0, newChars, 0, newCharIndex);
661         
662         char newChar = newParagraph.setIndex(insertPos);
663         newChars[newCharIndex] = newChar;
664         System.arraycopy(fChars,
665                          newCharIndex,
666                          newChars,
667                          newCharIndex+1,
668                          end-insertPos-1);
669         fChars = newChars;
670         
671         if (fBidi != null || Bidi.requiresBidi(newChars, newCharIndex, newCharIndex + 1) ||
672                 newParagraph.getAttribute(TextAttribute.BIDI_EMBEDDING) != null) {
673
674             fBidi = new Bidi JavaDoc(newParagraph);
675         if (fBidi.isLeftToRight()) {
676         fBidi = null;
677         }
678         }
679         
680         fParagraph = StyledParagraph.insertChar(newParagraph,
681                                                 fChars,
682                                                 insertPos,
683                                                 fParagraph);
684         invalidateComponents();
685     }
686     
687     /**
688      * Updates the <code>TextMeasurer</code> after a single character has
689      * been deleted
690      * from the paragraph currently represented by this
691      * <code>TextMeasurer</code>. After this call, this
692      * <code>TextMeasurer</code> is equivalent to a new <code>TextMeasurer</code>
693      * created from the text; however, it will usually be more efficient
694      * to update an existing <code>TextMeasurer</code> than to create a new one
695      * from scratch.
696      *
697      * @param newParagraph the text of the paragraph after performing
698      * the deletion. Cannot be null.
699      * @param deletePos the position in the text where the character was removed.
700      * Must not be less than
701      * the start of <code>newParagraph</code>, and must not be greater than the
702      * end of <code>newParagraph</code>.
703      * @throws IndexOutOfBoundsException if <code>deletePos</code> is
704      * less than the start of <code>newParagraph</code> or greater
705      * than the end of <code>newParagraph</code>
706      * @throws NullPointerException if <code>newParagraph</code> is
707      * <code>null</code>
708      */

709     public void deleteChar(AttributedCharacterIterator JavaDoc newParagraph, int deletePos) {
710
711         fStart = newParagraph.getBeginIndex();
712         int end = newParagraph.getEndIndex();
713         if (end - fStart != fChars.length-1) {
714             initAll(newParagraph);
715         }
716         
717         char[] newChars = new char[end-fStart];
718         int changedIndex = deletePos-fStart;
719         
720         System.arraycopy(fChars, 0, newChars, 0, deletePos-fStart);
721         System.arraycopy(fChars, changedIndex+1, newChars, changedIndex, end-deletePos);
722         fChars = newChars;
723         
724         if (fBidi != null) {
725             fBidi = new Bidi JavaDoc(newParagraph);
726         if (fBidi.isLeftToRight()) {
727         fBidi = null;
728         }
729         }
730         
731         fParagraph = StyledParagraph.deleteChar(newParagraph,
732                                                 fChars,
733                                                 deletePos,
734                                                 fParagraph);
735         invalidateComponents();
736     }
737
738     /**
739      * NOTE: This method is only for LineBreakMeasurer's use. It is package-
740      * private because it returns internal data.
741      */

742     char[] getChars() {
743
744         return fChars;
745     }
746 }
747
Popular Tags