summaryrefslogtreecommitdiffstats
path: root/awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java')
-rw-r--r--awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java979
1 files changed, 0 insertions, 979 deletions
diff --git a/awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java b/awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java
deleted file mode 100644
index 0ec2d05..0000000
--- a/awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java
+++ /dev/null
@@ -1,979 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * @author Oleg V. Khaschansky
- * @version $Revision$
- *
- */
-
-package org.apache.harmony.awt.gl.font;
-
-import java.awt.*;
-import java.awt.font.*;
-import java.awt.geom.Rectangle2D;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Point2D;
-// XXX - TODO - bidi not implemented yet
-//import java.text.Bidi;
-import java.util.Arrays;
-
-import org.apache.harmony.awt.internal.nls.Messages;
-
-/**
- * Date: Apr 25, 2005
- * Time: 4:33:18 PM
- *
- * This class contains the implementation of the behavior of the
- * text run segment with constant text attributes and direction.
- */
-public class TextRunSegmentImpl {
-
- /**
- * This class contains basic information required for creation
- * of the glyph-based text run segment.
- */
- public static class TextSegmentInfo {
- // XXX - TODO - bidi not implemented yet
- //Bidi bidi;
-
- Font font;
- FontRenderContext frc;
-
- char text[];
-
- int start;
- int end;
- int length;
-
- int flags = 0;
-
- byte level = 0;
-
- TextSegmentInfo(
- byte level,
- Font font, FontRenderContext frc,
- char text[], int start, int end
- ) {
- this.font = font;
- this.frc = frc;
- this.text = text;
- this.start = start;
- this.end = end;
- this.level = level;
- length = end - start;
- }
- }
-
- /**
- * This class represents a simple text segment backed by the glyph vector
- */
- public static class TextRunSegmentCommon extends TextRunSegment {
- TextSegmentInfo info;
- private GlyphVector gv;
- private float advanceIncrements[];
- private int char2glyph[];
- private GlyphJustificationInfo gjis[]; // Glyph justification info
-
- TextRunSegmentCommon(TextSegmentInfo i, TextDecorator.Decoration d) {
- // XXX - todo - check support bidi
- i.flags &= ~0x09; // Clear bidi flags
-
- if ((i.level & 0x1) != 0) {
- i.flags |= Font.LAYOUT_RIGHT_TO_LEFT;
- }
-
- info = i;
- this.decoration = d;
-
- LineMetrics lm = i.font.getLineMetrics(i.text, i.start, i.end, i.frc);
- this.metrics = new BasicMetrics(lm, i.font);
-
- if (lm.getNumChars() != i.length) { // XXX todo - This should be handled
- // awt.41=Font returned unsupported type of line metrics. This case is known, but not supported yet.
- throw new UnsupportedOperationException(
- Messages.getString("awt.41")); //$NON-NLS-1$
- }
- }
-
- @Override
- public Object clone() {
- return new TextRunSegmentCommon(info, decoration);
- }
-
- /**
- * Creates glyph vector from the managed text if needed
- * @return glyph vector
- */
- private GlyphVector getGlyphVector() {
- if (gv==null) {
- gv = info.font.layoutGlyphVector(
- info.frc,
- info.text,
- info.start,
- info.end - info.start, // NOTE: This parameter violates
- // spec, it is count,
- // not limit as spec states
- info.flags
- );
- }
-
- return gv;
- }
-
- /**
- * Renders this text run segment
- * @param g2d - graphics to render to
- * @param xOffset - X offset from the graphics origin to the
- * origin of the text layout
- * @param yOffset - Y offset from the graphics origin to the
- * origin of the text layout
- */
- @Override
- void draw(Graphics2D g2d, float xOffset, float yOffset) {
- if (decoration == null) {
- g2d.drawGlyphVector(getGlyphVector(), xOffset + x, yOffset + y);
- } else {
- TextDecorator.prepareGraphics(this, g2d, xOffset, yOffset);
- g2d.drawGlyphVector(getGlyphVector(), xOffset + x, yOffset + y);
- TextDecorator.drawTextDecorations(this, g2d, xOffset, yOffset);
- TextDecorator.restoreGraphics(decoration, g2d);
- }
- }
-
- /**
- * Returns visual bounds of this segment
- * @return visual bounds
- */
- @Override
- Rectangle2D getVisualBounds() {
- if (visualBounds == null) {
- visualBounds =
- TextDecorator.extendVisualBounds(
- this,
- getGlyphVector().getVisualBounds(),
- decoration
- );
-
- visualBounds.setRect(
- x + visualBounds.getX(),
- y + visualBounds.getY(),
- visualBounds.getWidth(),
- visualBounds.getHeight()
- );
- }
-
- return (Rectangle2D) visualBounds.clone();
- }
-
- /**
- * Returns logical bounds of this segment
- * @return logical bounds
- */
- @Override
- Rectangle2D getLogicalBounds() {
- if (logicalBounds == null) {
- logicalBounds = getGlyphVector().getLogicalBounds();
-
- logicalBounds.setRect(
- x + logicalBounds.getX(),
- y + logicalBounds.getY(),
- logicalBounds.getWidth(),
- logicalBounds.getHeight()
- );
- }
-
- return (Rectangle2D) logicalBounds.clone();
- }
-
- @Override
- float getAdvance() {
- return (float) getLogicalBounds().getWidth();
- }
-
- /**
- * Attemts to map each character to the corresponding advance increment
- */
- void initAdvanceMapping() {
- GlyphVector gv = getGlyphVector();
- int charIndicies[] = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null);
- advanceIncrements = new float[info.length];
-
- for (int i=0; i<charIndicies.length; i++) {
- advanceIncrements[charIndicies[i]] = gv.getGlyphMetrics(i).getAdvance();
- }
- }
-
- /**
- * Calculates advance delta between two characters
- * @param start - 1st position
- * @param end - 2nd position
- * @return advance increment between specified positions
- */
- @Override
- float getAdvanceDelta(int start, int end) {
- // Get coordinates in the segment context
- start -= info.start;
- end -= info.start;
-
- if (advanceIncrements == null) {
- initAdvanceMapping();
- }
-
- if (start < 0) {
- start = 0;
- }
- if (end > info.length) {
- end = info.length;
- }
-
- float sum = 0;
- for (int i=start; i<end; i++) {
- sum += advanceIncrements[i];
- }
-
- return sum;
- }
-
- /**
- * Calculates index of the character which advance is equal to
- * the given. If the given advance is greater then the segment
- * advance it returns the position after the last character.
- * @param advance - given advance
- * @param start - character, from which to start measuring advance
- * @return character index
- */
- @Override
- int getCharIndexFromAdvance(float advance, int start) {
- // XXX - todo - probably, possible to optimize
- // Add check if the given advance is greater then
- // the segment advance in the beginning. In this case
- // we don't need to run through all increments
- if (advanceIncrements == null) {
- initAdvanceMapping();
- }
-
- start -= info.start;
-
- if (start < 0) {
- start = 0;
- }
-
- int i = start;
- for (; i<info.length; i++) {
- advance -= advanceIncrements[i];
- if (advance < 0) {
- break;
- }
- }
-
- return i + info.start;
- }
-
- @Override
- int getStart() {
- return info.start;
- }
-
- @Override
- int getEnd() {
- return info.end;
- }
-
- @Override
- int getLength() {
- return info.length;
- }
-
- /**
- * Attemts to create mapping of the characters to glyphs in the glyph vector.
- * @return array where for each character index stored corresponding glyph index
- */
- private int[] getChar2Glyph() {
- if (char2glyph == null) {
- GlyphVector gv = getGlyphVector();
- char2glyph = new int[info.length];
- Arrays.fill(char2glyph, -1);
-
- // Fill glyph indicies for first characters corresponding to each glyph
- int charIndicies[] = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null);
- for (int i=0; i<charIndicies.length; i++) {
- char2glyph[charIndicies[i]] = i;
- }
-
- // If several characters corresponds to one glyph, create mapping for them
- // Suppose that these characters are going all together
- int currIndex = 0;
- for (int i=0; i<char2glyph.length; i++) {
- if (char2glyph[i] < 0) {
- char2glyph[i] = currIndex;
- } else {
- currIndex = char2glyph[i];
- }
- }
- }
-
- return char2glyph;
- }
-
- /**
- * Creates black box bounds shape for the specified range
- * @param start - range sart
- * @param limit - range end
- * @return black box bounds shape
- */
- @Override
- Shape getCharsBlackBoxBounds(int start, int limit) {
- start -= info.start;
- limit -= info.start;
-
- if (limit > info.length) {
- limit = info.length;
- }
-
- GeneralPath result = new GeneralPath();
-
- int glyphIndex = 0;
-
- for (int i=start; i<limit; i++) {
- glyphIndex = getChar2Glyph()[i];
- result.append(getGlyphVector().getGlyphVisualBounds(glyphIndex), false);
- }
-
- // Shift to the segment's coordinates
- result.transform(AffineTransform.getTranslateInstance(x, y));
-
- return result;
- }
-
- /**
- * Calculates position of the character on the screen
- * @param index - character index
- * @return X coordinate of the character position
- */
- @Override
- float getCharPosition(int index) {
- index -= info.start;
-
- if (index > info.length) {
- index = info.length;
- }
-
- float result = 0;
-
- int glyphIndex = getChar2Glyph()[index];
- result = (float) getGlyphVector().getGlyphPosition(glyphIndex).getX();
-
- // Shift to the segment's coordinates
- result += x;
-
- return result;
- }
-
- /**
- * Returns the advance of the individual character
- * @param index - character index
- * @return character advance
- */
- @Override
- float getCharAdvance(int index) {
- if (advanceIncrements == null) {
- initAdvanceMapping();
- }
-
- return advanceIncrements[index - this.getStart()];
- }
-
- /**
- * Returns the outline shape
- * @return outline
- */
- @Override
- Shape getOutline() {
- AffineTransform t = AffineTransform.getTranslateInstance(x, y);
- return t.createTransformedShape(
- TextDecorator.extendOutline(
- this,
- getGlyphVector().getOutline(),
- decoration
- )
- );
- }
-
- /**
- * Checks if the character doesn't contribute to the text advance
- * @param index - character index
- * @return true if the character has zero advance
- */
- @Override
- boolean charHasZeroAdvance(int index) {
- if (advanceIncrements == null) {
- initAdvanceMapping();
- }
-
- return advanceIncrements[index - this.getStart()] == 0;
- }
-
- /**
- * Creates text hit info from the hit position
- * @param hitX - X coordinate relative to the origin of the layout
- * @param hitY - Y coordinate relative to the origin of the layout
- * @return hit info
- */
- @Override
- TextHitInfo hitTest(float hitX, float hitY) {
- hitX -= x;
-
- float glyphPositions[] =
- getGlyphVector().getGlyphPositions(0, info.length+1, null);
-
- int glyphIdx;
- boolean leading = false;
- for (glyphIdx = 1; glyphIdx <= info.length; glyphIdx++) {
- if (glyphPositions[(glyphIdx)*2] >= hitX) {
- float advance =
- glyphPositions[(glyphIdx)*2] - glyphPositions[(glyphIdx-1)*2];
- leading = glyphPositions[(glyphIdx-1)*2] + advance/2 > hitX ? true : false;
- glyphIdx--;
- break;
- }
- }
-
- if (glyphIdx == info.length) {
- glyphIdx--;
- }
-
- int charIdx = getGlyphVector().getGlyphCharIndex(glyphIdx);
-
- return (leading) ^ ((info.level & 0x1) == 0x1)?
- TextHitInfo.leading(charIdx + info.start) :
- TextHitInfo.trailing(charIdx + info.start);
- }
-
- /**
- * Collects GlyphJustificationInfo objects from the glyph vector
- * @return array of all GlyphJustificationInfo objects
- */
- private GlyphJustificationInfo[] getGlyphJustificationInfos() {
- if (gjis == null) {
- GlyphVector gv = getGlyphVector();
- int nGlyphs = gv.getNumGlyphs();
- int charIndicies[] = gv.getGlyphCharIndices(0, nGlyphs, null);
- gjis = new GlyphJustificationInfo[nGlyphs];
-
- // Patch: temporary patch, getGlyphJustificationInfo is not implemented
- float fontSize = info.font.getSize2D();
- GlyphJustificationInfo defaultInfo =
- new GlyphJustificationInfo(
- 0, // weight
- false, GlyphJustificationInfo.PRIORITY_NONE, 0, 0, // grow
- false, GlyphJustificationInfo.PRIORITY_NONE, 0, 0); // shrink
- GlyphJustificationInfo spaceInfo = new GlyphJustificationInfo(
- fontSize, // weight
- true, GlyphJustificationInfo.PRIORITY_WHITESPACE, 0, fontSize, // grow
- true, GlyphJustificationInfo.PRIORITY_WHITESPACE, 0, fontSize); // shrink
-
- ////////
- // Temporary patch, getGlyphJustificationInfo is not implemented
- for (int i = 0; i < nGlyphs; i++) {
- //gjis[i] = getGlyphVector().getGlyphJustificationInfo(i);
-
- char c = info.text[charIndicies[i] + info.start];
- if (Character.isWhitespace(c)) {
- gjis[i] = spaceInfo;
- } else {
- gjis[i] = defaultInfo;
- }
- // End patch
- }
- }
-
- return gjis;
- }
-
- /**
- * Collects justification information into JustificationInfo object
- * @param jInfo - JustificationInfo object
- */
- @Override
- void updateJustificationInfo(TextRunBreaker.JustificationInfo jInfo) {
- int lastChar = Math.min(jInfo.lastIdx, info.end) - info.start;
- boolean haveFirst = info.start <= jInfo.firstIdx;
- boolean haveLast = info.end >= (jInfo.lastIdx + 1);
-
- int prevGlyphIdx = -1;
- int currGlyphIdx;
-
- if (jInfo.grow) { // Check how much we can grow/shrink on current priority level
- for (int i=0; i<lastChar; i++) {
- currGlyphIdx = getChar2Glyph()[i];
-
- if (currGlyphIdx == prevGlyphIdx) {
- // Several chars could be represented by one glyph,
- // suppose they are contiguous
- continue;
- }
- prevGlyphIdx = currGlyphIdx;
-
- GlyphJustificationInfo gji = getGlyphJustificationInfos()[currGlyphIdx];
- if (gji.growPriority == jInfo.priority) {
- jInfo.weight += gji.weight * 2;
- jInfo.growLimit += gji.growLeftLimit;
- jInfo.growLimit += gji.growRightLimit;
- if (gji.growAbsorb) {
- jInfo.absorbedWeight += gji.weight * 2;
- }
- }
- }
- } else {
- for (int i=0; i<lastChar; i++) {
- currGlyphIdx = getChar2Glyph()[i];
- if (currGlyphIdx == prevGlyphIdx) {
- continue;
- }
- prevGlyphIdx = currGlyphIdx;
-
- GlyphJustificationInfo gji = getGlyphJustificationInfos()[currGlyphIdx];
- if (gji.shrinkPriority == jInfo.priority) {
- jInfo.weight += gji.weight * 2;
- jInfo.growLimit -= gji.shrinkLeftLimit;
- jInfo.growLimit -= gji.shrinkRightLimit;
- if (gji.shrinkAbsorb) {
- jInfo.absorbedWeight += gji.weight * 2;
- }
- }
- }
- }
-
- if (haveFirst) { // Don't add padding before first char
- GlyphJustificationInfo gji = getGlyphJustificationInfos()[getChar2Glyph()[0]];
- jInfo.weight -= gji.weight;
- if (jInfo.grow) {
- jInfo.growLimit -= gji.growLeftLimit;
- if (gji.growAbsorb) {
- jInfo.absorbedWeight -= gji.weight;
- }
- } else {
- jInfo.growLimit += gji.shrinkLeftLimit;
- if (gji.shrinkAbsorb) {
- jInfo.absorbedWeight -= gji.weight;
- }
- }
- }
-
- if (haveLast) { // Don't add padding after last char
- GlyphJustificationInfo gji =
- getGlyphJustificationInfos()[getChar2Glyph()[lastChar]];
- jInfo.weight -= gji.weight;
- if (jInfo.grow) {
- jInfo.growLimit -= gji.growRightLimit;
- if (gji.growAbsorb) {
- jInfo.absorbedWeight -= gji.weight;
- }
- } else {
- jInfo.growLimit += gji.shrinkRightLimit;
- if (gji.shrinkAbsorb) {
- jInfo.absorbedWeight -= gji.weight;
- }
- }
- }
- }
-
- /**
- * Performs justification of the segment.
- * Updates positions of individual characters.
- * @param jInfos - justification information, gathered by the previous passes
- * @return amount of growth or shrink of the segment
- */
- @Override
- float doJustification(TextRunBreaker.JustificationInfo jInfos[]) {
- int lastPriority =
- jInfos[jInfos.length-1] == null ?
- -1 : jInfos[jInfos.length-1].priority;
-
- // Get the highest priority
- int highestPriority = 0;
- for (; highestPriority<jInfos.length; highestPriority++) {
- if (jInfos[highestPriority] != null) {
- break;
- }
- }
-
- if (highestPriority == jInfos.length) {
- return 0;
- }
-
- TextRunBreaker.JustificationInfo firstInfo = jInfos[highestPriority];
- TextRunBreaker.JustificationInfo lastInfo =
- lastPriority > 0 ? jInfos[lastPriority] : null;
-
- boolean haveFirst = info.start <= firstInfo.firstIdx;
- boolean haveLast = info.end >= (firstInfo.lastIdx + 1);
-
- // Here we suppose that GLYPHS are ordered LEFT TO RIGHT
- int firstGlyph = haveFirst ?
- getChar2Glyph()[firstInfo.firstIdx - info.start] :
- getChar2Glyph()[0];
-
- int lastGlyph = haveLast ?
- getChar2Glyph()[firstInfo.lastIdx - info.start] :
- getChar2Glyph()[info.length - 1];
- if (haveLast) {
- lastGlyph--;
- }
-
- TextRunBreaker.JustificationInfo currInfo;
- float glyphOffset = 0;
- float positionIncrement = 0;
- float sideIncrement = 0;
-
- if (haveFirst) { // Don't add padding before first char
- GlyphJustificationInfo gji = getGlyphJustificationInfos()[firstGlyph];
- currInfo = jInfos[gji.growPriority];
- if (currInfo != null) {
- if (currInfo.useLimits) {
- if (currInfo.absorb) {
- glyphOffset += gji.weight * currInfo.absorbedGapPerUnit;
- } else if (
- lastInfo != null &&
- lastInfo.priority == currInfo.priority
- ) {
- glyphOffset += gji.weight * lastInfo.absorbedGapPerUnit;
- }
- glyphOffset +=
- firstInfo.grow ?
- gji.growRightLimit :
- -gji.shrinkRightLimit;
- } else {
- glyphOffset += gji.weight * currInfo.gapPerUnit;
- }
- }
-
- firstGlyph++;
- }
-
- if (firstInfo.grow) {
- for (int i=firstGlyph; i<=lastGlyph; i++) {
- GlyphJustificationInfo gji = getGlyphJustificationInfos()[i];
- currInfo = jInfos[gji.growPriority];
- if (currInfo == null) {
- // We still have to increment glyph position
- Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
- glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY());
- getGlyphVector().setGlyphPosition(i, glyphPos);
-
- continue;
- }
-
- if (currInfo.useLimits) {
- glyphOffset += gji.growLeftLimit;
- if (currInfo.absorb) {
- sideIncrement = gji.weight * currInfo.absorbedGapPerUnit;
- glyphOffset += sideIncrement;
- positionIncrement = glyphOffset;
- glyphOffset += sideIncrement;
- } else if (lastInfo != null && lastInfo.priority == currInfo.priority) {
- sideIncrement = gji.weight * lastInfo.absorbedGapPerUnit;
- glyphOffset += sideIncrement;
- positionIncrement = glyphOffset;
- glyphOffset += sideIncrement;
- } else {
- positionIncrement = glyphOffset;
- }
- glyphOffset += gji.growRightLimit;
- } else {
- sideIncrement = gji.weight * currInfo.gapPerUnit;
- glyphOffset += sideIncrement;
- positionIncrement = glyphOffset;
- glyphOffset += sideIncrement;
- }
-
- Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
- glyphPos.setLocation(glyphPos.getX() + positionIncrement, glyphPos.getY());
- getGlyphVector().setGlyphPosition(i, glyphPos);
- }
- } else {
- for (int i=firstGlyph; i<=lastGlyph; i++) {
- GlyphJustificationInfo gji = getGlyphJustificationInfos()[i];
- currInfo = jInfos[gji.shrinkPriority];
- if (currInfo == null) {
- // We still have to increment glyph position
- Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
- glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY());
- getGlyphVector().setGlyphPosition(i, glyphPos);
-
- continue;
- }
-
- if (currInfo.useLimits) {
- glyphOffset -= gji.shrinkLeftLimit;
- if (currInfo.absorb) {
- sideIncrement = gji.weight * currInfo.absorbedGapPerUnit;
- glyphOffset += sideIncrement;
- positionIncrement = glyphOffset;
- glyphOffset += sideIncrement;
- } else if (lastInfo != null && lastInfo.priority == currInfo.priority) {
- sideIncrement = gji.weight * lastInfo.absorbedGapPerUnit;
- glyphOffset += sideIncrement;
- positionIncrement = glyphOffset;
- glyphOffset += sideIncrement;
- } else {
- positionIncrement = glyphOffset;
- }
- glyphOffset -= gji.shrinkRightLimit;
- } else {
- sideIncrement = gji.weight * currInfo.gapPerUnit;
- glyphOffset += sideIncrement;
- positionIncrement = glyphOffset;
- glyphOffset += sideIncrement;
- }
-
- Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
- glyphPos.setLocation(glyphPos.getX() + positionIncrement, glyphPos.getY());
- getGlyphVector().setGlyphPosition(i, glyphPos);
- }
- }
-
-
- if (haveLast) { // Don't add padding after last char
- lastGlyph++;
-
- GlyphJustificationInfo gji = getGlyphJustificationInfos()[lastGlyph];
- currInfo = jInfos[gji.growPriority];
-
- if (currInfo != null) {
- if (currInfo.useLimits) {
- glyphOffset += firstInfo.grow ? gji.growLeftLimit : -gji.shrinkLeftLimit;
- if (currInfo.absorb) {
- glyphOffset += gji.weight * currInfo.absorbedGapPerUnit;
- } else if (lastInfo != null && lastInfo.priority == currInfo.priority) {
- glyphOffset += gji.weight * lastInfo.absorbedGapPerUnit;
- }
- } else {
- glyphOffset += gji.weight * currInfo.gapPerUnit;
- }
- }
-
- // Ajust positions of all glyphs after last glyph
- for (int i=lastGlyph; i<getGlyphVector().getNumGlyphs()+1; i++) {
- Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
- glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY());
- getGlyphVector().setGlyphPosition(i, glyphPos);
- }
- } else { // Update position after last glyph in glyph vector -
- // to get correct advance for it
- Point2D glyphPos = getGlyphVector().getGlyphPosition(lastGlyph+1);
- glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY());
- getGlyphVector().setGlyphPosition(lastGlyph+1, glyphPos);
- }
-
- gjis = null; // We don't need justification infos any more
- // Also we have to reset cached bounds and metrics
- this.visualBounds = null;
- this.logicalBounds = null;
-
- return glyphOffset; // How much our segment grown or shrunk
- }
- }
-
- public static class TextRunSegmentGraphic extends TextRunSegment {
- GraphicAttribute ga;
- int start;
- int length;
- float fullAdvance;
-
- TextRunSegmentGraphic(GraphicAttribute attr, int len, int start) {
- this.start = start;
- length = len;
- ga = attr;
- metrics = new BasicMetrics(ga);
- fullAdvance = ga.getAdvance() * length;
- }
-
- @Override
- public Object clone() {
- return new TextRunSegmentGraphic(ga, length, start);
- }
-
- // Renders this text run segment
- @Override
- void draw(Graphics2D g2d, float xOffset, float yOffset) {
- if (decoration != null) {
- TextDecorator.prepareGraphics(this, g2d, xOffset, yOffset);
- }
-
- float xPos = x + xOffset;
- float yPos = y + yOffset;
-
- for (int i=0; i < length; i++) {
- ga.draw(g2d, xPos, yPos);
- xPos += ga.getAdvance();
- }
-
- if (decoration != null) {
- TextDecorator.drawTextDecorations(this, g2d, xOffset, yOffset);
- TextDecorator.restoreGraphics(decoration, g2d);
- }
- }
-
- // Returns visual bounds of this segment
- @Override
- Rectangle2D getVisualBounds() {
- if (visualBounds == null) {
- Rectangle2D bounds = ga.getBounds();
-
- // First and last chars can be out of logical bounds, so we calculate
- // (bounds.getWidth() - ga.getAdvance()) which is exactly the difference
- bounds.setRect(
- bounds.getMinX() + x,
- bounds.getMinY() + y,
- bounds.getWidth() - ga.getAdvance() + getAdvance(),
- bounds.getHeight()
- );
- visualBounds = TextDecorator.extendVisualBounds(this, bounds, decoration);
- }
-
- return (Rectangle2D) visualBounds.clone();
- }
-
- @Override
- Rectangle2D getLogicalBounds() {
- if (logicalBounds == null) {
- logicalBounds =
- new Rectangle2D.Float(
- x, y - metrics.ascent,
- getAdvance(), metrics.ascent + metrics.descent
- );
- }
-
- return (Rectangle2D) logicalBounds.clone();
- }
-
- @Override
- float getAdvance() {
- return fullAdvance;
- }
-
- @Override
- float getAdvanceDelta(int start, int end) {
- return ga.getAdvance() * (end - start);
- }
-
- @Override
- int getCharIndexFromAdvance(float advance, int start) {
- start -= this.start;
-
- if (start < 0) {
- start = 0;
- }
-
- int charOffset = (int) (advance/ga.getAdvance());
-
- if (charOffset + start > length) {
- return length + this.start;
- }
- return charOffset + start + this.start;
- }
-
- @Override
- int getStart() {
- return start;
- }
-
- @Override
- int getEnd() {
- return start + length;
- }
-
- @Override
- int getLength() {
- return length;
- }
-
- @Override
- Shape getCharsBlackBoxBounds(int start, int limit) {
- start -= this.start;
- limit -= this.start;
-
- if (limit > length) {
- limit = length;
- }
-
- Rectangle2D charBounds = ga.getBounds();
- charBounds.setRect(
- charBounds.getX() + ga.getAdvance() * start + x,
- charBounds.getY() + y,
- charBounds.getWidth() + ga.getAdvance() * (limit - start),
- charBounds.getHeight()
- );
-
- return charBounds;
- }
-
- @Override
- float getCharPosition(int index) {
- index -= start;
- if (index > length) {
- index = length;
- }
-
- return ga.getAdvance() * index + x;
- }
-
- @Override
- float getCharAdvance(int index) {
- return ga.getAdvance();
- }
-
- @Override
- Shape getOutline() {
- AffineTransform t = AffineTransform.getTranslateInstance(x, y);
- return t.createTransformedShape(
- TextDecorator.extendOutline(this, getVisualBounds(), decoration)
- );
- }
-
- @Override
- boolean charHasZeroAdvance(int index) {
- return false;
- }
-
- @Override
- TextHitInfo hitTest(float hitX, float hitY) {
- hitX -= x;
-
- float tmp = hitX / ga.getAdvance();
- int hitIndex = Math.round(tmp);
-
- if (tmp > hitIndex) {
- return TextHitInfo.leading(hitIndex + this.start);
- }
- return TextHitInfo.trailing(hitIndex + this.start);
- }
-
- @Override
- void updateJustificationInfo(TextRunBreaker.JustificationInfo jInfo) {
- // Do nothing
- }
-
- @Override
- float doJustification(TextRunBreaker.JustificationInfo jInfos[]) {
- // Do nothing
- return 0;
- }
- }
-}