⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 glyphvectortoken.java

📁 具有不同语法高亮的编辑器实例
💻 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 + -