下面列出了java.text.AttributedCharacterIterator#first ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Draws a string of attributed characters at {@code (x, y)}.
*
* @param iterator an iterator over the characters ({@code null} not
* permitted).
* @param x the x-coordinate.
* @param y the y-coordinate.
*/
@Override
public void drawString(AttributedCharacterIterator iterator, float x,
float y) {
Set<AttributedCharacterIterator.Attribute>
s = iterator.getAllAttributeKeys();
if (!s.isEmpty()) {
TextLayout layout = new TextLayout(iterator,
getFontRenderContext());
layout.draw(this, x, y);
} else {
StringBuilder strb = new StringBuilder();
iterator.first();
for (int i = iterator.getBeginIndex(); i < iterator.getEndIndex();
i++) {
strb.append(iterator.current());
iterator.next();
}
drawString(strb.toString(), x, y);
}
}
/**
* Draws the characters of an AttributedCharacterIterator, starting from
* (x,y).
*/
public void drawString(AttributedCharacterIterator iterator, float x, float y) {
if(getAccurateTextMode()) {
TextLayout layout = new TextLayout(iterator, getFontRenderContext());
Shape shape = layout.getOutline(AffineTransform.getTranslateInstance(x, y));
draw(shape, "fill"); //$NON-NLS-1$
} else {
append("newpath"); //$NON-NLS-1$
Point2D location = transform(x, y);
append(location.getX()+" "+location.getY()+" moveto"); //$NON-NLS-1$ //$NON-NLS-2$
StringBuffer buffer = new StringBuffer();
for(char ch = iterator.first(); ch!=CharacterIterator.DONE; ch = iterator.next()) {
if((ch=='(')||(ch==')')) {
buffer.append('\\');
}
buffer.append(ch);
}
append("("+buffer.toString()+") show"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
/**
* @see Graphics2D#drawString(AttributedCharacterIterator, float, float)
*/
@Override
public void drawString( final AttributedCharacterIterator iter, float x, final float y ) {
/*
* StringBuffer sb = new StringBuffer(); for(char c = iter.first(); c != AttributedCharacterIterator.DONE; c =
* iter.next()) { sb.append(c); } drawString(sb.toString(),x,y);
*/
final StringBuilder stringbuffer = new StringBuilder( iter.getEndIndex() );
for ( char c = iter.first(); c != AttributedCharacterIterator.DONE; c = iter.next() ) {
if ( iter.getIndex() == iter.getRunStart() ) {
if ( stringbuffer.length() > 0 ) {
drawString( stringbuffer.toString(), x, y );
final FontMetrics fontmetrics = getFontMetrics();
x = (float) ( x + fontmetrics.getStringBounds( stringbuffer.toString(), this ).getWidth() );
stringbuffer.delete( 0, stringbuffer.length() );
}
doAttributes( iter );
}
stringbuffer.append( c );
}
drawString( stringbuffer.toString(), x, y );
underline = false;
}
/**
* When this returns, the ACI's current position will be at the start of the
* first run which does NOT contain a GraphicAttribute. If no such run exists
* the ACI's position will be at the end, and this method will return false.
*/
static boolean advanceToFirstFont(AttributedCharacterIterator aci) {
for (char ch = aci.first();
ch != CharacterIterator.DONE;
ch = aci.setIndex(aci.getRunLimit()))
{
if (aci.getAttribute(TextAttribute.CHAR_REPLACEMENT) == null) {
return true;
}
}
return false;
}
private static final void dumpIterator(AttributedCharacterIterator iterator) {
Set attributeKeys = iterator.getAllAttributeKeys();
System.out.print("All attributes: ");
Iterator keyIterator = attributeKeys.iterator();
while (keyIterator.hasNext()) {
Attribute key = (Attribute) keyIterator.next();
System.out.print(key);
}
for(char c = iterator.first(); c != CharacterIterator.DONE; c = iterator.next()) {
if (iterator.getIndex() == iterator.getBeginIndex() ||
iterator.getIndex() == iterator.getRunStart()) {
System.out.println();
Map attributes = iterator.getAttributes();
Set entries = attributes.entrySet();
Iterator attributeIterator = entries.iterator();
while (attributeIterator.hasNext()) {
Map.Entry entry = (Map.Entry) attributeIterator.next();
System.out.print("<" + entry.getKey() + ": "
+ entry.getValue() + ">");
}
}
System.out.print(" ");
System.out.print(c);
}
System.out.println();
System.out.println("done");
System.out.println();
}
/**
* Draws a string at the specified position.
*
* @param iterator the string.
* @param x the x-coordinate.
* @param y the y-coordinate.
*/
public void drawString(AttributedCharacterIterator iterator, int x, int y) {
// for now we simply want to extract the chars from the iterator
// and call an unstyled text renderer
StringBuffer sb = new StringBuffer();
int numChars = iterator.getEndIndex() - iterator.getBeginIndex();
char c = iterator.first();
for (int i = 0; i < numChars; i++) {
sb.append(c);
c = iterator.next();
}
drawString(new String(sb),x,y);
}
/**
* Constructs a <code>TextLayout</code> from an iterator over styled text.
* <p>
* The iterator must specify a single paragraph of text because an
* entire paragraph is required for the bidirectional
* algorithm.
* @param text the styled text to display
* @param frc contains information about a graphics device which is needed
* to measure the text correctly.
* Text measurements can vary slightly depending on the
* device resolution, and attributes such as antialiasing. This
* parameter does not specify a translation between the
* <code>TextLayout</code> and user space.
*/
public TextLayout(AttributedCharacterIterator text, FontRenderContext frc) {
if (text == null) {
throw new IllegalArgumentException("Null iterator passed to TextLayout constructor.");
}
int start = text.getBeginIndex();
int limit = text.getEndIndex();
if (start == limit) {
throw new IllegalArgumentException("Zero length iterator passed to TextLayout constructor.");
}
int len = limit - start;
text.first();
char[] chars = new char[len];
int n = 0;
for (char c = text.first();
c != CharacterIterator.DONE;
c = text.next())
{
chars[n++] = c;
}
text.first();
if (text.getRunLimit() == limit) {
Map<? extends Attribute, ?> attributes = text.getAttributes();
Font font = singleFont(chars, 0, len, attributes);
if (font != null) {
fastInit(chars, font, attributes, frc);
return;
}
}
standardInit(text, chars, frc);
}
private static final void checkIteratorSubranges(AttributedCharacterIterator iterator, int[] expectedLimits) throws Exception {
int previous = 0;
char c = iterator.first();
for (int i = 0; i < expectedLimits.length; i++) {
if (iterator.getRunStart() != previous || iterator.getRunLimit() != expectedLimits[i]) {
throwException(iterator, "run boundaries are not as expected: " + iterator.getRunStart() + ", " + iterator.getRunLimit());
}
previous = expectedLimits[i];
c = iterator.setIndex(previous);
}
if (c != CharacterIterator.DONE) {
throwException(iterator, "iterator's run sequence doesn't end with DONE");
}
}
@Override
String format(
AttributedCharacterIterator iterator,
String preExponent) {
int copyFromOffset = 0;
StringBuilder result = new StringBuilder();
for (
iterator.first();
iterator.current() != CharacterIterator.DONE;
) {
Map<Attribute, Object> attributeSet = iterator.getAttributes();
if (attributeSet.containsKey(NumberFormat.Field.EXPONENT_SYMBOL)) {
append(
iterator,
copyFromOffset,
iterator.getRunStart(NumberFormat.Field.EXPONENT_SYMBOL),
result);
copyFromOffset = iterator.getRunLimit(NumberFormat.Field.EXPONENT_SYMBOL);
iterator.setIndex(copyFromOffset);
result.append(preExponent);
result.append(beginMarkup);
} else if (attributeSet.containsKey(NumberFormat.Field.EXPONENT)) {
int limit = iterator.getRunLimit(NumberFormat.Field.EXPONENT);
append(
iterator,
copyFromOffset,
limit,
result);
copyFromOffset = limit;
iterator.setIndex(copyFromOffset);
result.append(endMarkup);
} else {
iterator.next();
}
}
append(iterator, copyFromOffset, iterator.getEndIndex(), result);
return result.toString();
}
/**
* Tests two attributed strings for equality.
*
* @param s1 string 1 (<code>null</code> permitted).
* @param s2 string 2 (<code>null</code> permitted).
*
* @return <code>true</code> if <code>s1</code> and <code>s2</code> are
* equal or both <code>null</code>, and <code>false</code>
* otherwise.
*/
public static boolean equal(AttributedString s1, AttributedString s2) {
if (s1 == null) {
return (s2 == null);
}
if (s2 == null) {
return false;
}
AttributedCharacterIterator it1 = s1.getIterator();
AttributedCharacterIterator it2 = s2.getIterator();
char c1 = it1.first();
char c2 = it2.first();
int start = 0;
while (c1 != CharacterIterator.DONE) {
int limit1 = it1.getRunLimit();
int limit2 = it2.getRunLimit();
if (limit1 != limit2) {
return false;
}
// if maps aren't equivalent, return false
Map m1 = it1.getAttributes();
Map m2 = it2.getAttributes();
if (!m1.equals(m2)) {
return false;
}
// now check characters in the run are the same
for (int i = start; i < limit1; i++) {
if (c1 != c2) {
return false;
}
c1 = it1.next();
c2 = it2.next();
}
start = limit1;
}
return c2 == CharacterIterator.DONE;
}
private static final void checkIteratorSubranges(AttributedCharacterIterator iterator, int[] expectedLimits) throws Exception {
int previous = 0;
char c = iterator.first();
for (int i = 0; i < expectedLimits.length; i++) {
if (iterator.getRunStart() != previous || iterator.getRunLimit() != expectedLimits[i]) {
throwException(iterator, "run boundaries are not as expected: " + iterator.getRunStart() + ", " + iterator.getRunLimit());
}
previous = expectedLimits[i];
c = iterator.setIndex(previous);
}
if (c != CharacterIterator.DONE) {
throwException(iterator, "iterator's run sequence doesn't end with DONE");
}
}
/**
* Constructs a <code>TextLayout</code> from an iterator over styled text.
* <p>
* The iterator must specify a single paragraph of text because an
* entire paragraph is required for the bidirectional
* algorithm.
* @param text the styled text to display
* @param frc contains information about a graphics device which is needed
* to measure the text correctly.
* Text measurements can vary slightly depending on the
* device resolution, and attributes such as antialiasing. This
* parameter does not specify a translation between the
* <code>TextLayout</code> and user space.
*/
public TextLayout(AttributedCharacterIterator text, FontRenderContext frc) {
if (text == null) {
throw new IllegalArgumentException("Null iterator passed to TextLayout constructor.");
}
int start = text.getBeginIndex();
int limit = text.getEndIndex();
if (start == limit) {
throw new IllegalArgumentException("Zero length iterator passed to TextLayout constructor.");
}
int len = limit - start;
text.first();
char[] chars = new char[len];
int n = 0;
for (char c = text.first();
c != CharacterIterator.DONE;
c = text.next())
{
chars[n++] = c;
}
text.first();
if (text.getRunLimit() == limit) {
Map<? extends Attribute, ?> attributes = text.getAttributes();
Font font = singleFont(chars, 0, len, attributes);
if (font != null) {
fastInit(chars, font, attributes, frc);
return;
}
}
standardInit(text, chars, frc);
}
private static final void checkIteratorSubranges(AttributedCharacterIterator iterator, Attribute key, int[] expectedLimits) throws Exception {
int previous = 0;
char c = iterator.first();
for (int i = 0; i < expectedLimits.length; i++) {
if (iterator.getRunStart(key) != previous || iterator.getRunLimit(key) != expectedLimits[i]) {
throwException(iterator, "run boundaries are not as expected: " + iterator.getRunStart(key) + ", " + iterator.getRunLimit(key) + " for key " + key);
}
previous = expectedLimits[i];
c = iterator.setIndex(previous);
}
if (c != CharacterIterator.DONE) {
throwException(iterator, "iterator's run sequence doesn't end with DONE");
}
}
/**
* Create a new StyledParagraph over the given styled text.
* @param aci an iterator over the text
* @param chars the characters extracted from aci
*/
public StyledParagraph(AttributedCharacterIterator aci,
char[] chars) {
int start = aci.getBeginIndex();
int end = aci.getEndIndex();
length = end - start;
int index = start;
aci.first();
do {
final int nextRunStart = aci.getRunLimit();
final int localIndex = index-start;
Map<? extends Attribute, ?> attributes = aci.getAttributes();
attributes = addInputMethodAttrs(attributes);
Decoration d = Decoration.getDecoration(attributes);
addDecoration(d, localIndex);
Object f = getGraphicOrFont(attributes);
if (f == null) {
addFonts(chars, attributes, localIndex, nextRunStart-start);
}
else {
addFont(f, localIndex);
}
aci.setIndex(nextRunStart);
index = nextRunStart;
} while (index < end);
// Add extra entries to starts arrays with the length
// of the paragraph. 'this' is used as a dummy value
// in the Vector.
if (decorations != null) {
decorationStarts = addToVector(this, length, decorations, decorationStarts);
}
if (fonts != null) {
fontStarts = addToVector(this, length, fonts, fontStarts);
}
}
/**
* Perform the Unicode Bidi algorithm on a given paragraph, as defined in the
* <a href="http://www.unicode.org/unicode/reports/tr9/">Unicode Standard Annex #9</a>,
* version 13,
* also described in The Unicode Standard, Version 4.0 .<p>
*
* This method takes a paragraph of text and computes the
* left-right-directionality of each character. The text should not
* contain any Unicode block separators.<p>
*
* The RUN_DIRECTION attribute in the text, if present, determines the base
* direction (left-to-right or right-to-left). If not present, the base
* direction is computed using the Unicode Bidirectional Algorithm,
* defaulting to left-to-right if there are no strong directional characters
* in the text. This attribute, if present, must be applied to all the text
* in the paragraph.<p>
*
* The BIDI_EMBEDDING attribute in the text, if present, represents
* embedding level information. Negative values from -1 to -62 indicate
* overrides at the absolute value of the level. Positive values from 1 to
* 62 indicate embeddings. Where values are zero or not defined, the base
* embedding level as determined by the base direction is assumed.<p>
*
* The NUMERIC_SHAPING attribute in the text, if present, converts European
* digits to other decimal digits before running the bidi algorithm. This
* attribute, if present, must be applied to all the text in the paragraph.
*
* If the entire text is all of the same directionality, then
* the method may not perform all the steps described by the algorithm,
* i.e., some levels may not be the same as if all steps were performed.
* This is not relevant for unidirectional text.<br>
* For example, in pure LTR text with numbers the numbers would get
* a resolved level of 2 higher than the surrounding text according to
* the algorithm. This implementation may set all resolved levels to
* the same value in such a case.<p>
*
* @param paragraph a paragraph of text with optional character and
* paragraph attribute information
* @stable ICU 3.8
*/
public void setPara(AttributedCharacterIterator paragraph)
{
byte paraLvl;
char ch = paragraph.first();
Boolean runDirection =
(Boolean) paragraph.getAttribute(TextAttributeConstants.RUN_DIRECTION);
Object shaper = paragraph.getAttribute(TextAttributeConstants.NUMERIC_SHAPING);
if (runDirection == null) {
paraLvl = INTERNAL_LEVEL_DEFAULT_LTR;
} else {
paraLvl = (runDirection.equals(TextAttributeConstants.RUN_DIRECTION_LTR)) ?
(byte)Bidi.DIRECTION_LEFT_TO_RIGHT : (byte)Bidi.DIRECTION_RIGHT_TO_LEFT;
}
byte[] lvls = null;
int len = paragraph.getEndIndex() - paragraph.getBeginIndex();
byte[] embeddingLevels = new byte[len];
char[] txt = new char[len];
int i = 0;
while (ch != AttributedCharacterIterator.DONE) {
txt[i] = ch;
Integer embedding =
(Integer) paragraph.getAttribute(TextAttributeConstants.BIDI_EMBEDDING);
if (embedding != null) {
byte level = embedding.byteValue();
if (level == 0) {
/* no-op */
} else if (level < 0) {
lvls = embeddingLevels;
embeddingLevels[i] = (byte)((0 - level) | INTERNAL_LEVEL_OVERRIDE);
} else {
lvls = embeddingLevels;
embeddingLevels[i] = level;
}
}
ch = paragraph.next();
++i;
}
if (shaper != null) {
NumericShapings.shape(shaper, txt, 0, len);
}
setPara(txt, paraLvl, lvls);
}
/**
* Serialises an <code>AttributedString</code> object.
*
* @param as the attributed string object (<code>null</code> permitted).
* @param stream the output stream (<code>null</code> not permitted).
*
* @throws IOException if there is an I/O error.
*/
public static void writeAttributedString(AttributedString as,
ObjectOutputStream stream) throws IOException {
if (stream == null) {
throw new IllegalArgumentException("Null 'stream' argument.");
}
if (as != null) {
stream.writeBoolean(false);
AttributedCharacterIterator aci = as.getIterator();
// build a plain string from aci
// then write the string
StringBuffer plainStr = new StringBuffer();
char current = aci.first();
while (current != CharacterIterator.DONE) {
plainStr = plainStr.append(current);
current = aci.next();
}
stream.writeObject(plainStr.toString());
// then write the attributes and limits for each run
current = aci.first();
int begin = aci.getBeginIndex();
while (current != CharacterIterator.DONE) {
// write the current character - when the reader sees that this
// is not CharacterIterator.DONE, it will know to read the
// run limits and attributes
stream.writeChar(current);
// now write the limit, adjusted as if beginIndex is zero
int limit = aci.getRunLimit();
stream.writeInt(limit - begin);
// now write the attribute set
Map atts = new HashMap(aci.getAttributes());
stream.writeObject(atts);
current = aci.setIndex(limit);
}
// write a character that signals to the reader that all runs
// are done...
stream.writeChar(CharacterIterator.DONE);
}
else {
// write a flag that indicates a null
stream.writeBoolean(true);
}
}
/**
* Perform the Unicode Bidi algorithm on a given paragraph, as defined in the
* <a href="http://www.unicode.org/unicode/reports/tr9/">Unicode Standard Annex #9</a>,
* version 13,
* also described in The Unicode Standard, Version 4.0 .<p>
*
* This method takes a paragraph of text and computes the
* left-right-directionality of each character. The text should not
* contain any Unicode block separators.<p>
*
* The RUN_DIRECTION attribute in the text, if present, determines the base
* direction (left-to-right or right-to-left). If not present, the base
* direction is computed using the Unicode Bidirectional Algorithm,
* defaulting to left-to-right if there are no strong directional characters
* in the text. This attribute, if present, must be applied to all the text
* in the paragraph.<p>
*
* The BIDI_EMBEDDING attribute in the text, if present, represents
* embedding level information. Negative values from -1 to -62 indicate
* overrides at the absolute value of the level. Positive values from 1 to
* 62 indicate embeddings. Where values are zero or not defined, the base
* embedding level as determined by the base direction is assumed.<p>
*
* The NUMERIC_SHAPING attribute in the text, if present, converts European
* digits to other decimal digits before running the bidi algorithm. This
* attribute, if present, must be applied to all the text in the paragraph.
*
* If the entire text is all of the same directionality, then
* the method may not perform all the steps described by the algorithm,
* i.e., some levels may not be the same as if all steps were performed.
* This is not relevant for unidirectional text.<br>
* For example, in pure LTR text with numbers the numbers would get
* a resolved level of 2 higher than the surrounding text according to
* the algorithm. This implementation may set all resolved levels to
* the same value in such a case.<p>
*
* @param paragraph a paragraph of text with optional character and
* paragraph attribute information
* @stable ICU 3.8
*/
public void setPara(AttributedCharacterIterator paragraph)
{
byte paraLvl;
char ch = paragraph.first();
Boolean runDirection =
(Boolean) paragraph.getAttribute(TextAttributeConstants.RUN_DIRECTION);
Object shaper = paragraph.getAttribute(TextAttributeConstants.NUMERIC_SHAPING);
if (runDirection == null) {
paraLvl = INTERNAL_LEVEL_DEFAULT_LTR;
} else {
paraLvl = (runDirection.equals(TextAttributeConstants.RUN_DIRECTION_LTR)) ?
(byte)Bidi.DIRECTION_LEFT_TO_RIGHT : (byte)Bidi.DIRECTION_RIGHT_TO_LEFT;
}
byte[] lvls = null;
int len = paragraph.getEndIndex() - paragraph.getBeginIndex();
byte[] embeddingLevels = new byte[len];
char[] txt = new char[len];
int i = 0;
while (ch != AttributedCharacterIterator.DONE) {
txt[i] = ch;
Integer embedding =
(Integer) paragraph.getAttribute(TextAttributeConstants.BIDI_EMBEDDING);
if (embedding != null) {
byte level = embedding.byteValue();
if (level == 0) {
/* no-op */
} else if (level < 0) {
lvls = embeddingLevels;
embeddingLevels[i] = (byte)((0 - level) | INTERNAL_LEVEL_OVERRIDE);
} else {
lvls = embeddingLevels;
embeddingLevels[i] = level;
}
}
ch = paragraph.next();
++i;
}
if (shaper != null) {
NumericShapings.shape(shaper, txt, 0, len);
}
setPara(txt, paraLvl, lvls);
}
/**
* Create a new StyledParagraph over the given styled text.
* @param aci an iterator over the text
* @param chars the characters extracted from aci
*/
public StyledParagraph(AttributedCharacterIterator aci,
char[] chars) {
int start = aci.getBeginIndex();
int end = aci.getEndIndex();
length = end - start;
int index = start;
aci.first();
do {
final int nextRunStart = aci.getRunLimit();
final int localIndex = index-start;
Map<? extends Attribute, ?> attributes = aci.getAttributes();
attributes = addInputMethodAttrs(attributes);
Decoration d = Decoration.getDecoration(attributes);
addDecoration(d, localIndex);
Object f = getGraphicOrFont(attributes);
if (f == null) {
addFonts(chars, attributes, localIndex, nextRunStart-start);
}
else {
addFont(f, localIndex);
}
aci.setIndex(nextRunStart);
index = nextRunStart;
} while (index < end);
// Add extra entries to starts arrays with the length
// of the paragraph. 'this' is used as a dummy value
// in the Vector.
if (decorations != null) {
decorationStarts = addToVector(this, length, decorations, decorationStarts);
}
if (fonts != null) {
fontStarts = addToVector(this, length, fonts, fontStarts);
}
}
/**
* Create a new StyledParagraph over the given styled text.
* @param aci an iterator over the text
* @param chars the characters extracted from aci
*/
public StyledParagraph(AttributedCharacterIterator aci,
char[] chars) {
int start = aci.getBeginIndex();
int end = aci.getEndIndex();
length = end - start;
int index = start;
aci.first();
do {
final int nextRunStart = aci.getRunLimit();
final int localIndex = index-start;
Map<? extends Attribute, ?> attributes = aci.getAttributes();
attributes = addInputMethodAttrs(attributes);
Decoration d = Decoration.getDecoration(attributes);
addDecoration(d, localIndex);
Object f = getGraphicOrFont(attributes);
if (f == null) {
addFonts(chars, attributes, localIndex, nextRunStart-start);
}
else {
addFont(f, localIndex);
}
aci.setIndex(nextRunStart);
index = nextRunStart;
} while (index < end);
// Add extra entries to starts arrays with the length
// of the paragraph. 'this' is used as a dummy value
// in the Vector.
if (decorations != null) {
decorationStarts = addToVector(this, length, decorations, decorationStarts);
}
if (fonts != null) {
fontStarts = addToVector(this, length, fonts, fontStarts);
}
}
/**
* Create a new StyledParagraph over the given styled text.
* @param aci an iterator over the text
* @param chars the characters extracted from aci
*/
public StyledParagraph(AttributedCharacterIterator aci,
char[] chars) {
int start = aci.getBeginIndex();
int end = aci.getEndIndex();
length = end - start;
int index = start;
aci.first();
do {
final int nextRunStart = aci.getRunLimit();
final int localIndex = index-start;
Map<? extends Attribute, ?> attributes = aci.getAttributes();
attributes = addInputMethodAttrs(attributes);
Decoration d = Decoration.getDecoration(attributes);
addDecoration(d, localIndex);
Object f = getGraphicOrFont(attributes);
if (f == null) {
addFonts(chars, attributes, localIndex, nextRunStart-start);
}
else {
addFont(f, localIndex);
}
aci.setIndex(nextRunStart);
index = nextRunStart;
} while (index < end);
// Add extra entries to starts arrays with the length
// of the paragraph. 'this' is used as a dummy value
// in the Vector.
if (decorations != null) {
decorationStarts = addToVector(this, length, decorations, decorationStarts);
}
if (fonts != null) {
fontStarts = addToVector(this, length, fonts, fontStarts);
}
}