/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
* (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
*
* The original version of this source code and documentation is
* copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
* of IBM. These materials are provided under terms of a License
* Agreement between Taligent and Sun. This technology is protected
* by multiple US and International patents.
*
* This notice and attribution to Taligent may not be removed.
* Taligent is a registered trademark of Taligent, Inc.
*
*/
/**
* The <code>TextMeasurer</code> class provides the primitive operations
* needed for line break: measuring up to a given advance, determining the
* advance of a range of characters, and generating a
* <code>TextLayout</code> for a range of characters. It also provides
* methods for incremental editing of paragraphs.
* <p>
* A <code>TextMeasurer</code> object is constructed with an
* {@link java.text.AttributedCharacterIterator AttributedCharacterIterator}
* representing a single paragraph of text. The value returned by the
* {@link AttributedCharacterIterator#getBeginIndex() getBeginIndex}
* method of <code>AttributedCharacterIterator</code>
* defines the absolute index of the first character. The value
* returned by the
* {@link AttributedCharacterIterator#getEndIndex() getEndIndex}
* method of <code>AttributedCharacterIterator</code> defines the index
* past the last character. These values define the range of indexes to
* use in calls to the <code>TextMeasurer</code>. For example, calls to
* get the advance of a range of text or the line break of a range of text
* must use indexes between the beginning and end index values. Calls to
* {@link #insertChar(java.text.AttributedCharacterIterator, int) insertChar}
* and
* {@link #deleteChar(java.text.AttributedCharacterIterator, int) deleteChar}
* reset the <code>TextMeasurer</code> to use the beginning index and end
* index of the <code>AttributedCharacterIterator</code> passed in those calls.
* <p>
* Most clients will use the more convenient <code>LineBreakMeasurer</code>,
* which implements the standard line break policy (placing as many words
* as will fit on each line).
*
* @author John Raley
* @see LineBreakMeasurer
* @since 1.3
*/
// Number of lines to format to.
/*
static {
String s = System.getProperty("estLines");
if (s != null) {
try {
Float f = new Float(s);
EST_LINES = f.floatValue();
}
catch(NumberFormatException e) {
}
}
//System.out.println("EST_LINES="+EST_LINES);
}
*/
private int fStart;
// characters in source text
private char[] fChars;
// Bidi for this paragraph
// Levels array for chars in this paragraph - needed to reorder
// trailing counterdirectional whitespace
private byte[] fLevels;
// line components in logical order
// index where components begin
private int fComponentStart;
// index where components end
private int fComponentLimit;
private boolean haveLayoutWindow;
// used to find valid starting points for line components
// paragraph, with resolved fonts and styles
// paragraph data - same across all layouts
private boolean fIsDirectionLTR;
private byte fBaseline;
private float[] fBaselineOffsets;
/**
* Constructs a <code>TextMeasurer</code> from the source text.
* The source text should be a single entire paragraph.
* @param text the source paragraph. Cannot be null.
* @param frc the information about a graphics device which is needed
* to measure the text correctly. Cannot be null.
*/
}
try {
}
catch(CloneNotSupportedException e) {
throw new Error();
}
if (fComponents != null) {
}
return other;
}
private void invalidateComponents() {
fComponents = null;
haveLayoutWindow = false;
}
/**
* Initialize state, including fChars array, direction, and
* fBidi.
*/
// extract chars
int n = 0;
fChars[n++] = c;
}
if (fBidi.isLeftToRight()) {
}
}
// set paragraph attributes
{
// If there's an embedded graphic at the start of the
// paragraph, look for the first non-graphic character
// and use it and its font to initialize the paragraph.
// If not, use the first graphic to initialize.
if (haveFont) {
}
else {
// hmmm what to do here? Just try to supply reasonable
// values I guess.
}
}
}
/**
* Generate components for the paragraph. fChars, fBidi should have been
* initialized already.
*/
if (collectStats) {
}
}
else {
fIsDirectionLTR = true;
}
try {
}
catch(IllegalArgumentException e) {
throw e;
}
//debugFormatCount += (endingAt-startingAt);
}
// either of these statements removes the bug:
//generateComponents(0, fChars.length);
//generateComponents(pos, fChars.length);
float width = maxAdvance;
int tlcIndex;
int tlcStart = fComponentStart;
break;
}
else {
}
}
// tlcStart is now the start of the tlc at tlcIndex
tlcStart += numCharsInGa;
}
else {
}
}
// format more text and try again
//if (haveLayoutWindow) {
// outOfWindow++;
//}
}
}
/**
* According to the Unicode Bidirectional Behavior specification
* (Unicode Standard 2.0, section 3.11), whitespace at the ends
* of lines which would naturally flow against the base direction
* must be made to flow with the line direction, and moved to the
* end of the line. This method returns the start of the sequence
* of trailing whitespace characters to move to the end of a
* line taken from the given range.
*/
// Back up over counterdirectional whitespace
return ++cdWsStart;
}
}
}
return startPos;
}
int limitPos) {
// sigh I really hate to do this here since it's part of the
// bidi algorithm.
// cdWsStart is the start of the trailing counterdirectional
// whitespace
int tlcIndex;
int tlcStart = fComponentStart;
break;
}
else {
}
}
// tlcStart is now the start of the tlc at tlcIndex
int componentCount;
{
boolean split = false;
split = true;
}
cont=false;
}
else {
}
}
if (split) {
}
}
int newCompIndex = 0;
int subsetFlag;
}
else {
}
}
tlcIndex++;
}
}
return components;
}
byte[] charLevels = null;
}
}
}
}
int compStart = localStart;
// If we've already gone past the layout window, format to end of paragraph
}
}
else {
}
if (fLineBreak == null) {
}
if (localStart > 0) {
}
}
}
}
}
haveLayoutWindow = true;
}
/**
* Returns the index of the first character which will not fit on
* on a line beginning at <code>start</code> and possible
* measuring up to <code>maxAdvance</code> in graphical width.
*
* @param start the character index at which to start measuring.
* <code>start</code> is an absolute index, not relative to the
* start of the paragraph
* @param maxAdvance the graphical width in which the line must fit
* @return the index after the last character that will fit
* on a line beginning at <code>start</code>, which is not longer
* than <code>maxAdvance</code> in graphical width
* @throws IllegalArgumentException if <code>start</code> is
* less than the beginning of the paragraph.
*/
if (!haveLayoutWindow ||
localStart >= fComponentLimit) {
}
}
/**
* Returns the graphical width of a line beginning at <code>start</code>
* and including characters up to <code>limit</code>.
* <code>start</code> and <code>limit</code> are absolute indices,
* not relative to the start of the paragraph.
*
* @param start the character index at which to start measuring
* @param limit the character index at which to stop measuring
* @return the graphical width of a line beginning at <code>start</code>
* and including characters up to <code>limit</code>
* @throws IndexOutOfBoundsException if <code>limit</code> is less
* than <code>start</code>
* @throws IllegalArgumentException if <code>start</code> or
* <code>limit</code> is not between the beginning of
* the paragraph and the end of the paragraph.
*/
// could cache line in case getLayout is called with same start, limit
}
/**
* Returns a <code>TextLayout</code> on the given character range.
*
* @param start the index of the first character
* @param limit the index after the last character. Must be greater
* than <code>start</code>
* @return a <code>TextLayout</code> for the characters beginning at
* <code>start</code> up to (but not including) <code>limit</code>
* @throws IndexOutOfBoundsException if <code>limit</code> is less
* than <code>start</code>
* @throws IllegalArgumentException if <code>start</code> or
* <code>limit</code> is not between the beginning of
* the paragraph and the end of the paragraph.
*/
layoutCount++;
}
return new TextLayout(textLine,
}
private boolean collectStats = false;
private void printStats() {
//formattedChars = 0;
collectStats = false;
}
/**
* Updates the <code>TextMeasurer</code> after a single character has
* been inserted
* into the paragraph currently represented by this
* <code>TextMeasurer</code>. After this call, this
* <code>TextMeasurer</code> is equivalent to a new
* <code>TextMeasurer</code> created from the text; however, it will
* usually be more efficient to update an existing
* <code>TextMeasurer</code> than to create a new one from scratch.
*
* @param newParagraph the text of the paragraph after performing
* the insertion. Cannot be null.
* @param insertPos the position in the text where the character was
* inserted. Must not be less than the start of
* <code>newParagraph</code>, and must be less than the end of
* <code>newParagraph</code>.
* @throws IndexOutOfBoundsException if <code>insertPos</code> is less
* than the start of <code>newParagraph</code> or greater than
* or equal to the end of <code>newParagraph</code>
* @throws NullPointerException if <code>newParagraph</code> is
* <code>null</code>
*/
if (collectStats) {
printStats();
}
if (wantStats) {
collectStats = true;
}
}
newCharIndex+1,
if (fBidi.isLeftToRight()) {
}
}
}
/**
* Updates the <code>TextMeasurer</code> after a single character has
* been deleted
* from the paragraph currently represented by this
* <code>TextMeasurer</code>. After this call, this
* <code>TextMeasurer</code> is equivalent to a new <code>TextMeasurer</code>
* created from the text; however, it will usually be more efficient
* to update an existing <code>TextMeasurer</code> than to create a new one
* from scratch.
*
* @param newParagraph the text of the paragraph after performing
* the deletion. Cannot be null.
* @param deletePos the position in the text where the character was removed.
* Must not be less than
* the start of <code>newParagraph</code>, and must not be greater than the
* end of <code>newParagraph</code>.
* @throws IndexOutOfBoundsException if <code>deletePos</code> is
* less than the start of <code>newParagraph</code> or greater
* than the end of <code>newParagraph</code>
* @throws NullPointerException if <code>newParagraph</code> is
* <code>null</code>
*/
}
if (fBidi.isLeftToRight()) {
}
}
}
/**
* NOTE: This method is only for LineBreakMeasurer's use. It is package-
* private because it returns internal data.
*/
char[] getChars() {
return fChars;
}
}