You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-commits@xmlgraphics.apache.org by ca...@apache.org on 2007/11/13 01:40:58 UTC

svn commit: r594367 [9/9] - in /xmlgraphics/batik/trunk: ./ resources/org/apache/batik/apps/svgbrowser/resources/ resources/org/apache/batik/util/gui/resources/ sources-1.3/org/apache/batik/util/ sources-1.3/org/apache/batik/util/gui/ sources-1.4/org/a...

Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextAreaPainter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextAreaPainter.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextAreaPainter.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextAreaPainter.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,699 @@
+/*
+ * TextAreaPainter.java - Paints the text area
+ * Copyright (C) 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+package org.gjt.sp.jedit.textarea;
+
+import javax.swing.ToolTipManager;
+import javax.swing.text.*;
+import javax.swing.JComponent;
+import java.awt.event.MouseEvent;
+import java.awt.*;
+
+/**
+ * The text area repaint manager. It performs double buffering and paints
+ * lines of text.
+ * @author Slava Pestov
+ * @version $Id: TextAreaPainter.java,v 1.24 1999/12/13 03:40:30 sp Exp $
+ */
+public class TextAreaPainter extends JComponent implements TabExpander
+{
+	/**
+	 * Creates a new repaint manager. This should be not be called
+	 * directly.
+	 */
+	public TextAreaPainter(JEditTextArea textArea, TextAreaDefaults defaults)
+	{
+		this.textArea = textArea;
+
+		setAutoscrolls(true);
+		setDoubleBuffered(true);
+		setOpaque(true);
+
+		ToolTipManager.sharedInstance().registerComponent(this);
+
+		currentLine = new Segment();
+		currentLineIndex = -1;
+
+		setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
+
+		setFont(new Font("Monospaced",Font.PLAIN,14));
+		setForeground(Color.black);
+		setBackground(Color.white);
+
+		blockCaret = defaults.blockCaret;
+		styles = defaults.styles;
+		cols = defaults.cols;
+		rows = defaults.rows;
+		caretColor = defaults.caretColor;
+		selectionColor = defaults.selectionColor;
+		lineHighlightColor = defaults.lineHighlightColor;
+		lineHighlight = defaults.lineHighlight;
+		bracketHighlightColor = defaults.bracketHighlightColor;
+		bracketHighlight = defaults.bracketHighlight;
+		paintInvalid = defaults.paintInvalid;
+		eolMarkerColor = defaults.eolMarkerColor;
+		eolMarkers = defaults.eolMarkers;
+	}
+
+	/**
+	 * Returns if this component can be traversed by pressing the
+	 * Tab key. This returns false.
+	 */
+	public final boolean isManagingFocus()
+	{
+		return false;
+	}
+
+	/**
+	 * Returns the syntax styles used to paint colorized text. Entry <i>n</i>
+	 * will be used to paint tokens with id = <i>n</i>.
+	 * @see org.gjt.sp.jedit.syntax.Token
+	 */
+	public final SyntaxStyle[] getStyles()
+	{
+		return styles;
+	}
+
+	/**
+	 * Sets the syntax styles used to paint colorized text. Entry <i>n</i>
+	 * will be used to paint tokens with id = <i>n</i>.
+	 * @param styles The syntax styles
+	 * @see org.gjt.sp.jedit.syntax.Token
+	 */
+	public final void setStyles(SyntaxStyle[] styles)
+	{
+		this.styles = styles;
+		repaint();
+	}
+
+	/**
+	 * Returns the caret color.
+	 */
+	public final Color getCaretColor()
+	{
+		return caretColor;
+	}
+
+	/**
+	 * Sets the caret color.
+	 * @param caretColor The caret color
+	 */
+	public final void setCaretColor(Color caretColor)
+	{
+		this.caretColor = caretColor;
+		invalidateSelectedLines();
+	}
+
+	/**
+	 * Returns the selection color.
+	 */
+	public final Color getSelectionColor()
+	{
+		return selectionColor;
+	}
+
+	/**
+	 * Sets the selection color.
+	 * @param selectionColor The selection color
+	 */
+	public final void setSelectionColor(Color selectionColor)
+	{
+		this.selectionColor = selectionColor;
+		invalidateSelectedLines();
+	}
+
+	/**
+	 * Returns the line highlight color.
+	 */
+	public final Color getLineHighlightColor()
+	{
+		return lineHighlightColor;
+	}
+
+	/**
+	 * Sets the line highlight color.
+	 * @param lineHighlightColor The line highlight color
+	 */
+	public final void setLineHighlightColor(Color lineHighlightColor)
+	{
+		this.lineHighlightColor = lineHighlightColor;
+		invalidateSelectedLines();
+	}
+
+	/**
+	 * Returns true if line highlight is enabled, false otherwise.
+	 */
+	public final boolean isLineHighlightEnabled()
+	{
+		return lineHighlight;
+	}
+
+	/**
+	 * Enables or disables current line highlighting.
+	 * @param lineHighlight True if current line highlight should be enabled,
+	 * false otherwise
+	 */
+	public final void setLineHighlightEnabled(boolean lineHighlight)
+	{
+		this.lineHighlight = lineHighlight;
+		invalidateSelectedLines();
+	}
+
+	/**
+	 * Returns the bracket highlight color.
+	 */
+	public final Color getBracketHighlightColor()
+	{
+		return bracketHighlightColor;
+	}
+
+	/**
+	 * Sets the bracket highlight color.
+	 * @param bracketHighlightColor The bracket highlight color
+	 */
+	public final void setBracketHighlightColor(Color bracketHighlightColor)
+	{
+		this.bracketHighlightColor = bracketHighlightColor;
+		invalidateLine(textArea.getBracketLine());
+	}
+
+	/**
+	 * Returns true if bracket highlighting is enabled, false otherwise.
+	 * When bracket highlighting is enabled, the bracket matching the
+	 * one before the caret (if any) is highlighted.
+	 */
+	public final boolean isBracketHighlightEnabled()
+	{
+		return bracketHighlight;
+	}
+
+	/**
+	 * Enables or disables bracket highlighting.
+	 * When bracket highlighting is enabled, the bracket matching the
+	 * one before the caret (if any) is highlighted.
+	 * @param bracketHighlight True if bracket highlighting should be
+	 * enabled, false otherwise
+	 */
+	public final void setBracketHighlightEnabled(boolean bracketHighlight)
+	{
+		this.bracketHighlight = bracketHighlight;
+		invalidateLine(textArea.getBracketLine());
+	}
+
+	/**
+	 * Returns true if the caret should be drawn as a block, false otherwise.
+	 */
+	public final boolean isBlockCaretEnabled()
+	{
+		return blockCaret;
+	}
+
+	/**
+	 * Sets if the caret should be drawn as a block, false otherwise.
+	 * @param blockCaret True if the caret should be drawn as a block,
+	 * false otherwise.
+	 */
+	public final void setBlockCaretEnabled(boolean blockCaret)
+	{
+		this.blockCaret = blockCaret;
+		invalidateSelectedLines();
+	}
+
+	/**
+	 * Returns the EOL marker color.
+	 */
+	public final Color getEOLMarkerColor()
+	{
+		return eolMarkerColor;
+	}
+
+	/**
+	 * Sets the EOL marker color.
+	 * @param eolMarkerColor The EOL marker color
+	 */
+	public final void setEOLMarkerColor(Color eolMarkerColor)
+	{
+		this.eolMarkerColor = eolMarkerColor;
+		repaint();
+	}
+
+	/**
+	 * Returns true if EOL markers are drawn, false otherwise.
+	 */
+	public final boolean getEOLMarkersPainted()
+	{
+		return eolMarkers;
+	}
+
+	/**
+	 * Sets if EOL markers are to be drawn.
+	 * @param eolMarkers True if EOL markers should be drawn, false otherwise
+	 */
+	public final void setEOLMarkersPainted(boolean eolMarkers)
+	{
+		this.eolMarkers = eolMarkers;
+		repaint();
+	}
+
+	/**
+	 * Returns true if invalid lines are painted as red tildes (~),
+	 * false otherwise.
+	 */
+	public boolean getInvalidLinesPainted()
+	{
+		return paintInvalid;
+	}
+
+	/**
+	 * Sets if invalid lines are to be painted as red tildes.
+	 * @param paintInvalid True if invalid lines should be drawn, false otherwise
+	 */
+	public void setInvalidLinesPainted(boolean paintInvalid)
+	{
+		this.paintInvalid = paintInvalid;
+	}
+
+	/**
+	 * Adds a custom highlight painter.
+	 * @param highlight The highlight
+	 */
+	public void addCustomHighlight(Highlight highlight)
+	{
+		highlight.init(textArea,highlights);
+		highlights = highlight;
+	}
+
+	/**
+	 * Highlight interface.
+	 */
+	public interface Highlight
+	{
+		/**
+		 * Called after the highlight painter has been added.
+		 * @param textArea The text area
+		 * @param next The painter this one should delegate to
+		 */
+		void init(JEditTextArea textArea, Highlight next);
+
+		/**
+		 * This should paint the highlight and delgate to the
+		 * next highlight painter.
+		 * @param gfx The graphics context
+		 * @param line The line number
+		 * @param y The y co-ordinate of the line
+		 */
+		void paintHighlight(Graphics gfx, int line, int y);
+
+		/**
+		 * Returns the tool tip to display at the specified
+		 * location. If this highlighter doesn't know what to
+		 * display, it should delegate to the next highlight
+		 * painter.
+		 * @param evt The mouse event
+		 */
+		String getToolTipText(MouseEvent evt);
+	}
+
+	/**
+	 * Returns the tool tip to display at the specified location.
+	 * @param evt The mouse event
+	 */
+	public String getToolTipText(MouseEvent evt)
+	{
+		if(highlights != null)
+			return highlights.getToolTipText(evt);
+		else
+			return null;
+	}
+
+	/**
+	 * Returns the font metrics used by this component.
+	 */
+	public FontMetrics getFontMetrics()
+	{
+		return fm;
+	}
+
+	/**
+	 * Sets the font for this component. This is overridden to update the
+	 * cached font metrics and to recalculate which lines are visible.
+	 * @param font The font
+	 */
+	public void setFont(Font font)
+	{
+		super.setFont(font);
+		fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
+		textArea.recalculateVisibleLines();
+	}
+
+	/**
+	 * Repaints the text.
+	 * @param g The graphics context
+	 */
+	public void paint(Graphics gfx)
+	{
+		Graphics2D g2d = (Graphics2D) gfx;
+		Object aa = g2d.getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING);
+		g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+                                     RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+		tabSize = fm.charWidth(' ') * ((Integer)textArea
+			.getDocument().getProperty(
+			PlainDocument.tabSizeAttribute)).intValue();
+
+		Rectangle clipRect = gfx.getClipBounds();
+
+		gfx.setColor(getBackground());
+		gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height);
+
+		// We don't use yToLine() here because that method doesn't
+		// return lines past the end of the document
+		int height = fm.getHeight();
+		int firstLine = textArea.getFirstLine();
+		int firstInvalid = firstLine + clipRect.y / height;
+		// Because the clipRect's height is usually an even multiple
+		// of the font height, we subtract 1 from it, otherwise one
+		// too many lines will always be painted.
+		int lastInvalid = firstLine + (clipRect.y + clipRect.height - 1) / height;
+
+		try
+		{
+			TokenMarker tokenMarker = textArea.getDocument()
+				.getTokenMarker();
+			int x = textArea.getHorizontalOffset();
+
+			for(int line = firstInvalid; line <= lastInvalid; line++)
+			{
+				paintLine(gfx,tokenMarker,line,x);
+			}
+
+			if(tokenMarker != null && tokenMarker.isNextLineRequested())
+			{
+				int h = clipRect.y + clipRect.height;
+				repaint(0,h,getWidth(),getHeight() - h);
+			}
+		}
+		catch(Exception e)
+		{
+			System.err.println("Error repainting line"
+				+ " range {" + firstInvalid + ","
+				+ lastInvalid + "}:");
+			e.printStackTrace();
+		}
+		g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, aa);
+	}
+
+	/**
+	 * Marks a line as needing a repaint.
+	 * @param line The line to invalidate
+	 */
+	public final void invalidateLine(int line)
+	{
+		repaint(0,textArea.lineToY(line) + fm.getMaxDescent() + fm.getLeading(),
+			getWidth(),fm.getHeight());
+	}
+
+	/**
+	 * Marks a range of lines as needing a repaint.
+	 * @param firstLine The first line to invalidate
+	 * @param lastLine The last line to invalidate
+	 */
+	public final void invalidateLineRange(int firstLine, int lastLine)
+	{
+		repaint(0,textArea.lineToY(firstLine) + fm.getMaxDescent() + fm.getLeading(),
+			getWidth(),(lastLine - firstLine + 1) * fm.getHeight());
+	}
+
+	/**
+	 * Repaints the lines containing the selection.
+	 */
+	public final void invalidateSelectedLines()
+	{
+		invalidateLineRange(textArea.getSelectionStartLine(),
+			textArea.getSelectionEndLine());
+	}
+
+	/**
+	 * Implementation of TabExpander interface. Returns next tab stop after
+	 * a specified point.
+	 * @param x The x co-ordinate
+	 * @param tabOffset Ignored
+	 * @return The next tab stop after <i>x</i>
+	 */
+	public float nextTabStop(float x, int tabOffset)
+	{
+		int offset = textArea.getHorizontalOffset();
+		int ntabs = ((int)x - offset) / tabSize;
+		return (ntabs + 1) * tabSize + offset;
+	}
+
+	/**
+	 * Returns the painter's preferred size.
+	 */
+	public Dimension getPreferredSize()
+	{
+		Dimension dim = new Dimension();
+		dim.width = fm.charWidth('w') * cols;
+		dim.height = fm.getHeight() * rows;
+		return dim;
+	}
+
+
+	/**
+	 * Returns the painter's minimum size.
+	 */
+	public Dimension getMinimumSize()
+	{
+		return getPreferredSize();
+	}
+
+	// package-private members
+	int currentLineIndex;
+	Token currentLineTokens;
+	Segment currentLine;
+
+	// protected members
+	protected JEditTextArea textArea;
+	
+	protected SyntaxStyle[] styles;
+	protected Color caretColor;
+	protected Color selectionColor;
+	protected Color lineHighlightColor;
+	protected Color bracketHighlightColor;
+	protected Color eolMarkerColor;
+
+	protected boolean blockCaret;
+	protected boolean lineHighlight;
+	protected boolean bracketHighlight;
+	protected boolean paintInvalid;
+	protected boolean eolMarkers;
+	protected int cols;
+	protected int rows;
+	
+	protected int tabSize;
+	protected FontMetrics fm;
+
+	protected Highlight highlights;
+
+	protected void paintLine(Graphics gfx, TokenMarker tokenMarker,
+		int line, int x)
+	{
+		Font defaultFont = getFont();
+		Color defaultColor = getForeground();
+
+		currentLineIndex = line;
+		int y = textArea.lineToY(line);
+
+		if(line < 0 || line >= textArea.getLineCount())
+		{
+			if(paintInvalid)
+			{
+				paintHighlight(gfx,line,y);
+				styles[Token.INVALID].setGraphicsFlags(gfx,defaultFont);
+				gfx.drawString("~",0,y + fm.getHeight());
+			}
+		}
+		else if(tokenMarker == null)
+		{
+			paintPlainLine(gfx,line,defaultFont,defaultColor,x,y);
+		}
+		else
+		{
+			paintSyntaxLine(gfx,tokenMarker,line,defaultFont,
+				defaultColor,x,y);
+		}
+	}
+
+	protected void paintPlainLine(Graphics gfx, int line, Font defaultFont,
+		Color defaultColor, int x, int y)
+	{
+		paintHighlight(gfx,line,y);
+		textArea.getLineText(line,currentLine);
+
+		gfx.setFont(defaultFont);
+		gfx.setColor(defaultColor);
+
+		y += fm.getHeight();
+		x = Utilities.drawTabbedText(currentLine,x,y,gfx,this,0);
+
+		if(eolMarkers)
+		{
+			gfx.setColor(eolMarkerColor);
+			gfx.drawString(".",x,y);
+		}
+	}
+
+	protected void paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker,
+		int line, Font defaultFont, Color defaultColor, int x, int y)
+	{
+		textArea.getLineText(currentLineIndex,currentLine);
+		currentLineTokens = tokenMarker.markTokens(currentLine,
+			currentLineIndex);
+
+		paintHighlight(gfx,line,y);
+
+		gfx.setFont(defaultFont);
+		gfx.setColor(defaultColor);
+		y += fm.getHeight();
+		x = SyntaxUtilities.paintSyntaxLine(currentLine,
+			currentLineTokens,styles,this,gfx,x,y);
+
+		if(eolMarkers)
+		{
+			gfx.setColor(eolMarkerColor);
+			gfx.drawString(".",x,y);
+		}
+	}
+
+	protected void paintHighlight(Graphics gfx, int line, int y)
+	{
+		if(line >= textArea.getSelectionStartLine()
+			&& line <= textArea.getSelectionEndLine())
+			paintLineHighlight(gfx,line,y);
+
+		if(highlights != null)
+			highlights.paintHighlight(gfx,line,y);
+
+		if(bracketHighlight && line == textArea.getBracketLine())
+			paintBracketHighlight(gfx,line,y);
+
+		if(line == textArea.getCaretLine())
+			paintCaret(gfx,line,y);
+	}
+
+	protected void paintLineHighlight(Graphics gfx, int line, int y)
+	{
+		int height = fm.getHeight();
+		y += fm.getLeading() + fm.getMaxDescent();
+
+		int selectionStart = textArea.getSelectionStart();
+		int selectionEnd = textArea.getSelectionEnd();
+
+		if(selectionStart == selectionEnd)
+		{
+			if(lineHighlight)
+			{
+				gfx.setColor(lineHighlightColor);
+				gfx.fillRect(0,y,getWidth(),height);
+			}
+		}
+		else
+		{
+			gfx.setColor(selectionColor);
+
+			int selectionStartLine = textArea.getSelectionStartLine();
+			int selectionEndLine = textArea.getSelectionEndLine();
+			int lineStart = textArea.getLineStartOffset(line);
+
+			int x1, x2;
+			if(textArea.isSelectionRectangular())
+			{
+				int lineLen = textArea.getLineLength(line);
+				x1 = textArea._offsetToX(line,Math.min(lineLen,
+					selectionStart - textArea.getLineStartOffset(
+					selectionStartLine)));
+				x2 = textArea._offsetToX(line,Math.min(lineLen,
+					selectionEnd - textArea.getLineStartOffset(
+					selectionEndLine)));
+				if(x1 == x2)
+					x2++;
+			}
+			else if(selectionStartLine == selectionEndLine)
+			{
+				x1 = textArea._offsetToX(line,
+					selectionStart - lineStart);
+				x2 = textArea._offsetToX(line,
+					selectionEnd - lineStart);
+			}
+			else if(line == selectionStartLine)
+			{
+				x1 = textArea._offsetToX(line,
+					selectionStart - lineStart);
+				x2 = getWidth();
+			}
+			else if(line == selectionEndLine)
+			{
+				x1 = 0;
+				x2 = textArea._offsetToX(line,
+					selectionEnd - lineStart);
+			}
+			else
+			{
+				x1 = 0;
+				x2 = getWidth();
+			}
+
+			// "inlined" min/max()
+			gfx.fillRect(x1 > x2 ? x2 : x1,y,x1 > x2 ?
+				(x1 - x2) : (x2 - x1),height);
+		}
+
+	}
+
+	protected void paintBracketHighlight(Graphics gfx, int line, int y)
+	{
+		int position = textArea.getBracketPosition();
+		if(position == -1)
+			return;
+		y += fm.getLeading() + fm.getMaxDescent();
+		int x = textArea._offsetToX(line,position);
+		gfx.setColor(bracketHighlightColor);
+		// Hack!!! Since there is no fast way to get the character
+		// from the bracket matching routine, we use ( since all
+		// brackets probably have the same width anyway
+		gfx.drawRect(x,y,fm.charWidth('(') - 1,
+			fm.getHeight() - 1);
+	}
+
+	protected void paintCaret(Graphics gfx, int line, int y)
+	{
+		if(textArea.isCaretVisible())
+		{
+			int offset = textArea.getCaretPosition() 
+				- textArea.getLineStartOffset(line);
+			int caretX = textArea._offsetToX(line,offset);
+			int caretWidth = ((blockCaret ||
+				textArea.isOverwriteEnabled()) ?
+				fm.charWidth('w') : 1);
+			y += fm.getLeading() + fm.getMaxDescent();
+			int height = fm.getHeight();
+			
+			gfx.setColor(caretColor);
+
+			if(textArea.isOverwriteEnabled())
+			{
+				gfx.fillRect(caretX,y + height - 1,
+					caretWidth,1);
+			}
+			else
+			{
+				gfx.drawRect(caretX,y,caretWidth - 1,height - 1);
+			}
+		}
+	}
+}

Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextUtilities.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextUtilities.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextUtilities.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextUtilities.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,183 @@
+/*
+ * TextUtilities.java - Utility functions used by the text area classes
+ * Copyright (C) 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+package org.gjt.sp.jedit.textarea;
+
+import javax.swing.text.*;
+
+/**
+ * Class with several utility functions used by the text area component.
+ * @author Slava Pestov
+ * @version $Id: TextUtilities.java,v 1.4 1999/12/13 03:40:30 sp Exp $
+ */
+public class TextUtilities
+{
+	/**
+	 * Returns the offset of the bracket matching the one at the
+	 * specified offset of the document, or -1 if the bracket is
+	 * unmatched (or if the character is not a bracket).
+	 * @param doc The document
+	 * @param offset The offset
+	 * @exception BadLocationException If an out-of-bounds access
+	 * was attempted on the document text
+	 */
+	public static int findMatchingBracket(Document doc, int offset)
+		throws BadLocationException
+	{
+		if(doc.getLength() == 0)
+			return -1;
+		char c = doc.getText(offset,1).charAt(0);
+		char cprime; // c` - corresponding character
+		boolean direction; // true = back, false = forward
+
+		switch(c)
+		{
+		case '(': cprime = ')'; direction = false; break;
+		case ')': cprime = '('; direction = true; break;
+		case '[': cprime = ']'; direction = false; break;
+		case ']': cprime = '['; direction = true; break;
+		case '{': cprime = '}'; direction = false; break;
+		case '}': cprime = '{'; direction = true; break;
+		default: return -1;
+		}
+
+		int count;
+
+		// How to merge these two cases is left as an exercise
+		// for the reader.
+
+		// Go back or forward
+		if(direction)
+		{
+			// Count is 1 initially because we have already
+			// `found' one closing bracket
+			count = 1;
+
+			// Get text[0,offset-1];
+			String text = doc.getText(0,offset);
+
+			// Scan backwards
+			for(int i = offset - 1; i >= 0; i--)
+			{
+				// If text[i] == c, we have found another
+				// closing bracket, therefore we will need
+				// two opening brackets to complete the
+				// match.
+				char x = text.charAt(i);
+				if(x == c)
+					count++;
+
+				// If text[i] == cprime, we have found a
+				// opening bracket, so we return i if
+				// --count == 0
+				else if(x == cprime)
+				{
+					if(--count == 0)
+						return i;
+				}
+			}
+		}
+		else
+		{
+			// Count is 1 initially because we have already
+			// `found' one opening bracket
+			count = 1;
+
+			// So we don't have to + 1 in every loop
+			offset++;
+
+			// Number of characters to check
+			int len = doc.getLength() - offset;
+
+			// Get text[offset+1,len];
+			String text = doc.getText(offset,len);
+
+			// Scan forwards
+			for(int i = 0; i < len; i++)
+			{
+				// If text[i] == c, we have found another
+				// opening bracket, therefore we will need
+				// two closing brackets to complete the
+				// match.
+				char x = text.charAt(i);
+
+				if(x == c)
+					count++;
+
+				// If text[i] == cprime, we have found an
+				// closing bracket, so we return i if
+				// --count == 0
+				else if(x == cprime)
+				{
+					if(--count == 0)
+						return i + offset;
+				}
+			}
+		}
+
+		// Nothing found
+		return -1;
+	}
+
+	/**
+	 * Locates the start of the word at the specified position.
+	 * @param line The text
+	 * @param pos The position
+	 */
+	public static int findWordStart(String line, int pos, String noWordSep)
+	{
+		char ch = line.charAt(pos - 1);
+
+		if(noWordSep == null)
+			noWordSep = "";
+		boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
+			&& noWordSep.indexOf(ch) == -1);
+
+		int wordStart = 0;
+		for(int i = pos - 1; i >= 0; i--)
+		{
+			ch = line.charAt(i);
+			if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
+				noWordSep.indexOf(ch) == -1))
+			{
+				wordStart = i + 1;
+				break;
+			}
+		}
+
+		return wordStart;
+	}
+
+	/**
+	 * Locates the end of the word at the specified position.
+	 * @param line The text
+	 * @param pos The position
+	 */
+	public static int findWordEnd(String line, int pos, String noWordSep)
+	{
+		char ch = line.charAt(pos);
+
+		if(noWordSep == null)
+			noWordSep = "";
+		boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
+			&& noWordSep.indexOf(ch) == -1);
+
+		int wordEnd = line.length();
+		for(int i = pos; i < line.length(); i++)
+		{
+			ch = line.charAt(i);
+			if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
+				noWordSep.indexOf(ch) == -1))
+			{
+				wordEnd = i;
+				break;
+			}
+		}
+		return wordEnd;
+	}
+}

Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/Token.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/Token.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/Token.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/Token.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,155 @@
+/*
+ * Token.java - Generic token
+ * Copyright (C) 1998, 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+
+package org.gjt.sp.jedit.textarea;
+
+/**
+ * A linked list of tokens. Each token has three fields - a token
+ * identifier, which is a byte value that can be looked up in the
+ * array returned by <code>SyntaxDocument.getColors()</code>
+ * to get a color value, a length value which is the length of the
+ * token in the text, and a pointer to the next token in the list.
+ *
+ * @author Slava Pestov
+ * @version $Id: Token.java,v 1.12 1999/12/13 03:40:30 sp Exp $
+ */
+public class Token
+{
+	/**
+	 * Normal text token id. This should be used to mark
+	 * normal text.
+	 */
+	public static final byte NULL = 0;
+
+	/**
+	 * Comment 1 token id. This can be used to mark a comment.
+	 */
+	public static final byte COMMENT1 = 1;
+
+	/**
+	 * Comment 2 token id. This can be used to mark a comment.
+	 */
+	public static final byte COMMENT2 = 2;
+
+	
+	/**
+	 * Literal 1 token id. This can be used to mark a string
+	 * literal (eg, C mode uses this to mark "..." literals)
+	 */
+	public static final byte LITERAL1 = 3;
+
+	/**
+	 * Literal 2 token id. This can be used to mark an object
+	 * literal (eg, Java mode uses this to mark true, false, etc)
+	 */
+	public static final byte LITERAL2 = 4;
+
+	/**
+	 * Label token id. This can be used to mark labels
+	 * (eg, C mode uses this to mark ...: sequences)
+	 */
+	public static final byte LABEL = 5;
+
+	/**
+	 * Keyword 1 token id. This can be used to mark a
+	 * keyword. This should be used for general language
+	 * constructs.
+	 */
+	public static final byte KEYWORD1 = 6;
+
+	/**
+	 * Keyword 2 token id. This can be used to mark a
+	 * keyword. This should be used for preprocessor
+	 * commands, or variables.
+	 */
+	public static final byte KEYWORD2 = 7;
+
+	/**
+	 * Keyword 3 token id. This can be used to mark a
+	 * keyword. This should be used for data types.
+	 */
+	public static final byte KEYWORD3 = 8;
+
+	/**
+	 * Keyword 3 token id. This can be used to mark a
+	 * keyword. This should be used for data types.
+	 */
+	public static final byte KEYWORD4 = 9;
+
+	/**
+	 * Operator token id. This can be used to mark an
+	 * operator. (eg, SQL mode marks +, -, etc with this
+	 * token type)
+	 */
+	public static final byte OPERATOR = 10;
+
+	/**
+	 * Invalid token id. This can be used to mark invalid
+	 * or incomplete tokens, so the user can easily spot
+	 * syntax errors.
+	 */
+	public static final byte INVALID = 11;
+
+	/**
+	 * The total number of defined token ids.
+	 */
+	public static final byte ID_COUNT = 12;
+
+	/**
+	 * The first id that can be used for internal state
+	 * in a token marker.
+	 */
+	public static final byte INTERNAL_FIRST = 100;
+
+	/**
+	 * The last id that can be used for internal state
+	 * in a token marker.
+	 */
+	public static final byte INTERNAL_LAST = 126;
+
+	/**
+	 * The token type, that along with a length of 0
+	 * marks the end of the token list.
+	 */
+	public static final byte END = 127;
+
+	/**
+	 * The length of this token.
+	 */
+	public int length;
+
+	/**
+	 * The id of this token.
+	 */
+	public byte id;
+
+	/**
+	 * The next token in the linked list.
+	 */
+	public Token next;
+
+	/**
+	 * Creates a new token.
+	 * @param length The length of the token
+	 * @param id The id of the token
+	 */
+	public Token(int length, byte id)
+	{
+		this.length = length;
+		this.id = id;
+	}
+
+	/**
+	 * Returns a string representation of this token.
+	 */
+	public String toString()
+	{
+		return "[id=" + id + ",length=" + length + "]";
+	}
+}

Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TokenMarker.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TokenMarker.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TokenMarker.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TokenMarker.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,344 @@
+/*
+ * TokenMarker.java - Generic token marker
+ * Copyright (C) 1998, 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+package org.gjt.sp.jedit.textarea;
+
+import javax.swing.text.Segment;
+import java.util.*;
+
+/**
+ * A token marker that splits lines of text into tokens. Each token carries
+ * a length field and an indentification tag that can be mapped to a color
+ * for painting that token.<p>
+ *
+ * For performance reasons, the linked list of tokens is reused after each
+ * line is tokenized. Therefore, the return value of <code>markTokens</code>
+ * should only be used for immediate painting. Notably, it cannot be
+ * cached.
+ *
+ * @author Slava Pestov
+ * @version $Id: TokenMarker.java,v 1.32 1999/12/13 03:40:30 sp Exp $
+ *
+ * @see org.gjt.sp.jedit.syntax.Token
+ */
+public abstract class TokenMarker
+{
+	/**
+	 * A wrapper for the lower-level <code>markTokensImpl</code> method
+	 * that is called to split a line up into tokens.
+	 * @param line The line
+	 * @param lineIndex The line number
+	 */
+	public Token markTokens(Segment line, int lineIndex)
+	{
+		if(lineIndex >= length)
+		{
+			throw new IllegalArgumentException("Tokenizing invalid line: "
+				+ lineIndex);
+		}
+
+		lastToken = null;
+
+		LineInfo info = lineInfo[lineIndex];
+		LineInfo prev;
+		if(lineIndex == 0)
+			prev = null;
+		else
+			prev = lineInfo[lineIndex - 1];
+
+		byte oldToken = info.token;
+		byte token = markTokensImpl(prev == null ?
+			Token.NULL : prev.token,line,lineIndex);
+
+		info.token = token;
+
+		/*
+		 * This is a foul hack. It stops nextLineRequested
+		 * from being cleared if the same line is marked twice.
+		 *
+		 * Why is this necessary? It's all JEditTextArea's fault.
+		 * When something is inserted into the text, firing a
+		 * document event, the insertUpdate() method shifts the
+		 * caret (if necessary) by the amount inserted.
+		 *
+		 * All caret movement is handled by the select() method,
+		 * which eventually pipes the new position to scrollTo()
+		 * and calls repaint().
+		 *
+		 * Note that at this point in time, the new line hasn't
+		 * yet been painted; the caret is moved first.
+		 *
+		 * scrollTo() calls offsetToX(), which tokenizes the line
+		 * unless it is being called on the last line painted
+		 * (in which case it uses the text area's painter cached
+		 * token list). What scrollTo() does next is irrelevant.
+		 *
+		 * After scrollTo() has done it's job, repaint() is
+		 * called, and eventually we end up in paintLine(), whose
+		 * job is to paint the changed line. It, too, calls
+		 * markTokens().
+		 *
+		 * The problem was that if the line started a multiline
+		 * token, the first markTokens() (done in offsetToX())
+		 * would set nextLineRequested (because the line end
+		 * token had changed) but the second would clear it
+		 * (because the line was the same that time) and therefore
+		 * paintLine() would never know that it needed to repaint
+		 * subsequent lines.
+		 *
+		 * This bug took me ages to track down, that's why I wrote
+		 * all the relevant info down so that others wouldn't
+		 * duplicate it.
+		 */
+		 if(!(lastLine == lineIndex && nextLineRequested))
+			nextLineRequested = (oldToken != token);
+
+		lastLine = lineIndex;
+
+		addToken(0,Token.END);
+
+		return firstToken;
+	}
+
+	/**
+	 * An abstract method that splits a line up into tokens. It
+	 * should parse the line, and call <code>addToken()</code> to
+	 * add syntax tokens to the token list. Then, it should return
+	 * the initial token type for the next line.<p>
+	 *
+	 * For example if the current line contains the start of a 
+	 * multiline comment that doesn't end on that line, this method
+	 * should return the comment token type so that it continues on
+	 * the next line.
+	 *
+	 * @param token The initial token type for this line
+	 * @param line The line to be tokenized
+	 * @param lineIndex The index of the line in the document,
+	 * starting at 0
+	 * @return The initial token type for the next line
+	 */
+	protected abstract byte markTokensImpl(byte token, Segment line,
+		int lineIndex);
+
+	/**
+	 * Returns if the token marker supports tokens that span multiple
+	 * lines. If this is true, the object using this token marker is
+	 * required to pass all lines in the document to the
+	 * <code>markTokens()</code> method (in turn).<p>
+	 *
+	 * The default implementation returns true; it should be overridden
+	 * to return false on simpler token markers for increased speed.
+	 */
+	public boolean supportsMultilineTokens()
+	{
+		return true;
+	}
+
+	/**
+	 * Informs the token marker that lines have been inserted into
+	 * the document. This inserts a gap in the <code>lineInfo</code>
+	 * array.
+	 * @param index The first line number
+	 * @param lines The number of lines 
+	 */
+	public void insertLines(int index, int lines)
+	{
+		if(lines <= 0)
+			return;
+		length += lines;
+		ensureCapacity(length);
+		int len = index + lines;
+		System.arraycopy(lineInfo,index,lineInfo,len,
+			lineInfo.length - len);
+
+		for(int i = index + lines - 1; i >= index; i--)
+		{
+			lineInfo[i] = new LineInfo();
+		}
+	}
+	
+	/**
+	 * Informs the token marker that line have been deleted from
+	 * the document. This removes the lines in question from the
+	 * <code>lineInfo</code> array.
+	 * @param index The first line number
+	 * @param lines The number of lines
+	 */
+	public void deleteLines(int index, int lines)
+	{
+		if (lines <= 0)
+			return;
+		int len = index + lines;
+		length -= lines;
+		System.arraycopy(lineInfo,len,lineInfo,
+			index,lineInfo.length - len);
+	}
+
+	/**
+	 * Returns the number of lines in this token marker.
+	 */
+	public int getLineCount()
+	{
+		return length;
+	}
+
+	/**
+	 * Returns true if the next line should be repainted. This
+	 * will return true after a line has been tokenized that starts
+	 * a multiline token that continues onto the next line.
+	 */
+	public boolean isNextLineRequested()
+	{
+		return nextLineRequested;
+	}
+
+	// protected members
+
+	/**
+	 * The first token in the list. This should be used as the return
+	 * value from <code>markTokens()</code>.
+	 */
+	protected Token firstToken;
+
+	/**
+	 * The last token in the list. New tokens are added here.
+	 * This should be set to null before a new line is to be tokenized.
+	 */
+	protected Token lastToken;
+
+	/**
+	 * An array for storing information about lines. It is enlarged and
+	 * shrunk automatically by the <code>insertLines()</code> and
+	 * <code>deleteLines()</code> methods.
+	 */
+	protected LineInfo[] lineInfo;
+
+	/**
+	 * The number of lines in the model being tokenized. This can be
+	 * less than the length of the <code>lineInfo</code> array.
+	 */
+	protected int length;
+
+	/**
+	 * The last tokenized line.
+	 */
+	protected int lastLine;
+
+	/**
+	 * True if the next line should be painted.
+	 */
+	protected boolean nextLineRequested;
+
+	/**
+	 * Creates a new <code>TokenMarker</code>. This DOES NOT create
+	 * a lineInfo array; an initial call to <code>insertLines()</code>
+	 * does that.
+	 */
+	protected TokenMarker()
+	{
+		lastLine = -1;
+	}
+
+	/**
+	 * Ensures that the <code>lineInfo</code> array can contain the
+	 * specified index. This enlarges it if necessary. No action is
+	 * taken if the array is large enough already.<p>
+	 *
+	 * It should be unnecessary to call this under normal
+	 * circumstances; <code>insertLine()</code> should take care of
+	 * enlarging the line info array automatically.
+	 *
+	 * @param index The array index
+	 */
+	protected void ensureCapacity(int index)
+	{
+		if(lineInfo == null)
+			lineInfo = new LineInfo[index + 1];
+		else if(lineInfo.length <= index)
+		{
+			LineInfo[] lineInfoN = new LineInfo[(index + 1) * 2];
+			System.arraycopy(lineInfo,0,lineInfoN,0,
+					 lineInfo.length);
+			lineInfo = lineInfoN;
+		}
+	}
+
+	/**
+	 * Adds a token to the token list.
+	 * @param length The length of the token
+	 * @param id The id of the token
+	 */
+	protected void addToken(int length, byte id)
+	{
+		if(id >= Token.INTERNAL_FIRST && id <= Token.INTERNAL_LAST)
+			throw new InternalError("Invalid id: " + id);
+
+		if(length == 0 && id != Token.END)
+			return;
+
+		if(firstToken == null)
+		{
+			firstToken = new Token(length,id);
+			lastToken = firstToken;
+		}
+		else if(lastToken == null)
+		{
+			lastToken = firstToken;
+			firstToken.length = length;
+			firstToken.id = id;
+		}
+		else if(lastToken.next == null)
+		{
+			lastToken.next = new Token(length,id);
+			lastToken = lastToken.next;
+		}
+		else
+		{
+			lastToken = lastToken.next;
+			lastToken.length = length;
+			lastToken.id = id;
+		}
+	}
+
+	/**
+	 * Inner class for storing information about tokenized lines.
+	 */
+	public class LineInfo
+	{
+		/**
+		 * Creates a new LineInfo object with token = Token.NULL
+		 * and obj = null.
+		 */
+		public LineInfo()
+		{
+		}
+
+		/**
+		 * Creates a new LineInfo object with the specified
+		 * parameters.
+		 */
+		public LineInfo(byte token, Object obj)
+		{
+			this.token = token;
+			this.obj = obj;
+		}
+
+		/**
+		 * The id of the last token of the line.
+		 */
+		public byte token;
+
+		/**
+		 * This is for use by the token marker implementations
+		 * themselves. It can be used to store anything that
+		 * is an object and that needs to exist on a per-line
+		 * basis.
+		 */
+		public Object obj;
+	}
+}

Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/XMLTokenMarker.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/XMLTokenMarker.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/XMLTokenMarker.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/XMLTokenMarker.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,190 @@
+/*
+ * XMLTokenMarker.java - XML token marker
+ * Copyright (C) 1998, 1999 Slava Pestov
+ * Copyright (C) 2001 Tom Bradford
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+package org.gjt.sp.jedit.textarea;
+
+import javax.swing.text.Segment;
+
+/**
+ * XML Token Marker Rewrite
+ *
+ * @author Tom Bradford
+ * @version $Id: XMLTokenMarker.java,v 1.5 2001/07/29 20:45:43 tom Exp $
+ */
+public class XMLTokenMarker extends TokenMarker {
+   public XMLTokenMarker() {
+   }
+   
+   public byte markTokensImpl(byte token, Segment line, int lineIndex) {
+      char[] array = line.array;
+      int offset = line.offset;
+      int lastOffset = offset;
+      int length = line.count + offset;
+      
+      // Ugly hack to handle multi-line tags
+      boolean sk1 = token == Token.KEYWORD1;
+      
+      for ( int i = offset; i < length; i++ ) {
+         int ip1 = i+1;
+         char c = array[i];
+         switch ( token ) {
+            case Token.NULL: // text
+               switch ( c ) {
+                  case '<':
+                     addToken(i-lastOffset, token);
+                     lastOffset = i;
+                     if ( SyntaxUtilities.regionMatches(false, line, ip1, "!--") ) {
+                        i += 3;
+                        token = Token.COMMENT1;
+                     }
+                     else if ( array[ip1] == '!' ) {
+                        i += 1;
+                        token = Token.COMMENT2;
+                     }
+                     else if ( array[ip1] == '?' ) {
+                        i += 1;
+                        token = Token.KEYWORD3;
+                     }
+                     else
+                        token = Token.KEYWORD1;
+                     break;
+                     
+                  case '&':
+                     addToken(i - lastOffset, token);
+                     lastOffset = i;
+                     token = Token.LABEL;
+                     break;
+               }
+               break;
+               
+            case Token.KEYWORD1: // tag
+               switch ( c ) {
+                  case '>':
+                     addToken(ip1-lastOffset, token);
+                     lastOffset = ip1;
+                     token = Token.NULL;
+                     sk1 = false;
+                     break;
+                     
+                  case ' ':
+                  case '\t':
+                     addToken(i-lastOffset, token);
+                     lastOffset = i;
+                     token = Token.KEYWORD2;
+                     sk1 = false;
+                     break;
+                     
+                  default:
+                     if ( sk1 ) {
+                        token = Token.KEYWORD2;
+                        sk1 = false;
+                     }
+                     break;
+               }
+               break;
+
+            case Token.KEYWORD2: // attribute
+               switch ( c ) {
+                   case '>':
+                     addToken(ip1-lastOffset, token);
+                     lastOffset = ip1;
+                     token = Token.NULL;
+                     break;
+                    
+                  case '/':
+                     addToken(i-lastOffset, token);
+                     lastOffset = i;
+                     token = Token.KEYWORD1;
+                     break;
+                     
+                  case '=':
+                     addToken(i-lastOffset, token);
+                     lastOffset = i;
+                     token = Token.OPERATOR;
+               }
+               break;
+               
+            case Token.OPERATOR: // equal for attribute
+               switch ( c ) {
+                  case '\"':
+                  case '\'':
+                     addToken(i-lastOffset, token);
+                     lastOffset = i;
+                     if ( c == '\"' )
+                        token = Token.LITERAL1;
+                     else
+                        token = Token.LITERAL2;
+                     break;
+               }
+               break;
+               
+            case Token.LITERAL1:
+            case Token.LITERAL2: // strings
+               if ( ( token == Token.LITERAL1 && c == '\"' )
+                 || ( token == Token.LITERAL2 && c == '\'' ) ) {
+                  addToken(ip1-lastOffset, token);
+                  lastOffset = ip1;
+                  token = Token.KEYWORD1;
+               }
+               break;
+            
+            case Token.LABEL: // entity
+               if ( c == ';' ) {
+                  addToken(ip1-lastOffset, token);
+                  lastOffset = ip1;
+                  token = Token.NULL;
+                  break;
+               }
+               break;
+               
+            case Token.COMMENT1: // Inside a comment
+               if ( SyntaxUtilities.regionMatches(false, line, i, "-->") ) {
+                  addToken((i+3)-lastOffset, token);
+                  lastOffset = i+3;
+                  token = Token.NULL;
+               }
+               break;
+
+            case Token.COMMENT2: // Inside a declaration
+               if ( SyntaxUtilities.regionMatches(false, line, i, ">") ) {
+                  addToken(ip1-lastOffset, token);
+                  lastOffset = ip1;
+                  token = Token.NULL;
+               }
+               break;
+
+            case Token.KEYWORD3: // Inside a processor instruction
+               if ( SyntaxUtilities.regionMatches(false, line, i, "?>") ) {
+                  addToken((i+2)-lastOffset, token);
+                  lastOffset = i+2;
+                  token = Token.NULL;
+               }
+               break;
+               
+            default:
+               throw new InternalError("Invalid state: " + token);
+         }
+      }
+      
+      switch ( token ) {
+         case Token.LABEL:
+            addToken(length-lastOffset, Token.INVALID);
+            token = Token.NULL;
+            break;
+            
+         default:
+            addToken(length-lastOffset, token);
+            break;
+      }
+      
+      return token;
+   }
+}
+
+