/jEdit/tags/jedit-3-2-2/org/gjt/sp/jedit/textarea/TextRenderer.java

# · Java · 253 lines · 184 code · 45 blank · 24 comment · 27 complexity · 0facfcd5bf8314c6cac2b0056532a2cf MD5 · raw file

  1. /*
  2. * TextRenderer.java - Abstract differences between AWT and Java 2D
  3. * Copyright (C) 2001 Slava Pestov
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License
  7. * as published by the Free Software Foundation; either version 2
  8. * of the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. */
  19. package org.gjt.sp.jedit.textarea;
  20. import javax.swing.text.TabExpander;
  21. import java.awt.*;
  22. import org.gjt.sp.util.Log;
  23. /**
  24. * Java 1.1 and Java 2 have different APIs for drawing and measuring text.
  25. * Using the Java 1.1 API in Java 2 can result in incorrect caret placement,
  26. * etc. So we abstract away the differences with this class.
  27. */
  28. public abstract class TextRenderer
  29. {
  30. static final String JAVA2D_RENDER_CLASS = "org.gjt.sp.jedit.textarea.TextRenderer2D";
  31. public static TextRenderer createTextRenderer()
  32. {
  33. if(java2d)
  34. {
  35. try
  36. {
  37. ClassLoader loader = TextRenderer.class
  38. .getClassLoader();
  39. Class clazz;
  40. if(loader == null)
  41. clazz = Class.forName(JAVA2D_RENDER_CLASS);
  42. else
  43. clazz = loader.loadClass(JAVA2D_RENDER_CLASS);
  44. return (TextRenderer)clazz.newInstance();
  45. }
  46. catch(Exception e)
  47. {
  48. throw new NoClassDefFoundError(JAVA2D_RENDER_CLASS);
  49. }
  50. }
  51. else
  52. return new TextRendererAWT();
  53. }
  54. public static TextRenderer createPrintTextRenderer()
  55. {
  56. return new TextRendererAWT();
  57. }
  58. public void setupGraphics(Graphics g) {}
  59. public void configure(boolean antiAlias, boolean fracFontMetrics) {}
  60. public float drawChars(char[] text, int off, int len, Graphics g,
  61. float x, float y, TabExpander e, Color foreground,
  62. Color tokenBackground, Color componentBackground)
  63. {
  64. // this probably should be moved elsewhere
  65. if(tokenBackground != null)
  66. {
  67. float width = charsWidth(text,off,len,g.getFont(),x,e);
  68. FontMetrics fm = g.getFontMetrics();
  69. float height = fm.getHeight();
  70. float descent = fm.getDescent();
  71. float leading = fm.getLeading();
  72. g.setXORMode(componentBackground);
  73. g.setColor(tokenBackground);
  74. g.fillRect((int)x,(int)(y - height + descent + leading),
  75. (int)width,(int)height);
  76. g.setPaintMode();
  77. }
  78. g.setColor(foreground);
  79. int flushLen = 0;
  80. int flushIndex = off;
  81. int end = off + len;
  82. for(int i = off; i < end; i++)
  83. {
  84. if(text[i] == '\t')
  85. {
  86. if(flushLen > 0)
  87. {
  88. x += _drawChars(text,flushIndex,
  89. flushLen,g,x,y);
  90. flushLen = 0;
  91. }
  92. flushIndex = i + 1;
  93. x = e.nextTabStop(x,i - off);
  94. }
  95. else
  96. flushLen++;
  97. }
  98. if(flushLen > 0)
  99. x += _drawChars(text,flushIndex,flushLen,g,x,y);
  100. return x;
  101. }
  102. public float charsWidth(char[] text, int off, int len, Font font, float x,
  103. TabExpander e)
  104. {
  105. float newX = x;
  106. int flushLen = 0;
  107. int flushIndex = off;
  108. int end = off + len;
  109. for(int i = off; i < end; i++)
  110. {
  111. if(text[i] == '\t')
  112. {
  113. if(flushLen > 0)
  114. {
  115. newX += _getWidth(text,flushIndex,flushLen,font);
  116. flushLen = 0;
  117. }
  118. flushIndex = i + 1;
  119. newX = e.nextTabStop(newX,i - off);
  120. }
  121. else
  122. flushLen++;
  123. }
  124. if(flushLen > 0)
  125. newX += _getWidth(text,flushIndex,flushLen,font);
  126. return newX - x;
  127. }
  128. public int xToOffset(char[] text, int off, int len, Font font, float x,
  129. TabExpander e, boolean round, float[] widthArray)
  130. {
  131. int flushLen = 0;
  132. int flushIndex = off;
  133. int end = off + len;
  134. float width = widthArray[0];
  135. for(int i = off; i < end; i++)
  136. {
  137. if(text[i] == '\t')
  138. {
  139. if(flushLen > 0)
  140. {
  141. float newWidth = _getWidth(text,flushIndex,
  142. flushLen,font);
  143. if(x <= width + newWidth)
  144. {
  145. return _xToOffset(text,flushIndex,
  146. flushLen,font,x - width,
  147. round) + flushIndex;
  148. }
  149. else
  150. width += newWidth;
  151. flushLen = 0;
  152. }
  153. flushIndex = i + 1;
  154. float newWidth = e.nextTabStop(width,i - off) - width;
  155. if(x <= width + newWidth)
  156. {
  157. if(round && (x - width) < (width + newWidth - x))
  158. return i;
  159. else
  160. return i + 1;
  161. }
  162. else
  163. width += newWidth;
  164. }
  165. else
  166. flushLen++;
  167. }
  168. if(flushLen > 0)
  169. {
  170. float newWidth = _getWidth(text,flushIndex,flushLen,font);
  171. if(x <= width + newWidth)
  172. {
  173. return _xToOffset(text,flushIndex,flushLen,font,
  174. x - width,round) + flushIndex;
  175. }
  176. else
  177. width += newWidth;
  178. }
  179. widthArray[0] = width;
  180. return -1;
  181. }
  182. abstract float _drawChars(char[] text, int start, int len, Graphics g,
  183. float x, float y);
  184. abstract float _getWidth(char[] text, int start, int len, Font font);
  185. abstract int _xToOffset(char[] text, int start, int len, Font font,
  186. float x, boolean round);
  187. static boolean java2d;
  188. static
  189. {
  190. try
  191. {
  192. ClassLoader loader = TextRenderer.class.getClassLoader();
  193. if(loader == null)
  194. Class.forName("java.awt.Graphics2D");
  195. else
  196. loader.loadClass("java.awt.Graphics2D");
  197. Log.log(Log.DEBUG,TextRenderer.class,
  198. "Java2D detected; will use new text rendering code");
  199. java2d = true;
  200. }
  201. catch(ClassNotFoundException cnf)
  202. {
  203. Log.log(Log.DEBUG,TextRenderer.class,
  204. "Java2D not detected; will use old text rendering code");
  205. java2d = false;
  206. }
  207. }
  208. }