📄 textlayout.java
字号:
// justifyRatio of the justified layout is set to this value. private static final float ALREADY_JUSTIFIED = -53.9f; // dx and dy specify the distance between the TextLayout's origin // and the origin of the leftmost GlyphSet (TextLayoutComponent, // actually). They were used for hanging punctuation support, // which is no longer implemented. Currently they are both always 0, // and TextLayout is not guaranteed to work with non-zero dx, dy // values right now. They were left in as an aide and reminder to // anyone who implements hanging punctuation or other similar stuff. // They are static now so they don't take up space in TextLayout // instances. private static float dx; private static float dy; /* * Natural bounds is used internally. It is built on demand in * getNaturalBounds. */ private Rectangle2D naturalBounds = null; /* * boundsRect encloses all of the bits this TextLayout can draw. It * is build on demand in getBounds. */ private Rectangle2D boundsRect = null; /* * flag to supress/allow carets inside of ligatures when hit testing or * arrow-keying */ private boolean caretsInLigaturesAreAllowed = false; /** * Defines a policy for determining the strong caret location. * This class contains one method, <code>getStrongCaret</code>, which * is used to specify the policy that determines the strong caret in * dual-caret text. The strong caret is used to move the caret to the * left or right. Instances of this class can be passed to * <code>getCaretShapes</code>, <code>getNextLeftHit</code> and * <code>getNextRightHit</code> to customize strong caret * selection. * <p> * To specify alternate caret policies, subclass <code>CaretPolicy</code> * and override <code>getStrongCaret</code>. <code>getStrongCaret</code> * should inspect the two <code>TextHitInfo</code> arguments and choose * one of them as the strong caret. * <p> * Most clients do not need to use this class. */ public static class CaretPolicy { /** * Constructs a <code>CaretPolicy</code>. */ public CaretPolicy() { } /** * Chooses one of the specified <code>TextHitInfo</code> instances as * a strong caret in the specified <code>TextLayout</code>. * @param hit1 a valid hit in <code>layout</code> * @param hit2 a valid hit in <code>layout</code> * @param layout the <code>TextLayout</code> in which * <code>hit1</code> and <code>hit2</code> are used * @return <code>hit1</code> or <code>hit2</code> * (or an equivalent <code>TextHitInfo</code>), indicating the * strong caret. */ public TextHitInfo getStrongCaret(TextHitInfo hit1, TextHitInfo hit2, TextLayout layout) { // default implmentation just calls private method on layout return layout.getStrongHit(hit1, hit2); } } /** * This <code>CaretPolicy</code> is used when a policy is not specified * by the client. With this policy, a hit on a character whose direction * is the same as the line direction is stronger than a hit on a * counterdirectional character. If the characters' directions are * the same, a hit on the leading edge of a character is stronger * than a hit on the trailing edge of a character. */ public static final CaretPolicy DEFAULT_CARET_POLICY = new CaretPolicy(); /** * Constructs a <code>TextLayout</code> from a <code>String</code> * and a {@link Font}. All the text is styled using the specified * <code>Font</code>. * <p> * The <code>String</code> must specify a single paragraph of text, * because an entire paragraph is required for the bidirectional * algorithm. * @param string the text to display * @param font a <code>Font</code> used to style the text * @param frc contains information about a graphics device which is needed * to measure the text correctly. * Text measurements can vary slightly depending on the * device resolution, and attributes such as antialiasing. This * parameter does not specify a translation between the * <code>TextLayout</code> and user space. */ public TextLayout(String string, Font font, FontRenderContext frc) { if (font == null) { throw new IllegalArgumentException("Null font passed to TextLayout constructor."); } if (string == null) { throw new IllegalArgumentException("Null string passed to TextLayout constructor."); } if (string.length() == 0) { throw new IllegalArgumentException("Zero length string passed to TextLayout constructor."); } char[] text = string.toCharArray(); if (sameBaselineUpTo(font, text, 0, text.length) == text.length) { fastInit(text, font, null, frc); } else { AttributedString as = new AttributedString(string); as.addAttribute(TextAttribute.FONT, font); standardInit(as.getIterator(), text, frc); } } /** * Constructs a <code>TextLayout</code> from a <code>String</code> * and an attribute set. * <p> * All the text is styled using the provided attributes. * <p> * <code>string</code> must specify a single paragraph of text because an * entire paragraph is required for the bidirectional algorithm. * @param string the text to display * @param attributes the attributes used to style the text * @param frc contains information about a graphics device which is needed * to measure the text correctly. * Text measurements can vary slightly depending on the * device resolution, and attributes such as antialiasing. This * parameter does not specify a translation between the * <code>TextLayout</code> and user space. */ public TextLayout(String string, Map attributes, FontRenderContext frc) { if (string == null) { throw new IllegalArgumentException("Null string passed to TextLayout constructor."); } if (attributes == null) { throw new IllegalArgumentException("Null map passed to TextLayout constructor."); } if (string.length() == 0) { throw new IllegalArgumentException("Zero length string passed to TextLayout constructor."); } char[] text = string.toCharArray(); Font font = singleFont(text, 0, text.length, attributes); if (font != null) { fastInit(text, font, attributes, frc); } else { AttributedString as = new AttributedString(string, attributes); standardInit(as.getIterator(), text, frc); } } /* * Determines a font for the attributes, and if a single font can render * all the text on one baseline, return it, otherwise null. If the * attributes specify a font, assume it can display all the text without * checking. * If the AttributeSet contains an embedded graphic, return null. */ private static Font singleFont(char[] text, int start, int limit, Map attributes) { if (attributes.get(TextAttribute.CHAR_REPLACEMENT) != null) { return null; } Font font = (Font)attributes.get(TextAttribute.FONT); if (font == null) { if (attributes.get(TextAttribute.FAMILY) != null) { font = Font.getFont(attributes); if (font.canDisplayUpTo(text, start, limit) != -1) { return null; } } else { FontResolver resolver = FontResolver.getInstance(); int fontIndex = resolver.getFontIndex(text[start]); for (int i=start+1; i<limit; i++) { if (resolver.getFontIndex(text[i]) != fontIndex) { return null; } } font = resolver.getFont(fontIndex, attributes); } } if (sameBaselineUpTo(font, text, start, limit) != limit) { return null; } return font; } /** * Constructs a <code>TextLayout</code> from an iterator over styled text. * <p> * The iterator must specify a single paragraph of text because an * entire paragraph is required for the bidirectional * algorithm. * @param text the styled text to display * @param frc contains information about a graphics device which is needed * to measure the text correctly. * Text measurements can vary slightly depending on the * device resolution, and attributes such as antialiasing. This * parameter does not specify a translation between the * <code>TextLayout</code> and user space. */ public TextLayout(AttributedCharacterIterator text, FontRenderContext frc) { if (text == null) { throw new IllegalArgumentException("Null iterator passed to TextLayout constructor."); } int start = text.getBeginIndex(); int limit = text.getEndIndex(); if (start == limit) { throw new IllegalArgumentException("Zero length iterator passed to TextLayout constructor."); } int len = limit - start; text.first(); char[] chars = new char[len]; int n = 0; for (char c = text.first(); c != text.DONE; c = text.next()) { chars[n++] = c; } text.first(); if (text.getRunLimit() == limit) { Map attributes = text.getAttributes(); Font font = singleFont(chars, 0, len, attributes); if (font != null) { fastInit(chars, font, attributes, frc); return; } } standardInit(text, chars, frc); } /** * Creates a <code>TextLayout</code> from a {@link TextLine} and * some paragraph data. This method is used by {@link TextMeasurer}. * @param textLine the line measurement attributes to apply to the * the resulting <code>TextLayout</code> * @param baseline the baseline of the text * @param baselineOffsets the baseline offsets for this * <code>TextLayout</code>. This should already be normalized to * <code>baseline</code> * @param justifyRatio <code>0</code> if the <code>TextLayout</code> * cannot be justified; <code>1</code> otherwise. */ TextLayout(TextLine textLine, byte baseline, float[] baselineOffsets, float justifyRatio) { this.characterCount = textLine.characterCount(); this.baseline = baseline; this.baselineOffsets = baselineOffsets; this.textLine = textLine; this.justifyRatio = justifyRatio; } /** * Initialize the paragraph-specific data. */ private void paragraphInit(byte aBaseline, LineMetrics lm, Map paragraphAttrs, char[] text) { baseline = aBaseline; // normalize to current baseline baselineOffsets = TextLine.getNormalizedOffsets(lm.getBaselineOffsets(), baseline); justifyRatio = TextLine.getJustifyRatio(paragraphAttrs); if (paragraphAttrs != null) { Object o = paragraphAttrs.get(TextAttribute.NUMERIC_SHAPING); if (o != null) { try { NumericShaper shaper = (NumericShaper)o; shaper.shape(text, 0, text.length); } catch (ClassCastException e) { } } } } /* * the fast init generates a single glyph set. This requires: * all one style * all renderable by one font (ie no embedded graphics) * all on one baseline */ private void fastInit(char[] chars, Font font, Map attrs, FontRenderContext frc) { // Object vf = attrs.get(TextAttribute.ORIENTATION); // isVerticalLine = TextAttribute.ORIENTATION_VERTICAL.equals(vf); isVerticalLine = false; LineMetrics lm = font.getLineMetrics(chars, 0, chars.length, frc); byte glyphBaseline = (byte) lm.getBaselineIndex(); if (attrs == null) { baseline = glyphBaseline; baselineOffsets = lm.getBaselineOffsets(); justifyRatio = 1.0f; } else { paragraphInit(glyphBaseline, lm, attrs, chars); } characterCount = chars.length; optInfo = OptInfo.create(frc, chars, font, lm, attrs); if (optInfo == null) { textLine = TextLine.fastCreateTextLine(frc, chars, font, lm, attrs); } } private void initTextLine() { textLine = optInfo.createTextLine(); optInfo = null; } /* * the standard init generates multiple glyph sets based on style, * renderable, and baseline runs. * @param chars the text in the iterator, extracted into a char array */ private void standardInit(AttributedCharacterIterator text, char[] chars, FontRenderContext frc) { characterCount = chars.length;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -