📄 textline.java
字号:
return applyFunctionAtIndex(logicalIndex, fgYPositionF); } public float getCharLinePosition(int logicalIndex) { return getCharXPosition(logicalIndex); } public boolean caretAtOffsetIsValid(int offset) { if (offset < 0) { throw new IllegalArgumentException("Negative offset."); } int tlcStart = 0; for(int i=0; i < fComponents.length; i++) { int tlcLimit = tlcStart + fComponents[i].getNumCharacters(); if (tlcLimit > offset) { return fComponents[i].caretAtOffsetIsValid(offset-tlcStart); } else { tlcStart = tlcLimit; } } throw new IllegalArgumentException("logicalIndex too large."); } public Rectangle2D getCharBounds(int logicalIndex) { if (logicalIndex < 0) { throw new IllegalArgumentException("Negative logicalIndex."); } int tlcStart = 0; for (int i=0; i < fComponents.length; i++) { int tlcLimit = tlcStart + fComponents[i].getNumCharacters(); if (tlcLimit > logicalIndex) { TextLineComponent tlc = fComponents[i]; int indexInTlc = logicalIndex - tlcStart; Rectangle2D chBounds = tlc.getCharVisualBounds(indexInTlc); // now accumulate advances of visually preceding tlc's float componentsAdvance = 0; if (fComponentVisualOrder == null) { for (int j=0; j < i; j++) { Rectangle2D lb = fComponents[j].getLogicalBounds(); componentsAdvance += (float)lb.getWidth(); } } else { for (int j=0; fComponentVisualOrder[j] != i; j++) { int index = fComponentVisualOrder[j]; Rectangle2D lb = fComponents[index].getLogicalBounds(); componentsAdvance += (float)lb.getWidth(); } } chBounds.setRect(chBounds.getX() + componentsAdvance, chBounds.getY(), chBounds.getWidth(), chBounds.getHeight()); return chBounds; } else { tlcStart = tlcLimit; } } throw new IllegalArgumentException("logicalIndex too large."); } private float getComponentShift(int index) { byte baseline = (byte) fComponents[index].getLineMetrics().getBaselineIndex(); if (baseline >= 0) { return fBaselineOffsets[baseline]; } else { TextLineMetrics lineMetrics = getMetrics(); // don't bother to get chars right here: LineMetrics compMetrics = fComponents[index].getLineMetrics(); if (baseline == GraphicAttribute.TOP_ALIGNMENT) { return compMetrics.getAscent() - lineMetrics.ascent; } else { return lineMetrics.descent - compMetrics.getDescent(); } } } public void draw(Graphics2D g2, float x, float y) { float nx = x; for (int i = 0; i < fComponents.length; i++) { int index = fComponentVisualOrder==null? i : fComponentVisualOrder[i]; TextLineComponent tlc = fComponents[index]; float shift = getComponentShift(index); tlc.draw(g2, nx, y + shift); if (i != fComponents.length-1) { Rectangle2D lb = tlc.getLogicalBounds(); nx += (float)lb.getWidth(); } } } public Rectangle2D getBounds() { float tlcAdvance = 0; float left = Float.MAX_VALUE, right = Float.MIN_VALUE; float top = Float.MAX_VALUE, bottom = Float.MIN_VALUE; for (int i=0; i < fComponents.length; i++) { int index = fComponentVisualOrder==null? i : fComponentVisualOrder[i]; TextLineComponent tlc = fComponents[index]; Rectangle2D tlcBounds = tlc.getVisualBounds(); left = Math.min(left, (float) tlcBounds.getX() + tlcAdvance); right = Math.max(right, (float) tlcBounds.getMaxX() + tlcAdvance); float shift = getComponentShift(index); top = Math.min(top, (float) tlcBounds.getY()+shift); bottom = Math.max(bottom, (float) tlcBounds.getMaxY()+shift); Rectangle2D lb = tlc.getLogicalBounds(); tlcAdvance += (float)lb.getWidth(); } return new Rectangle2D.Float(left, top, right-left, bottom-top); } public Shape getOutline(AffineTransform tx) { GeneralPath dstShape = new GeneralPath(GeneralPath.WIND_NON_ZERO); float x = 0; for (int i=0; i < fComponents.length; i++) { int index = fComponentVisualOrder==null? i : fComponentVisualOrder[i]; TextLineComponent tlc = fComponents[index]; float shift = getComponentShift(index); dstShape.append(tlc.getOutline(x, shift), false); Rectangle2D lb = tlc.getLogicalBounds(); x += (float)lb.getWidth(); } if (tx != null) { dstShape.transform(tx); } return dstShape; } public int hashCode() { return (fComponents.length << 16) ^ (fComponents[0].hashCode() << 3) ^ (fCharsLimit-fCharsStart); } public String toString() { StringBuffer buf = new StringBuffer(); for (int i = 0; i < fComponents.length; i++) { buf.append(fComponents[i]); } return buf.toString(); } /** * Create a TextLine from the text. The Font must be able to * display all of the text. * attributes==null is equivalent to using an empty Map for * attributes */ public static TextLine fastCreateTextLine(FontRenderContext frc, char[] chars, Font font, LineMetrics lm, Map attributes) { boolean isDirectionLTR = true; byte[] levels = null; int[] charsLtoV = null; Bidi bidi = null; int characterCount = chars.length; boolean requiresBidi = false; boolean directionKnown = false; byte[] embs = null; if (attributes != null) { try { Boolean runDirection = (Boolean)attributes.get(TextAttribute.RUN_DIRECTION); if (runDirection != null) { directionKnown = true; isDirectionLTR = TextAttribute.RUN_DIRECTION_LTR.equals(runDirection); requiresBidi = !isDirectionLTR; } } catch (ClassCastException e) { } try { Integer embeddingLevel = (Integer)attributes.get(TextAttribute.BIDI_EMBEDDING); if (embeddingLevel != null) { int intLevel = embeddingLevel.intValue(); if (intLevel >= -61 && intLevel < 62) { byte level = (byte)intLevel; requiresBidi = true; embs = new byte[characterCount]; for (int i = 0; i < embs.length; ++i) { embs[i] = level; } } } } catch (ClassCastException e) { } } if (!requiresBidi) { requiresBidi = Bidi.requiresBidi(chars, 0, chars.length); } if (requiresBidi) { int bidiflags = Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT; if (directionKnown) { if (isDirectionLTR) { bidiflags = Bidi.DIRECTION_LEFT_TO_RIGHT; } else { bidiflags = Bidi.DIRECTION_RIGHT_TO_LEFT; } } bidi = new Bidi(chars, 0, embs, 0, chars.length, bidiflags); if (!bidi.isLeftToRight()) { levels = BidiUtils.getLevels(bidi); int[] charsVtoL = BidiUtils.createVisualToLogicalMap(levels); charsLtoV = BidiUtils.createInverseMap(charsVtoL); isDirectionLTR = bidi.baseIsLeftToRight(); } } Decoration decorator; if (attributes != null) { decorator = Decoration.getDecoration(StyledParagraph.addInputMethodAttrs(attributes)); } else { decorator = Decoration.getPlainDecoration(); } int layoutFlags = 0; // no extra info yet, bidi determines run and line direction TextLabelFactory factory = new TextLabelFactory(frc, chars, bidi, layoutFlags); TextLineComponent[] components = new TextLineComponent[1]; components = createComponentsOnRun(0, chars.length, chars, charsLtoV, levels, factory, font, lm, frc, decorator, components, 0); int numComponents = components.length; while (components[numComponents-1] == null) { numComponents -= 1; } if (numComponents != components.length) { TextLineComponent[] temp = new TextLineComponent[numComponents]; System.arraycopy(components, 0, temp, 0, numComponents); components = temp; } return new TextLine(components, lm.getBaselineOffsets(), chars, 0, chars.length, charsLtoV, levels, isDirectionLTR); } private static TextLineComponent[] expandArray(TextLineComponent[] orig) { TextLineComponent[] newComponents = new TextLineComponent[orig.length + 8]; System.arraycopy(orig, 0, newComponents, 0, orig.length); return newComponents; } /** * Returns an array in logical order of the TextLineComponents on * the text in the given range, with the given attributes. */ public static TextLineComponent[] createComponentsOnRun(int runStart, int runLimit, char[] chars, int[] charsLtoV, byte[] levels, TextLabelFactory factory, Font font, LineMetrics lm, FontRenderContext frc, Decoration decorator, TextLineComponent[] components, int numComponents) { int pos = runStart; if (lm != null) { if (lm.getNumChars() != (runLimit-runStart)) { throw new IllegalArgumentException("Invalid LineMetrics"); } } do { int chunkLimit = firstVisualChunk(charsLtoV, levels, pos, runLimit); // <= displayLimit do { int startPos = pos; LineMetrics lineMetrics; int lmCount; if (lm == null) { lineMetrics = font.getLineMetrics(chars, startPos, chunkLimit, frc); lmCount = lineMetrics.getNumChars(); } else { lineMetrics = lm; lmCount = (chunkLimit-startPos); } TextLineComponent nextComponent = factory.createExtended(font, lineMetrics, decorator, startPos, startPos + lmCount); ++numComponents; if (numComponents >= components.length) { components = expandArray(components); } components[numComponents-1] = nextComponent; pos += lmCount; } while (pos < chunkLimit); } while (pos < runLimit); return components; } /** * Returns an array (in logical order) of the TextLineComponents representing * the text. The components are both logically and visually contiguous. */ public static TextLineComponent[] getComponents(StyledParagraph styledParagraph, char[] chars, int textStart, int textLimit, int[] charsLtoV, byte[] levels, TextLabelFactory factory) { FontRenderContext frc = factory.getFontRenderContext(); int numComponents = 0; TextLineComponent[] tempComponents = new TextLineComponent[1]; int pos = textStart; do { int runLimit = Math.min(styledParagraph.getRunLimit(pos), textLimit); Decoration decorator = styledParagraph.getDecorationAt(pos);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -