📄 textlayout.java
字号:
public float getDescent() { if (optInfo != null) { return optInfo.getLineMetrics().getDescent(); } ensureCache(); return lineMetrics.descent; } /** * Returns the leading of the <code>TextLayout</code>. * The leading is the suggested interline spacing for this * <code>TextLayout</code>. * <p> * The leading is computed from the leading, descent, and baseline * of all glyphvectors in the <code>TextLayout</code>. The algorithm * is roughly as follows: * <blockquote><pre> * maxD = 0; * maxDL = 0; * for (GlyphVector g in all glyphvectors) { * maxD = max(maxD, g.getDescent() + offsets[g.getBaseline()]); * maxDL = max(maxDL, g.getDescent() + g.getLeading() + * offsets[g.getBaseline()]); * } * return maxDL - maxD; * </pre></blockquote> * @return the leading of this <code>TextLayout</code>. */ public float getLeading() { if (optInfo != null) { return optInfo.getLineMetrics().getLeading(); } ensureCache(); return lineMetrics.leading; } /** * Returns the bounds of this <code>TextLayout</code>. * The bounds contains all of the pixels the <code>TextLayout</code> * can draw. It might not coincide exactly with the ascent, descent, * origin or advance of the <code>TextLayout</code>. * @return a {@link Rectangle2D} that is the bounds of this * <code>TextLayout</code>. */ public Rectangle2D getBounds() { if (optInfo != null) { return optInfo.getVisualBounds(); } ensureCache(); if (boundsRect == null) { Rectangle2D lineBounds = textLine.getBounds(); if (dx != 0 || dy != 0) { lineBounds.setRect(lineBounds.getX() - dx, lineBounds.getY() - dy, lineBounds.getWidth(), lineBounds.getHeight()); } boundsRect = lineBounds; } Rectangle2D bounds = new Rectangle2D.Float(); bounds.setRect(boundsRect); return bounds; } /** * Returns <code>true</code> if this <code>TextLayout</code> has * a left-to-right base direction or <code>false</code> if it has * a right-to-left base direction. The <code>TextLayout</code> * has a base direction of either left-to-right (LTR) or * right-to-left (RTL). The base direction is independent of the * actual direction of text on the line, which may be either LTR, * RTL, or mixed. Left-to-right layouts by default should position * flush left. If the layout is on a tabbed line, the * tabs run left to right, so that logically successive layouts position * left to right. The opposite is true for RTL layouts. By default they * should position flush left, and tabs run right-to-left. * @return <code>true</code> if the base direction of this * <code>TextLayout</code> is left-to-right; <code>false</code> * otherwise. */ public boolean isLeftToRight() { return (optInfo != null) || textLine.isDirectionLTR(); } /** * Returns <code>true</code> if this <code>TextLayout</code> is vertical. * @return <code>true</code> if this <code>TextLayout</code> is vertical; * <code>false</code> otherwise. */ public boolean isVertical() { return isVerticalLine; } /** * Returns the number of characters represented by this * <code>TextLayout</code>. * @return the number of characters in this <code>TextLayout</code>. */ public int getCharacterCount() { return characterCount; } /* * carets and hit testing * * Positions on a text line are represented by instances of TextHitInfo. * Any TextHitInfo with characterOffset between 0 and characterCount-1, * inclusive, represents a valid position on the line. Additionally, * [-1, trailing] and [characterCount, leading] are valid positions, and * represent positions at the logical start and end of the line, * respectively. * * The characterOffsets in TextHitInfo's used and returned by TextLayout * are relative to the beginning of the text layout, not necessarily to * the beginning of the text storage the client is using. * * * Every valid TextHitInfo has either one or two carets associated with it. * A caret is a visual location in the TextLayout indicating where text at * the TextHitInfo will be displayed on screen. If a TextHitInfo * represents a location on a directional boundary, then there are two * possible visible positions for newly inserted text. Consider the * following example, in which capital letters indicate right-to-left text, * and the overall line direction is left-to-right: * * Text Storage: [ a, b, C, D, E, f ] * Display: a b E D C f * * The text hit info (1, t) represents the trailing side of 'b'. If 'q', * a left-to-right character is inserted into the text storage at this * location, it will be displayed between the 'b' and the 'E': * * Text Storage: [ a, b, q, C, D, E, f ] * Display: a b q E D C f * * However, if a 'W', which is right-to-left, is inserted into the storage * after 'b', the storage and display will be: * * Text Storage: [ a, b, W, C, D, E, f ] * Display: a b E D C W f * * So, for the original text storage, two carets should be displayed for * location (1, t): one visually between 'b' and 'E' and one visually * between 'C' and 'f'. * * * When two carets are displayed for a TextHitInfo, one caret is the * 'strong' caret and the other is the 'weak' caret. The strong caret * indicates where an inserted character will be displayed when that * character's direction is the same as the direction of the TextLayout. * The weak caret shows where an character inserted character will be * displayed when the character's direction is opposite that of the * TextLayout. * * * Clients should not be overly concerned with the details of correct * caret display. TextLayout.getCaretShapes(TextHitInfo) will return an * array of two paths representing where carets should be displayed. * The first path in the array is the strong caret; the second element, * if non-null, is the weak caret. If the second element is null, * then there is no weak caret for the given TextHitInfo. * * * Since text can be visually reordered, logically consecutive * TextHitInfo's may not be visually consecutive. One implication of this * is that a client cannot tell from inspecting a TextHitInfo whether the * hit represents the first (or last) caret in the layout. Clients * can call getVisualOtherHit(); if the visual companion is * (-1, TRAILING) or (characterCount, LEADING), then the hit is at the * first (last) caret position in the layout. */ private float[] getCaretInfo(int caret, Rectangle2D bounds, float[] info) { float top1X, top2X; float bottom1X, bottom2X; if (caret == 0 || caret == characterCount) { float pos; int logIndex; if (caret == characterCount) { logIndex = textLine.visualToLogical(characterCount-1); pos = textLine.getCharLinePosition(logIndex) + textLine.getCharAdvance(logIndex); } else { logIndex = textLine.visualToLogical(caret); pos = textLine.getCharLinePosition(logIndex); } float angle = textLine.getCharAngle(logIndex); top1X = top2X = pos + angle*textLine.getCharAscent(logIndex); bottom1X = bottom2X = pos - angle*textLine.getCharDescent(logIndex); } else { { int logIndex = textLine.visualToLogical(caret-1); float angle1 = textLine.getCharAngle(logIndex); float pos1 = textLine.getCharLinePosition(logIndex) + textLine.getCharAdvance(logIndex); if (angle1 != 0) { top1X = pos1 + angle1*textLine.getCharAscent(logIndex); bottom1X = pos1 - angle1*textLine.getCharDescent(logIndex); } else { top1X = bottom1X = pos1; } } { int logIndex = textLine.visualToLogical(caret); float angle2 = textLine.getCharAngle(logIndex); float pos2 = textLine.getCharLinePosition(logIndex); if (angle2 != 0) { top2X = pos2 + angle2*textLine.getCharAscent(logIndex); bottom2X = pos2 - angle2*textLine.getCharDescent(logIndex); } else { top2X = bottom2X = pos2; } } } float topX = (top1X + top2X) / 2; float bottomX = (bottom1X + bottom2X) / 2; if (info == null) { info = new float[2]; } if (isVerticalLine) { info[1] = (float) ((topX - bottomX) / bounds.getWidth()); info[0] = (float) (topX + (info[1]*bounds.getX())); } else { info[1] = (float) ((topX - bottomX) / bounds.getHeight()); info[0] = (float) (bottomX + (info[1]*bounds.getMaxY())); } return info; } /** * Returns information about the caret corresponding to <code>hit</code>. * The first element of the array is the intersection of the caret with * the baseline. The second element of the array is the inverse slope * (run/rise) of the caret. * <p> * This method is meant for informational use. To display carets, it * is better to use <code>getCaretShapes</code>. * @param hit a hit on a character in this <code>TextLayout</code> * @param bounds the bounds to which the caret info is constructed * @return a two-element array containing the position and slope of * the caret. * @see #getCaretShapes(int, Rectangle2D, TextLayout.CaretPolicy) * @see Font#getItalicAngle */ public float[] getCaretInfo(TextHitInfo hit, Rectangle2D bounds) { ensureCache(); checkTextHit(hit); return getCaretInfo(hitToCaret(hit), bounds, null); } /** * Returns information about the caret corresponding to <code>hit</code>. * This method is a convenience overload of <code>getCaretInfo</code> and * uses the natural bounds of this <code>TextLayout</code>. * @param hit a hit on a character in this <code>TextLayout</code> * @return the information about a caret corresponding to a hit. */ public float[] getCaretInfo(TextHitInfo hit) { return getCaretInfo(hit, getNaturalBounds()); } /** * Returns a caret index corresponding to <code>hit</code>. * Carets are numbered from left to right (top to bottom) starting from * zero. This always places carets next to the character hit, on the * indicated side of the character. * @param hit a hit on a character in this <code>TextLayout</code> * @return a caret index corresponding to the specified hit. */ private int hitToCaret(TextHitInfo hit) { int hitIndex = hit.getCharIndex(); if (hitIndex < 0) { return textLine.isDirectionLTR() ? 0 : characterCount; } else if (hitIndex >= characterCount) { return textLine.isDirectionLTR() ? characterCount : 0; } int visIndex = textLine.logicalToVisual(hitIndex); if (hit.isLeadingEdge() != textLine.isCharLTR(hitIndex)) { ++visIndex; } return visIndex; } /** * Given a caret index, return a hit whose caret is at the index. * The hit is NOT guaranteed to be strong!!! * * @param caret a caret index. * @return a hit on this layout whose strong caret is at the requested * index. */ private TextHitInfo caretToHit(int caret) { if (caret == 0 || caret == characterCount) { if ((caret == characterCount) == textLine.isDirectionLTR()) { return TextHitInfo.leading(characterCount); } else { return TextHitInfo.trailing(-1); } } else { int charIndex = textLine.visualToLogical(caret); boolean leading = textLine.isCharLTR(charIndex); return leading? TextHitInfo.leading(charIndex) : TextHitInfo.trailing(charIndex); } } private boolean caretIsValid(int caret) { if (caret == characterCount || caret == 0) { return true; } int offset = textLine.visualToLogical(caret); if (!textLine.isCharLTR(offset)) { offset = textLine.visualToLogical(caret-1); if (textLine.isCharLTR(offset)) { return true; } } // At this point, the leading edge of the character
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -