home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-03-20 | 20.8 KB | 648 lines |
- /*
- * @(#)StyledString.java 1.38 98/03/18
- *
- * Copyright 1997, 1998 by Sun Microsystems, Inc.,
- * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
- * All rights reserved.
- *
- * This software is the confidential and proprietary information
- * of Sun Microsystems, Inc. ("Confidential Information"). You
- * shall not disclose such Confidential Information and shall use
- * it only in accordance with the terms of the license agreement
- * you entered into with Sun.
- */
-
- /*
- * (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.
- *
- */
-
- package java.awt.font;
-
- import java.awt.Font;
- import java.awt.Shape;
- import java.awt.geom.GeneralPath;
- import java.awt.geom.Rectangle2D;
- import java.awt.geom.Point2D;
- import java.text.AttributedCharacterIterator;
- import java.text.AttributeSet;
-
- /**
- * StyledString is a simple, immutable storage model for styled
- * text. It supports substring and concatenation operations with
- * other StyledStrings.
- *
- */
-
-
- public final class StyledString {
- private float ascent;
- private float descent;
- private float leading;
- private int length;
-
- /*
- * package access
- * indices are start of each attr range, one more value than
- * ranges
- */
- char[] chars;
- AttributeSet[] attrs;
- int[] indices;
-
- /**
- * Constructs a new StyledString with no characters.
- */
- public StyledString(){
- initEmpty();
- }
-
- /**
- * Allocates a new styled string containing the same characters
- * as the string argument, all styled with the specified attributes.
- */
- public StyledString(String str, AttributeSet attributes) {
- init(str, attributes);
- }
-
- /**
- * Allocates a new styled string containing the same characters
- * as the first string argument, all styled with an attribute
- * that has the specified name and value.
- * REMIND jk . new api
- */
- private StyledString(String str, String name, Object value) {
- init(str, new TextAttributeSet(name, value));
- }
-
- /* package, used by StyledStringBuffer */
- StyledString(char[] chars, AttributeSet[] attrs, int[] indices) {
- this.chars = chars;
- this.attrs = attrs;
- this.indices = indices;
- ascent = -1;
- }
-
- /**
- * Allocates a new styled string containing the same characters
- * and attributes as the iterator argument.
- * REMIND jk . new api
- */
- /*private StyledString(AttributedCharacterIterator text) {
- if (text.getEndIndex() == text.getBeginIndex()) {
- initEmpty();
- } else {
- StyledStringBuffer buffer = new StyledStringBuffer(text);
- buffer.copyInto(this);
- ascent = -1;
- }
- }*/
-
- /**
- * Allocates a new styled string containing the same characters
- * and attributes currently contained in the styled string buffer
- * argument.
- *
- * @param buffer a <code>StringBuffer</code>.
- */
- /*StyledString(StyledStringBuffer buffer) {
- if (buffer.getLength() == 0) {
- initEmpty();
- } else {
- buffer.copyInto(this);
- ascent = -1;
- }
- }*/
-
- /**
- * Constructs a new StyledString from the given String using the given Font.
- * @param str the String object.
- * @param font the Font object.
- */
- public StyledString( String str, Font font ){
- TextAttributeSet attributes =
- new TextAttributeSet(font.getRequestedAttributes());
- attributes.add(TextAttributeSet.FONT, font);
- init(str, attributes);
- }
-
- private void init(String str, AttributeSet attributes) {
- if (str.length() == 0) {
- initEmpty();
- } else {
- this.chars = str.toCharArray();
- this.attrs = new AttributeSet[] { attributes };
- this.indices = new int[] { 0, chars.length };
- }
- length = 0;
- ascent = -1;
- }
-
- private void initEmpty() {
- chars = new char[0];
- indices = new int[] { 0 };
- length = 0;
- ascent = -1;
- }
-
- /**
- * Returns a new styled string that is a substring of this
- * styled string. The substring begins at the specified
- * <code>beginIndex</code> and extends to the character at
- * index <code>endIndex - 1</code>.
- *
- * @param beginIndex the beginning index, inclusive.
- * @param endIndex the ending index, exclusive.
- * @return the specified substring.
- * @exception StringIndexOutOfBoundsException if the
- * <code>beginIndex</code> or the <code>endIndex</code> is
- * out of range.
- */
- public StyledString substring(int beginIndex, int endIndex) {
- if (beginIndex < 0) {
- throw new StringIndexOutOfBoundsException(beginIndex);
- }
- if (endIndex > chars.length) {
- throw new StringIndexOutOfBoundsException(endIndex);
- }
- if (endIndex < beginIndex) {
- throw new StringIndexOutOfBoundsException(endIndex -
- beginIndex);
- }
-
- // check for empty string, which can cause array access errors
- if (length() == 0) {
- return this;
- } else if (endIndex == beginIndex) {
- return new StyledString();
- }
-
- int startSegment = findSegmentContaining(beginIndex);
- int endSegment = findSegmentContaining(endIndex);
- if (endIndex == indices[endSegment]) {
- --endSegment;
- }
-
- int len = endIndex - beginIndex;
- int attrLen = endSegment - startSegment + 1;
-
- char[] newChars = new char[len];
- System.arraycopy(chars, beginIndex, newChars, 0, len);
-
- AttributeSet[] newAttrs = new AttributeSet[attrLen];
- System.arraycopy(attrs, startSegment, newAttrs, 0, attrLen);
-
- int[] newIndices = new int[attrLen+1];
-
- newIndices[0] = 0;
- for (int i = 1; i < attrLen; i++) {
- newIndices[i] = indices[startSegment + i] - beginIndex;
- }
- newIndices[attrLen] = endIndex - beginIndex;
-
- return new StyledString(newChars, newAttrs, newIndices);
- }
-
- private void loadMetrics(){
- if(ascent == -1) {
- for (int i=0;i<attrs.length;i++){
- Font theFont = (Font) attrs[i].get(TextAttributeSet.FONT);
- ascent = Math.max(ascent,theFont.getAscent());
- descent = Math.max(descent,theFont.getDescent());
- leading = Math.max(leading,theFont.getLeading());
- }
- }
- }
-
-
- /**
- * Returns the largest ascent of any font represented in this StyledString.
- * The units are user space coordinates.
- */
- public float getAscent(){
- loadMetrics();
- return ascent;
- }
-
- /**
- * Returns the largest descent of any font represented in this StyledString.
- * The units are user space coordinates.
- */
- public float getDescent(){
- loadMetrics();
- return descent;
- }
-
- /**
- * Returns the largest leading of any font represented in this StyledString.
- * The units are user space coordinates.
- */
- public float getLeading(){
- loadMetrics();
- return leading;
- }
-
- /**
- * Internal method to map a position to the index of the style
- * run containing the character at that position.
- */
- int findSegmentContaining(int pos) {
- /*
- * Cache the last index on the assumption that most segment
- * queries are local. If this isn't the case then we can go
- * to a binary search, but this is simpler.
- */
- while (pos > indices[segmentIndexCache++]) {}
- while (pos < indices[--segmentIndexCache]) {}
- return segmentIndexCache;
- }
-
- // cache for findSegmentContaining
- private int segmentIndexCache = 0;
-
- /**
- * Return the index of the first character of the run of
- * characters containing index sharing equal attributes.
- *
- * @param index the index of the character. Index may be
- * equal to length, in which case the return value is the length
- * of the styled string.
- * @return the index of the first character in the run
- * @exception StringIndexOutOfBoundsException if the index is
- * out of range.
- * @see #getRunLimit
- */
- public int getRunStart(int index) {
- if (index < 0 || index > chars.length) {
- throw new StringIndexOutOfBoundsException(index);
- } else if (index == chars.length) {
- return index;
- }
- int seg = findSegmentContaining(index);
-
- return indices[seg];
- }
-
- /**
- * Return the index past the last character of the run of
- * characters containing index sharing equal attributes.
- *
- * @param index the index of the character. Index may be
- * equal to length, in which case the return value is the length
- * of the styled string.
- * @return the index past the last character in the run
- * @exception StringIndexOutOfBoundsException if the index is
- * out of range.
- * @see #getRunStart
- */
- public int getRunLimit(int index) {
- if (index < 0 || index > chars.length) {
- throw new StringIndexOutOfBoundsException(index);
- } else if (index == chars.length) {
- return index;
- }
- int seg = findSegmentContaining(index);
-
- return indices[seg+1];
- }
-
- /**
- * Returns the advance vector for the end position of this StyledString.
- */
- public Point2D getAdvanceVector(){
- float totalAdvance=0;
- GlyphSet glyphs;
- int start = 0;
- int end;
- for (int i=0;i<attrs.length;i++){
- end = indices[i+1];
- Font theFont = (Font) attrs[i].get(TextAttributeSet.FONT);
- String theString = new String(chars, start, end - start);
- glyphs = theFont.getGlyphSet(theString);
- totalAdvance += glyphs.getAdvance();
- start = end + 1;
- }
- return new Point2D.Float(totalAdvance,0);
- }
-
- /**
- * Returns the bounding box of this StyledString.
- */
- public Rectangle2D getBounds2D(){
- return new Rectangle2D.Double(0.0, 0.0, getAdvanceVector().getX(),
- getAscent() + getDescent());
- }
-
- /**
- * Returns an array of GlyphSet objects associated with this StyledString.
- * REMIND jk . ask ccc to remove this api
- */
- public GlyphSet[] getGlyphSets(){
- GlyphSet[] glyphs = new GlyphSet[attrs.length];
-
- int start = 0;
- int end;
- for (int i=0;i<attrs.length;i++){
- end = indices[i+1];
- Font theFont = (Font) attrs[i].get(TextAttributeSet.FONT);
- String theString = new String(chars, start, end - start);
- glyphs[i] = theFont.getGlyphSet(theString);
- start = end + 1;
- }
- return glyphs;
- }
-
- /**
- * Returns the Shape object for this StyledString, which is the union
- * of all the outlines for glyphs in the StyledString.
- */
- public Shape getStringOutline(){
- Font theFont;
- int start = 0;
- int end;
- GeneralPath resultShape = new GeneralPath(GeneralPath.EVEN_ODD);
- for (int i=0;i<attrs.length;i++){
- end = indices[i+1];
- theFont = (Font) attrs[i].get(TextAttributeSet.FONT);
- String theString = new String(chars, start, end - start);
- resultShape.append(theFont.getOutline(theFont.
- getGlyphSet(theString),
- null, 0, getAscent() +
- getDescent()), false);
- start = end + 1;
- }
- return resultShape;
- }
-
- /**
- * Return a String containing the characters in this object.
- *
- * @return a string containing the characters in this object.
- */
- public String toString(){
- return new String(chars);
- }
-
- /**
- * Concatenates the specified characters and attributes
- * to the end of this styled string.
- * <p>
- * If the length of the argument string is <code>0</code>, then this
- * object is returned.
- *
- * @param str the <code>String</code> that is concatenated to the
- * end of this <code>StyledString</code>.
- * @param attributes the attributes for the new characters
- * @return a styled string that represents the concatenation of this
- * object's characters and attributes followed by the string
- * argument's characters.
- * REMIND jk new api
- */
- private StyledString concat(String str, AttributeSet attributes) {
- return concat(new StyledString(str, attributes));
- }
-
- /**
- * Concatenates the specified styled text to the end of this string.
- * <p>
- * If the length of the argument text is <code>0</code>, then this
- * object is returned.
- *
- * @param iter the text and attributes that is concatenated to
- * the end of this <code>StyledString</code>.
- * @return a styled string that represents the concatenation of
- * this object's characters and attributes followed by the iterator's
- * characters and attributes.
- * REMIND jk new api
- */
- /*private StyledString concat(AttributedCharacterIterator iter) {
- return concat(new StyledString(iter));
- }*/
-
- /**
- * Concatenates the specified styled string to the end of this string.
- * <p>
- * If the length of the argument string is <code>0</code>, then this
- * object is returned.
- *
- * @param str the <code>StyledString</code> that is concatenated
- * to the end of this <code>StyledString</code>.
- * @return a styled string that represents the concatenation of this
- * object's characters and attributes followed by the string argument's
- * characters and attributes.
- */
- public StyledString concat(StyledString text){
- if (text.length() == 0) {
- return this;
- } else if (length() == 0) {
- return text;
- } else {
- // concatenate text
- char[] newChars = new char[chars.length + text.chars.length];
- System.arraycopy(chars, 0, newChars, 0, chars.length);
- System.arraycopy(text.chars, 0, newChars, chars.length,
- text.chars.length);
-
- boolean merge = attrs[attrs.length - 1].equals(text.attrs[0]);
-
- AttributeSet[] newAttrs = new AttributeSet[attrs.length +
- text.attrs.length - (merge ? 1 : 0)];
- System.arraycopy(attrs, 0, newAttrs, 0, attrs.length);
- System.arraycopy(text.attrs, merge ? 1 : 0, newAttrs,
- attrs.length, newAttrs.length - attrs.length);
-
- int[] newIndices = new int[newAttrs.length + 1];
- System.arraycopy(indices, 0, newIndices, 0, indices.length);
-
- int i = indices.length - (merge ? 1 : 0);
- int j = 1;
- int d = indices[indices.length - 1];
- while (i < newIndices.length) {
- newIndices[i++] = d + text.indices[j++];
- }
- return new StyledString(newChars, newAttrs, newIndices);
- }
- }
-
- /**
- * Returns the character at the specified index. An index ranges
- * from <code>0</code> to <code>length() - 1</code>.
- *
- * @param index the index of the character.
- * @return the character at the specified index of this string.
- * The first character is at index <code>0</code>.
- * @exception StringIndexOutOfBoundsException if the index is out of
- * range.
- */
- public char charAt(int index) {
- if (index < 0 || index >= chars.length) {
- throw new StringIndexOutOfBoundsException(index);
- }
- return chars[index];
- }
-
- /**
- * Returns the Font associated with the character at the specified index.
- * An index ranges from 0 to length() - 1.
- * @exception java.lang.StringIndexOutOfBoundsException if the index
- * is not in the range 0 to length()-1.
- */
- public Font getFontAt(int index) {
- if (index < 0 || index > chars.length) {
- throw new StringIndexOutOfBoundsException(index);
- }
- int seg = findSegmentContaining(index);
- return (Font) attrs[seg].get(TextAttributeSet.FONT);
- }
-
- /**
- * Returns the length of this styled string.
- * The length is equal to the number of Unicode characters in
- * the styled string.
- *
- * @return the length of the sequence of characters
- * represented by this object.
- */
- public int length() {
- return chars.length;
- }
-
- /**
- * Return a hashcode
- * REMIND jk .new api
- */
- /*public int hashCode() {
- return chars.length ^ indices.length << 8;
- }*/
-
- /**
- * Return true if the strings have the same characters and
- * attribute runs.
- * REMIND jk .new api
- */
- public boolean equals(Object rhs) {
- if (rhs == this) {
- return true;
- } else if (rhs == null) {
- return false;
- } else {
- try {
- StyledString other = (StyledString)rhs;
-
- if (chars.length != other.chars.length ||
- indices.length != other.indices.length) {
- return false;
- }
-
- for (int i = 0; i < chars.length; i++) {
- if (chars[i] != other.chars[i]) {
- return false;
- }
- }
-
- for (int i = 0; i < indices.length; i++) {
- if (indices[i] != other.indices[i]) {
- return false;
- }
- }
-
- if (attrs != null && other.attrs != null) {
- for (int i = 0; i < attrs.length; i++) {
- if (!attrs[i].equals(other.attrs[i])) {
- return false;
- }
- }
- }
-
- return true;
- }
- catch (ClassCastException e) {
- return false;
- }
- }
- }
- /*
- * other new taligent calls. need to know if I want them.
- */
- public AttributedCharacterIterator createIterator() {
- return new StyledStringIterator(this);
- }
-
- public AttributedCharacterIterator createIterator(int start, int limit, int pos) {
- return new StyledStringIterator(this, start, limit, pos);
- }
-
-
- /**
- * Return an attribute set describing the attributes on the
- * character at index.
- *
- * @param index the index of the character.
- * @return the attributes of the character at index.
- * @exception StringIndexOutOfBoundsException if the index is
- * out of range.
- */
- public AttributeSet getAttributesAt(int index) {
- if (index < 0 || index >= chars.length) {
- throw new StringIndexOutOfBoundsException(index);
- }
- int seg = findSegmentContaining(index);
-
- return attrs[seg];
- }
-
- /**
- * Copies characters from this string into the destination character array.
- * <p>
- * The first character to be copied is at index <code>srcBegin</code>;
- * the last character to be copied is at index <code>srcEnd-1</code>
- * (thus the total number of characters to be copied is
- * <code>srcEnd-srcBegin</code>). The characters are copied into the
- * subarray of <code>dst</code> starting at index <code>dstBegin</code>
- * and ending at index:
- * <p><blockquote><pre>
- * dstbegin + (srcEnd-srcBegin) - 1
- * </pre></blockquote>
- *
- * @param srcBegin index of the first character in the string
- * to copy.
- * @param srcEnd index after the last character in the string
- * to copy.
- * @param dst the destination array.
- * @param dstBegin the start offset in the destination array.
- * @exception StringIndexOutOfBoundsException If srcBegin or srcEnd is out
- * of range, or if srcBegin is greater than the srcEnd.
- */
- public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) {
- if (srcBegin < 0) {
- throw new StringIndexOutOfBoundsException(srcBegin);
- }
- if (srcEnd > chars.length) {
- throw new StringIndexOutOfBoundsException(srcEnd);
- }
- if (srcEnd < srcBegin) {
- throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
- }
- System.arraycopy(chars, srcBegin, dst, dstBegin, srcEnd - srcBegin);
- }
-
- /* this exposes internals and must remain package private as long as it
- does not copy the char array. */
- char[] getChars() {
- return chars;
- }
-
- }
-
-
-