📄 textline.java
字号:
/* * @(#)TextLine.java 1.46 03/01/23 * * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. *//* * (C) Copyright IBM Corp. 1998, All Rights Reserved * */package java.awt.font;import java.awt.Font;import java.awt.Graphics2D;import java.awt.Shape;import java.awt.geom.Rectangle2D;import java.awt.geom.AffineTransform;import java.awt.geom.GeneralPath;import java.awt.im.InputMethodHighlight;import java.text.CharacterIterator;import java.text.AttributedCharacterIterator;import java.text.Annotation;import java.text.Bidi;import java.util.Map;import java.util.Hashtable;import sun.awt.font.BidiUtils;import sun.awt.font.Decoration;import sun.awt.font.FontResolver;import sun.awt.font.GraphicComponent;import sun.awt.font.TextLabelFactory;import sun.awt.font.TextLineComponent;final class TextLine { static final class TextLineMetrics { public final float ascent; public final float descent; public final float leading; public final float advance; public TextLineMetrics(float ascent, float descent, float leading, float advance) { this.ascent = ascent; this.descent = descent; this.leading = leading; this.advance = advance; } } private TextLineComponent[] fComponents; private float[] fBaselineOffsets; private int[] fComponentVisualOrder; // if null, ltr private char[] fChars; private int fCharsStart; private int fCharsLimit; private int[] fCharVisualOrder; // if null, ltr private int[] fCharLogicalOrder; // if null, ltr private byte[] fCharLevels; // if null, 0 private boolean fIsDirectionLTR; private TextLineMetrics fMetrics = null; // built on demand in getMetrics public TextLine(TextLineComponent[] components, float[] baselineOffsets, char[] chars, int charsStart, int charsLimit, int[] charLogicalOrder, byte[] charLevels, boolean isDirectionLTR) { int[] componentVisualOrder = computeComponentOrder(components, charLogicalOrder); fComponents = components; fBaselineOffsets = baselineOffsets; fComponentVisualOrder = componentVisualOrder; fChars = chars; fCharsStart = charsStart; fCharsLimit = charsLimit; fCharLogicalOrder = charLogicalOrder; fCharLevels = charLevels; fIsDirectionLTR = isDirectionLTR; checkCtorArgs(); } private void checkCtorArgs() { int checkCharCount = 0; for (int i=0; i < fComponents.length; i++) { checkCharCount += fComponents[i].getNumCharacters(); } if (checkCharCount != this.characterCount()) { throw new IllegalArgumentException("Invalid TextLine! " + "char count is different from " + "sum of char counts of components."); } } private abstract static class Function { abstract float computeFunction(TextLine line, int componentIndex, int indexInArray); } private static Function fgAdvanceF = new Function() { float computeFunction(TextLine line, int componentIndex, int indexInArray) { TextLineComponent tlc = line.fComponents[componentIndex]; return tlc.getCharAdvance(indexInArray); } }; private static Function fgXPositionF = new Function() { float computeFunction(TextLine line, int componentIndex, int indexInArray) { // add up Component advances before componentIndex // Note how we have to get the component advances. It would // be better to have a getAdvance mathod on component. float componentsAdvance = 0; if (line.fComponentVisualOrder == null) { for (int i=0; i < componentIndex; i++) { Rectangle2D lb = line.fComponents[i].getLogicalBounds(); componentsAdvance += (float)lb.getWidth(); } } else { for (int i=0; line.fComponentVisualOrder[i] != componentIndex; i++) { int index = line.fComponentVisualOrder[i]; Rectangle2D lb = line.fComponents[index].getLogicalBounds(); componentsAdvance += (float)lb.getWidth(); } } TextLineComponent tlc = line.fComponents[componentIndex]; return componentsAdvance + tlc.getCharX(indexInArray); } }; private static Function fgYPositionF = new Function() { float computeFunction(TextLine line, int componentIndex, int indexInArray) { TextLineComponent tlc = line.fComponents[componentIndex]; float charPos = tlc.getCharY(indexInArray); // charPos is relative to the component - adjust for // baseline return charPos + line.getComponentShift(componentIndex); } }; public int characterCount() { return fCharsLimit - fCharsStart; } public boolean isDirectionLTR() { return fIsDirectionLTR; } public TextLineMetrics getMetrics() { if (fMetrics == null) { float ascent = 0; float descent = 0; float leading = 0; float advance = 0; // ascent + descent must not be less than this value float maxGraphicHeight = 0; float maxGraphicHeightWithLeading = 0; // walk through EGA's TextLineComponent tlc; boolean fitTopAndBottomGraphics = false; for (int i = 0; i < fComponents.length; i++) { tlc = fComponents[i]; Rectangle2D lb = tlc.getLogicalBounds(); advance += (float)lb.getWidth(); byte baseline = (byte) tlc.getLineMetrics().getBaselineIndex(); LineMetrics lm = tlc.getLineMetrics(); if (baseline >= 0) { float baselineOffset = fBaselineOffsets[baseline]; ascent = Math.max(ascent, -baselineOffset + lm.getAscent()); float gd = baselineOffset + lm.getDescent(); descent = Math.max(descent, gd); leading = Math.max(leading, gd + lm.getLeading()); } else { fitTopAndBottomGraphics = true; float graphicHeight = lm.getAscent() + lm.getDescent(); float graphicHeightWithLeading = graphicHeight + lm.getLeading(); maxGraphicHeight = Math.max(maxGraphicHeight, graphicHeight); maxGraphicHeightWithLeading = Math.max(maxGraphicHeightWithLeading, graphicHeightWithLeading); } } if (fitTopAndBottomGraphics) { if (maxGraphicHeight > ascent + descent) { descent = maxGraphicHeight - ascent; } if (maxGraphicHeightWithLeading > ascent + leading) { leading = maxGraphicHeightWithLeading - ascent; } } leading -= descent; fMetrics = new TextLineMetrics(ascent, descent, leading, advance); } return fMetrics; } public int visualToLogical(int visualIndex) { if (fCharLogicalOrder == null) { return visualIndex; } if (fCharVisualOrder == null) { fCharVisualOrder = BidiUtils.createInverseMap(fCharLogicalOrder); } return fCharVisualOrder[visualIndex]; } public int logicalToVisual(int logicalIndex) { return (fCharLogicalOrder == null)? logicalIndex : fCharLogicalOrder[logicalIndex]; } public byte getCharLevel(int logicalIndex) { return fCharLevels==null? 0 : fCharLevels[logicalIndex]; } public boolean isCharLTR(int logicalIndex) { return (getCharLevel(logicalIndex) & 0x1) == 0; } public int getCharType(int logicalIndex) { return Character.getType(fChars[logicalIndex + fCharsStart]); } public boolean isCharSpace(int logicalIndex) { return Character.isSpaceChar(fChars[logicalIndex + fCharsStart]); } public boolean isCharWhitespace(int logicalIndex) { return Character.isWhitespace(fChars[logicalIndex + fCharsStart]); } public float getCharAngle(int logicalIndex) { if (logicalIndex < 0) { throw new IllegalArgumentException("Negative logicalIndex."); } if (logicalIndex > fCharsLimit - fCharsStart) { throw new IllegalArgumentException("logicalIndex too large."); } int currentTlc = 0; int tlcLimit = 0; do { tlcLimit += fComponents[currentTlc].getNumCharacters(); if (tlcLimit > logicalIndex) { break; } ++currentTlc; } while(currentTlc < fComponents.length); return fComponents[currentTlc].getItalicAngle(); } private LineMetrics getLineMetricsAt(int logicalIndex) { if (logicalIndex < 0) { throw new IllegalArgumentException("Negative logicalIndex."); } if (logicalIndex > fCharsLimit - fCharsStart) { throw new IllegalArgumentException("logicalIndex too large."); } int currentTlc = 0; int tlcStart = 0; int tlcLimit = 0; do { tlcLimit += fComponents[currentTlc].getNumCharacters(); if (tlcLimit > logicalIndex) { break; } ++currentTlc; tlcStart = tlcLimit; } while(currentTlc < fComponents.length); return fComponents[currentTlc].getLineMetrics(); } public float getCharAscent(int logicalIndex) { return getLineMetricsAt(logicalIndex).getAscent(); } public float getCharDescent(int logicalIndex) { return getLineMetricsAt(logicalIndex).getDescent(); } private float applyFunctionAtIndex(int logicalIndex, Function f) { 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) { return f.computeFunction(this, i, logicalIndex - tlcStart); } else { tlcStart = tlcLimit; } } throw new IllegalArgumentException("logicalIndex too large."); } public float getCharAdvance(int logicalIndex) { return applyFunctionAtIndex(logicalIndex, fgAdvanceF); } public float getCharXPosition(int logicalIndex) { return applyFunctionAtIndex(logicalIndex, fgXPositionF); } public float getCharYPosition(int logicalIndex) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -