📄 textlayout.java
字号:
// set paragraph attributes { // If there's an embedded graphic at the start of the // paragraph, look for the first non-graphic character // and use it and its font to initialize the paragraph. // If not, use the first graphic to initialize. Map paragraphAttrs = text.getAttributes(); boolean haveFont = TextLine.advanceToFirstFont(text); if (haveFont) { Font defaultFont = TextLine.getFontAtCurrentPos(text); int charsStart = text.getIndex() - text.getBeginIndex(); LineMetrics lm = defaultFont.getLineMetrics(chars, charsStart, charsStart+1, frc); paragraphInit((byte)lm.getBaselineIndex(), lm, paragraphAttrs, chars); } else { // hmmm what to do here? Just try to supply reasonable // values I guess. GraphicAttribute graphic = (GraphicAttribute) paragraphAttrs.get(TextAttribute.CHAR_REPLACEMENT); byte defaultBaseline = getBaselineFromGraphic(graphic); Font dummyFont = new Font(new Hashtable(5, (float)0.9)); LineMetrics lm = dummyFont.getLineMetrics(" ", 0, 1, frc); paragraphInit(defaultBaseline, lm, paragraphAttrs, chars); } } textLine = TextLine.standardCreateTextLine(frc, text, chars, baselineOffsets); } /* * A utility to rebuild the ascent/descent/leading/advance cache. * You'll need to call this if you clone and mutate (like justification, * editing methods do) */ private void ensureCache() { if (!cacheIsValid) { buildCache(); } } private void buildCache() { if (textLine == null) { initTextLine(); } lineMetrics = textLine.getMetrics(); // compute visibleAdvance if (textLine.isDirectionLTR()) { int lastNonSpace = characterCount-1; while (lastNonSpace != -1) { int logIndex = textLine.visualToLogical(lastNonSpace); if (!textLine.isCharSpace(logIndex)) { break; } else { --lastNonSpace; } } if (lastNonSpace == characterCount-1) { visibleAdvance = lineMetrics.advance; } else if (lastNonSpace == -1) { visibleAdvance = 0; } else { int logIndex = textLine.visualToLogical(lastNonSpace); visibleAdvance = textLine.getCharLinePosition(logIndex) + textLine.getCharAdvance(logIndex); } } else { int leftmostNonSpace = 0; while (leftmostNonSpace != characterCount) { int logIndex = textLine.visualToLogical(leftmostNonSpace); if (!textLine.isCharSpace(logIndex)) { break; } else { ++leftmostNonSpace; } } if (leftmostNonSpace == characterCount) { visibleAdvance = 0; } else if (leftmostNonSpace == 0) { visibleAdvance = lineMetrics.advance; } else { int logIndex = textLine.visualToLogical(leftmostNonSpace); float pos = textLine.getCharLinePosition(logIndex); visibleAdvance = lineMetrics.advance - pos; } } // naturalBounds, boundsRect will be generated on demand naturalBounds = null; boundsRect = null; // hashCode will be regenerated on demand hashCodeCache = 0; cacheIsValid = true; } private Rectangle2D getNaturalBounds() { ensureCache(); if (naturalBounds == null) { int leftmostCharIndex = textLine.visualToLogical(0); float angle = textLine.getCharAngle(leftmostCharIndex); float leftOrTop = isVerticalLine? -dy : -dx; if (angle < 0) { leftOrTop += angle*textLine.getCharAscent(leftmostCharIndex); } else if (angle > 0) { leftOrTop -= angle*textLine.getCharDescent(leftmostCharIndex); } int rightmostCharIndex = textLine.visualToLogical(characterCount-1); angle = textLine.getCharAngle(rightmostCharIndex); float rightOrBottom = lineMetrics.advance; if (angle < 0) { rightOrBottom -= angle*textLine.getCharDescent(rightmostCharIndex); } else if (angle > 0) { rightOrBottom += angle*textLine.getCharAscent(rightmostCharIndex); } float lineDim = rightOrBottom - leftOrTop; if (isVerticalLine) { naturalBounds = new Rectangle2D.Float( -lineMetrics.descent, leftOrTop, lineMetrics.ascent + lineMetrics.descent, lineDim); } else { naturalBounds = new Rectangle2D.Float( leftOrTop, -lineMetrics.ascent, lineDim, lineMetrics.ascent + lineMetrics.descent); } } return naturalBounds; } /** * Creates a copy of this <code>TextLayout</code>. */ protected Object clone() { /* * !!! I think this is safe. Once created, nothing mutates the * glyphvectors or arrays. But we need to make sure. * {jbr} actually, that's not quite true. The justification code * mutates after cloning. It doesn't actually change the glyphvectors * (that's impossible) but it replaces them with justified sets. This * is a problem for GlyphIterator creation, since new GlyphIterators * are created by cloning a prototype. If the prototype has outdated * glyphvectors, so will the new ones. A partial solution is to set the * prototypical GlyphIterator to null when the glyphvectors change. If * you forget this one time, you're hosed. */ try { return super.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(); } } /* * Utility to throw an expection if an invalid TextHitInfo is passed * as a parameter. Avoids code duplication. */ private void checkTextHit(TextHitInfo hit) { if (hit == null) { throw new IllegalArgumentException("TextHitInfo is null."); } if (hit.getInsertionIndex() < 0 || hit.getInsertionIndex() > characterCount) { throw new IllegalArgumentException("TextHitInfo is out of range"); } } /** * Creates a copy of this <code>TextLayout</code> justified to the * specified width. * <p> * If this <code>TextLayout</code> has already been justified, an * exception is thrown. If this <code>TextLayout</code> object's * justification ratio is zero, a <code>TextLayout</code> identical * to this <code>TextLayout</code> is returned. * @param justificationWidth the width to use when justifying the line. * For best results, it should not be too different from the current * advance of the line. * @return a <code>TextLayout</code> justified to the specified width. * @exception Error if this layout has already been justified, an Error is * thrown. */ public TextLayout getJustifiedLayout(float justificationWidth) { if (justificationWidth <= 0) { throw new IllegalArgumentException("justificationWidth <= 0 passed to TextLayout.getJustifiedLayout()"); } if (justifyRatio == ALREADY_JUSTIFIED) { throw new Error("Can't justify again."); } ensureCache(); // make sure textLine is not null // default justification range to exclude trailing logical whitespace int limit = characterCount; while (limit > 0 && textLine.isCharWhitespace(limit-1)) { --limit; } TextLine newLine = textLine.getJustifiedLine(justificationWidth, justifyRatio, 0, limit); if (newLine != null) { return new TextLayout(newLine, baseline, baselineOffsets, ALREADY_JUSTIFIED); } return this; } /** * Justify this layout. Overridden by subclassers to control justification * (if there were subclassers, that is...) * * The layout will only justify if the paragraph attributes (from the * source text, possibly defaulted by the layout attributes) indicate a * non-zero justification ratio. The text will be justified to the * indicated width. The current implementation also adjusts hanging * punctuation and trailing whitespace to overhang the justification width. * Once justified, the layout may not be rejustified. * <p> * Some code may rely on immutablity of layouts. Subclassers should not * call this directly, but instead should call getJustifiedLayout, which * will call this method on a clone of this layout, preserving * the original. * * @param justificationWidth the width to use when justifying the line. * For best results, it should not be too different from the current * advance of the line. * @see #getJustifiedLayout(float) */ protected void handleJustify(float justificationWidth) { // never called } /** * Returns the baseline for this <code>TextLayout</code>. * The baseline is one of the values defined in <code>Font</code>, * which are roman, centered and hanging. Ascent and descent are * relative to this baseline. The <code>baselineOffsets</code> * are also relative to this baseline. * @return the baseline of this <code>TextLayout</code>. * @see #getBaselineOffsets() * @see Font */ public byte getBaseline() { return baseline; } /** * Returns the offsets array for the baselines used for this * <code>TextLayout</code>. * <p> * The array is indexed by one of the values defined in * <code>Font</code>, which are roman, centered and hanging. The * values are relative to this <code>TextLayout</code> object's * baseline, so that <code>getBaselineOffsets[getBaseline()] == 0</code>. * Offsets are added to the position of the <code>TextLayout</code> * object's baseline to get the position for the new baseline. * @return the offsets array containing the baselines used for this * <code>TextLayout</code>. * @see #getBaseline() * @see Font */ public float[] getBaselineOffsets() { float[] offsets = new float[baselineOffsets.length]; System.arraycopy(baselineOffsets, 0, offsets, 0, offsets.length); return offsets; } /** * Returns the advance of this <code>TextLayout</code>. * The advance is the distance from the origin to the advance of the * rightmost (bottommost) character measuring in the line direction. * @return the advance of this <code>TextLayout</code>. */ public float getAdvance() { if (optInfo != null) { try { return optInfo.getAdvance(); } catch (Error e) { // cache was flushed under optInfo } } ensureCache(); return lineMetrics.advance; } /** * Returns the advance of this <code>TextLayout</code>, minus trailing * whitespace. * @return the advance of this <code>TextLayout</code> without the * trailing whitespace. * @see #getAdvance() */ public float getVisibleAdvance() { ensureCache(); return visibleAdvance; } /** * Returns the ascent of this <code>TextLayout</code>. * The ascent is the distance from the top (right) of the * <code>TextLayout</code> to the baseline. It is always either * positive or zero. The ascent is sufficient to * accomodate superscripted text and is the maximum of the sum of the * ascent, offset, and baseline of each glyph. * @return the ascent of this <code>TextLayout</code>. */ public float getAscent() { if (optInfo != null) { return optInfo.getLineMetrics().getAscent(); } ensureCache(); return lineMetrics.ascent; } /** * Returns the descent of this <code>TextLayout</code>. * The descent is the distance from the baseline to the bottom (left) of * the <code>TextLayout</code>. It is always either positive or zero. * The descent is sufficient to accomodate subscripted text and is the * maximum of the sum of the descent, offset, and baseline of each glyph. * @return the descent of this <code>TextLayout</code>. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -