📄 glyphvectortoken.java
字号:
/*
* 10/28/2004
*
* GlyphVectorToken.java - A token that stores itself in a glyph vector.
* Copyright (C) 2004 Robert Futrell
* email@address.com
* www.website.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.fife.ui.rsyntaxtextarea;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import javax.swing.text.Segment;
import javax.swing.text.TabExpander;
/**
* A token that stores its image in a glyph vector, when possible, for fast
* painting. For tokens where this is not possible (i.e., tokens that may
* have a tab in them), the behavior is the same as
* {@link org.fife.ui.rsyntaxtextarea.DefaultToken}.<p>
*
* This token type stores itself in a glyph vector if it is not one of the
* following types:
* <ul>
* <li>Token.COMMENT</li>
* <li>Token.COMMENT_EOL</li>
* <li>Token.COMMENT_MULTILINE</li>
* <li>Token.COMMENT_DOCUMENTATION</li>
* <li>Token.LITERAL_STRING_DOUBLE_QUOTE</li>
* <li>Token.LITERAL_CHAR</li>
* <li>Token.LITERAL_BACKQUOTE</li>
* <li>Token.WHITESPACE</li>
* <li>Token.PREPROCESSOR</li>
* <li>Token.ERROR_STRING_DOUBLE</li>
* <li>Token.ERROR_CHAR</li>
* </ul>
* If it is one of those types, it is drawn like <code>DefaultToken</code>, as
* it is possible for the token to contain a tab.<p>
*
* Besides the benefit of speedier rendering, width calculations are also
* improved due to <code>GlyphVector</code>'s caching of width values. These
* width values are also better precision (floats, as opposed to ints returned
* by <code>FontMetrics.charsWidth()</code>), so our rendering hints should be
* a tad more accurate.<p>
*
* Note that these theoretical differences are far outweighed by the cost of
* allocating a new <code>GlyphVector</code> for every token painted, so this
* token type isn't actually very useful.<p>
*
* NOTE: This token type is experimental and is currently incorrect. In order
* for this token type to work, we'll have to pass the proper rendering
* hints to the token's set() method so the glyphvector is created
* correctly. We currently pass an FRC set to antialias, but not use
* fractional fontmetrics, regardless of the text area's current
* rendering hint state.
*
* @author Robert Futrell
* @version 0.1
* @see Token
* @see DefaultToken
* @see VisibleWhitespaceToken
*/
/*
* FIXME: This token must override makeStartAt and correct its glyph vector,
* but unfortunately we don't have the text area or FRC...
* FIXME2: This token should probably override DefaultToken's implementation
* of listOffsetToView()...
*/
public class GlyphVectorToken extends DefaultToken {
private GlyphVector glyphVector;
private float[] positions;
/*****************************************************************************/
/**
* Creates a "null token." The token itself is not null; rather, it
* signifies that it is the last token in a linked list of tokens and
* that it is not part of a "multiline token."
*/
public GlyphVectorToken() {
super();
}
/*****************************************************************************/
/**
* Constructor.
*
* @param line The segment from which to get the token.
* @param beg The first character's position in <code>line</code>.
* @param end The last character's position in <code>line</code>.
* @param startOffset The offset into the document at which this
* token begins.
* @param type A token type listed as "generic" above.
*/
public GlyphVectorToken(final Segment line, final int beg, final int end,
final int startOffset, final int type) {
super(line, beg,end, startOffset, type);
}
/*****************************************************************************/
/**
* Constructor.
*
* @param line The segment from which to get the token.
* @param beg The first character's position in <code>line</code>.
* @param end The last character's position in <code>line</code>.
* @param startOffset The offset into the document at which this
* token begins.
* @param type A token type listed as "generic" above.
*/
public GlyphVectorToken(final char[] line, final int beg, final int end,
final int startOffset, final int type) {
super(line, beg,end, startOffset, type);
}
/*****************************************************************************/
/**
* Determines the offset into this token list (i.e., into the
* document) that covers pixel location <code>x</code> if the token list
* starts at pixel location <code>x0</code><p>.
* This method will return the document position "closest" to the
* x-coordinate (i.e., if they click on the "right-half" of the
* <code>w</code> in <code>awe</code>, the caret will be placed in
* between the <code>w</code> and <code>e</code>; similarly, clicking on
* the left-half places the caret between the <code>a</code> and
* <code>w</code>). This makes it useful for methods such as
* <code>viewToModel</code> found in <code>javax.swing.text.View</code>
* subclasses.
*
* @param textArea The text area from which the token list was derived.
* @param e How to expand tabs.
* @param x0 The pixel x-location that is the beginning of
* <code>tokenList</code>.
* @param x The pixel-position for which you want to get the corresponding
* offset.
* @return The position (in the document, NOT into the token list!) that
* covers the pixel location. If <code>tokenList</code> is
* <code>null</code> or has type <code>Token.NULL</code>, then
* <code>-1</code is returned; the caller should recognize this and
* return the actual end position of the (empty) line.
*/
public int getListOffset(RSyntaxTextArea textArea, TabExpander e,
float x0, float x) {
// If the coordinate in question is before this line's start, quit.
if (x0 >= x)
return offset;
float currX = x0; // x-coordinate of current char.
float nextX = x0; // x-coordinate of next char.
float stableX = x0; // Cached ending x-coord. of last tab or token.
GlyphVectorToken token = this;
int last = offset;
FontMetrics fm = null;
while (token!=null && token.isPaintable()) {
if (token.glyphVector==null) {
fm = textArea.getFontMetricsForTokenType(token.type);
char[] text = token.text;
int start = token.textOffset;
int end = start + token.textCount;
for (int i=start; i<end; i++) {
currX = nextX;
if (text[i] == '\t') {
nextX = e.nextTabStop(nextX, 0);
stableX = nextX; // Cache ending x-coord. of tab.
start = i+1; // Do charsWidth() from next char.
}
else {
nextX = stableX + fm.charsWidth(text, start, i-start+1);
}
if (x>=currX && x<nextX) {
if ((x-currX) < (nextX-x))
return last + i-token.textOffset;
else
return last + i+1-token.textOffset;
}
}
}
else { // We have a glyph vector.
int count = token.textCount;
currX = stableX + token.getWidthUpTo(0, fm, e, stableX);
for (int i=1; i<=count; i++) {
nextX = stableX + token.getWidthUpTo(i, fm, e, stableX);
if (x>=currX && x<nextX) {
if ((x-currX) < (nextX-x))
return last + i - 1;
else
return last + i;
}
currX = nextX;
}
}
stableX = nextX; // Cache ending x-coordinate of token.
last += token.textCount;
token = (GlyphVectorToken)token.getNextToken();
}
// If we didn't find anything, return the end position of the text.
return last;
}
/*****************************************************************************/
/**
* Returns the width of a specified number of characters in this token.
* For example, for the token "while", specifying a value of <code>3</code>
* here returns the width of the "whi" portion of the token.
*
* @param numChars The number of characters for which to get the width.
* @param fm The font metrics used to paint this token.
* @param e How to expand tabs. This value cannot be <code>null</code>.
* @param x0 The pixel-location at which this token begins. This is needed
* because of tabs.
* @return The width of the specified number of characters in this token.
* @see #getWidth
*/
public float getWidthUpTo(int numChars, FontMetrics fm, TabExpander e,
float x0) {
if (glyphVector!=null)
return positions[numChars*2];
return super.getWidthUpTo(numChars, fm, e, x0);
}
/*****************************************************************************/
/**
* Initializes this token to use a glyph vector for painting/width
* calculations. This should be called after set().
*/
public void initGlyphVector(RSyntaxTextArea host, FontRenderContext frc) {
Font font = host.getFontForTokenType(type);
glyphVector = font.createGlyphVector(frc,
new String(text, textOffset, textCount));
positions = glyphVector.getGlyphPositions(0, textCount+1, null);
}
/*****************************************************************************/
/**
* Paints this token.
*
* @param g The graphics context in which to paint.
* @param x The x-coordinate at which to paint.
* @param y The y-coordinate at which to paint.
* @param scheme The syntax highlighting scheme to use.
* @param host The text area this token is in.
* @param e How to expand tabs.
* @param clipStart The left boundary of the clip rectangle in which we're
* painting. This optimizes painting by allowing us to
* not paint when this token is "to the left" of the clip
* rectangle.
* @return The x-coordinate representing the end of the painted text.
*/
public final float paint(Graphics2D g, float x, float y,
SyntaxScheme scheme,
RSyntaxTextArea host, TabExpander e,
float clipStart) {
if (glyphVector!=null) {
if (scheme.background!=null) {
FontMetrics fm = scheme.fontMetrics;
paintBackground(x,y,
getWidthUpTo(textCount, null, e, x), fm.getHeight(),
g, fm.getAscent(), host, scheme.background);
}
g.setColor(scheme.foreground);
g.drawGlyphVector(glyphVector, x,y);
if (scheme.underline) {
int y2 = (int)(y+1);
g.drawLine((int)x,y2, (int)positions[textCount-1],y2);
}
return x + getWidthUpTo(textCount, null, e, x);
}
else {
return super.paint(g, x,y, scheme, host, e, clipStart);
}
}
/*****************************************************************************/
/**
* Sets the value of this token to a particular segment of a document.
*
* @param line The segment from which to get the token.
* @param beg The first character's position in <code>line</code>.
* @param end The last character's position in <code>line</code>.
* @param offset The offset into the document at which this token begins.
* @param type A token type listed as "generic" above.
*/
public void set(final char[] line, final int beg, final int end,
final int offset, final int type) {
super.set(line, beg,end, offset, type);
glyphVector = null;
positions = null;
}
/*****************************************************************************/
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -