1. /*
  2. * @(#)GlyphPainter1.java 1.13 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.text;
  8. import java.awt.*;
  9. /**
  10. * A class to perform rendering of the glyphs.
  11. * This can be implemented to be stateless, or
  12. * to hold some information as a cache to
  13. * facilitate faster rendering and model/view
  14. * translation. At a minimum, the GlyphPainter
  15. * allows a View implementation to perform its
  16. * duties independent of a particular version
  17. * of JVM and selection of capabilities (i.e.
  18. * shaping for i18n, etc).
  19. * <p>
  20. * This implementation is intended for operation
  21. * under the JDK1.1 API of the Java Platform.
  22. * Since the Java 2 SDK is backward compatible with
  23. * JDK1.1 API, this class will also function on
  24. * Java 2. The Java 2 SDK introduces improved
  25. * API for rendering text however, so the GlyphPainter2
  26. * is recommended for the Java 2 SDK.
  27. *
  28. * @author Timothy Prinzing
  29. * @version 1.13 01/23/03
  30. * @see GlyphView
  31. */
  32. class GlyphPainter1 extends GlyphView.GlyphPainter {
  33. /**
  34. * Determine the span the glyphs given a start location
  35. * (for tab expansion).
  36. */
  37. public float getSpan(GlyphView v, int p0, int p1,
  38. TabExpander e, float x) {
  39. sync(v);
  40. Segment text = v.getText(p0, p1);
  41. int width = Utilities.getTabbedTextWidth(text, metrics, (int) x, e, p0);
  42. SegmentCache.releaseSharedSegment(text);
  43. return width;
  44. }
  45. public float getHeight(GlyphView v) {
  46. sync(v);
  47. return metrics.getHeight();
  48. }
  49. /**
  50. * Fetches the ascent above the baseline for the glyphs
  51. * corresponding to the given range in the model.
  52. */
  53. public float getAscent(GlyphView v) {
  54. sync(v);
  55. return metrics.getAscent();
  56. }
  57. /**
  58. * Fetches the descent below the baseline for the glyphs
  59. * corresponding to the given range in the model.
  60. */
  61. public float getDescent(GlyphView v) {
  62. sync(v);
  63. return metrics.getDescent();
  64. }
  65. /**
  66. * Paints the glyphs representing the given range.
  67. */
  68. public void paint(GlyphView v, Graphics g, Shape a, int p0, int p1) {
  69. sync(v);
  70. Segment text;
  71. TabExpander expander = v.getTabExpander();
  72. Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : a.getBounds();
  73. // determine the x coordinate to render the glyphs
  74. int x = alloc.x;
  75. int p = v.getStartOffset();
  76. if (p != p0) {
  77. text = v.getText(p, p0);
  78. int width = Utilities.getTabbedTextWidth(text, metrics, x, expander, p);
  79. x += width;
  80. SegmentCache.releaseSharedSegment(text);
  81. }
  82. // determine the y coordinate to render the glyphs
  83. int y = alloc.y + metrics.getHeight() - metrics.getDescent();
  84. // render the glyphs
  85. text = v.getText(p0, p1);
  86. g.setFont(metrics.getFont());
  87. Utilities.drawTabbedText(text, x, y, g, expander, p0);
  88. SegmentCache.releaseSharedSegment(text);
  89. }
  90. public Shape modelToView(GlyphView v, int pos, Position.Bias bias,
  91. Shape a) throws BadLocationException {
  92. sync(v);
  93. Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : a.getBounds();
  94. int p0 = v.getStartOffset();
  95. int p1 = v.getEndOffset();
  96. TabExpander expander = v.getTabExpander();
  97. Segment text;
  98. if(pos == p1) {
  99. // The caller of this is left to right and borders a right to
  100. // left view, return our end location.
  101. return new Rectangle(alloc.x + alloc.width, alloc.y, 0,
  102. metrics.getHeight());
  103. }
  104. if ((pos >= p0) && (pos <= p1)) {
  105. // determine range to the left of the position
  106. text = v.getText(p0, pos);
  107. int width = Utilities.getTabbedTextWidth(text, metrics, alloc.x, expander, p0);
  108. SegmentCache.releaseSharedSegment(text);
  109. return new Rectangle(alloc.x + width, alloc.y, 0, metrics.getHeight());
  110. }
  111. throw new BadLocationException("modelToView - can't convert", p1);
  112. }
  113. /**
  114. * Provides a mapping from the view coordinate space to the logical
  115. * coordinate space of the model.
  116. *
  117. * @param v the view containing the view coordinates
  118. * @param x the X coordinate
  119. * @param y the Y coordinate
  120. * @param a the allocated region to render into
  121. * @param biasReturn always returns <code>Position.Bias.Forward</code>
  122. * as the zero-th element of this array
  123. * @return the location within the model that best represents the
  124. * given point in the view
  125. * @see View#viewToModel
  126. */
  127. public int viewToModel(GlyphView v, float x, float y, Shape a,
  128. Position.Bias[] biasReturn) {
  129. sync(v);
  130. Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : a.getBounds();
  131. int p0 = v.getStartOffset();
  132. int p1 = v.getEndOffset();
  133. TabExpander expander = v.getTabExpander();
  134. Segment text = v.getText(p0, p1);
  135. int offs = Utilities.getTabbedTextOffset(text, metrics,
  136. alloc.x, (int) x, expander, p0);
  137. SegmentCache.releaseSharedSegment(text);
  138. int retValue = p0 + offs;
  139. if(retValue == p1) {
  140. // No need to return backward bias as GlyphPainter1 is used for
  141. // ltr text only.
  142. retValue--;
  143. }
  144. biasReturn[0] = Position.Bias.Forward;
  145. return retValue;
  146. }
  147. /**
  148. * Determines the best location (in the model) to break
  149. * the given view.
  150. * This method attempts to break on a whitespace
  151. * location. If a whitespace location can't be found, the
  152. * nearest character location is returned.
  153. *
  154. * @param v the view
  155. * @param p0 the location in the model where the
  156. * fragment should start its representation >= 0
  157. * @param pos the graphic location along the axis that the
  158. * broken view would occupy >= 0; this may be useful for
  159. * things like tab calculations
  160. * @param len specifies the distance into the view
  161. * where a potential break is desired >= 0
  162. * @return the model location desired for a break
  163. * @see View#breakView
  164. */
  165. public int getBoundedPosition(GlyphView v, int p0, float x, float len) {
  166. sync(v);
  167. TabExpander expander = v.getTabExpander();
  168. Segment s = v.getText(p0, v.getEndOffset());
  169. int index = Utilities.getTabbedTextOffset(s, metrics, (int)x, (int)(x+len),
  170. expander, p0, false);
  171. SegmentCache.releaseSharedSegment(s);
  172. int p1 = p0 + index;
  173. return p1;
  174. }
  175. void sync(GlyphView v) {
  176. Font f = v.getFont();
  177. if ((metrics == null) || (! f.equals(metrics.getFont()))) {
  178. // fetch a new FontMetrics
  179. Toolkit kit;
  180. Component c = v.getContainer();
  181. if (c != null) {
  182. kit = c.getToolkit();
  183. } else {
  184. kit = Toolkit.getDefaultToolkit();
  185. }
  186. metrics = kit.getFontMetrics(f);
  187. }
  188. }
  189. // --- variables ---------------------------------------------
  190. FontMetrics metrics;
  191. }