home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-03-20 | 21.8 KB | 822 lines |
- /*
- * @(#)TextLayoutGraphic.java 1.5 98/03/18
- *
- * Copyright 1998 by Sun Microsystems, Inc.,
- * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
- * All rights reserved.
- *
- * This software is the confidential and proprietary information
- * of Sun Microsystems, Inc. ("Confidential Information"). You
- * shall not disclose such Confidential Information and shall use
- * it only in accordance with the terms of the license agreement
- * you entered into with Sun.
- */
-
- /*
- * (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
- * (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
- *
- * The original version of this source code and documentation is
- * copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
- * of IBM. These materials are provided under terms of a License
- * Agreement between Taligent and Sun. This technology is protected
- * by multiple US and International patents.
- *
- * This notice and attribution to Taligent may not be removed.
- * Taligent is a registered trademark of Taligent, Inc.
- *
- */
-
- package java.awt.font;
-
- import java.awt.Image;
- import java.awt.Shape;
- import java.awt.Rectangle;
- import java.awt.Graphics;
- import java.awt.Graphics2D;
- import java.awt.Font;
-
- import java.text.AttributedCharacterIterator;
-
- import java.awt.geom.Rectangle2D;
-
- class TextLayoutGraphic implements TextLayoutComponent {
-
- /*
- * Leading shared by all graphics.
- */
- static final float GRAPHIC_LEADING = 2;
-
- /*
- * The graphic this component represents.
- */
- private /*final*/ GraphicAttribute fGraphic;
-
- /*
- * The number of graphics in this component.
- */
- private int fGraphicCount;
-
- /*
- * Advance of a single graphic.
- */
- private /*final*/ float fGraphicAdvance;
-
- /*
- * Array of advances of graphics. If null advances are fGraphicAdvance.
- */
- private float[] fAdvances = null;
-
- /*
- * Total advance of this component.
- */
- private float fTotalAdvance;
-
- /*
- * Amount to adjust drawing. Set in justification.
- */
- private float fAdjust = 0;
-
- /*
- * Levels of graphics. If null levels are all 0.
- */
- private byte[] fLevels;
-
- /*
- * Visual order of graphics. If null graphics are left-to-right.
- */
- private int[] fVisualOrder;
-
- /*
- * GlyphMetrics appropriate to graphic. Lazily evaluated
- * in getGlyphMetrics().
- */
- private GlyphMetrics fGlyphMetrics = null;
-
- /*
- * GlyphJustificationInfo appropriate to graphic. Lazily
- * evaluated in getGlyphJustificationInfo.
- */
- private GlyphJustificationInfo fGlyphJustInfo = null;
-
- // Several methods construct a copy of themselves and
- // mutate the copy.
-
- public static byte getBaselineFromGraphic(GraphicAttribute graphic) {
-
- byte alignment = (byte) graphic.getAlignment();
-
- if (alignment == GraphicAttribute.BOTTOM_ALIGNMENT ||
- alignment == GraphicAttribute.TOP_ALIGNMENT) {
-
- return Font.ROMAN_BASELINE;
- }
- else {
- return alignment;
- }
- }
-
- private TextLayoutGraphic(TextLayoutGraphic rhs) {
-
- fGraphic = rhs.fGraphic;
- fGraphicCount = rhs.fGraphicCount;
- fGraphicAdvance = rhs.fGraphicAdvance;
- fAdvances = rhs.fAdvances;
- fTotalAdvance = rhs.fTotalAdvance;
- fAdjust = rhs.fAdjust;
- fLevels = rhs.fLevels;
- fVisualOrder = rhs.fVisualOrder;
- fGlyphMetrics = rhs.fGlyphMetrics;
- fGlyphJustInfo = rhs.fGlyphJustInfo;
- }
-
- public TextLayoutGraphic(int contextStart,
- GraphicAttribute graphic,
- int runStart,
- int runLimit,
- int[] logicalOrder,
- byte[] levels) {
-
- runStart -= contextStart;
- runLimit -= contextStart;
-
- fGraphic = graphic;
-
- fGraphicCount = runLimit - runStart;
-
- if (logicalOrder != null) {
- int[] subOrder = GlyphSet.getNormalizedOrder(
- logicalOrder, levels, runStart, runLimit);
- fVisualOrder = GlyphSet.getInverseOrder(subOrder);
- }
- else {
- fVisualOrder = null;
- }
-
- if (levels != null) {
- fLevels = new byte[fGraphicCount];
- System.arraycopy(levels, runStart, fLevels, 0, fGraphicCount);
- }
- else {
- fLevels = null;
- }
-
- fGraphicAdvance = fGraphic.getAdvance();
- fTotalAdvance = fGraphicAdvance * fGraphicCount;
- }
-
- private final void checkIndex(int index) {
-
- if (index < 0 || index >= fGraphicCount) {
- throw new IllegalArgumentException("index is out of range.");
- }
- }
-
- public float getAdvance() {
-
- return fTotalAdvance;
- }
-
- public float getAscent() {
-
- byte alignment = (byte) fGraphic.getAlignment();
-
- if (alignment == GraphicAttribute.BOTTOM_ALIGNMENT ||
- alignment == GraphicAttribute.TOP_ALIGNMENT) {
-
- return 0;
- }
- else {
- return fGraphic.getAscent();
- }
- }
-
- public float getDescent(float ascent) {
-
- byte alignment = (byte) fGraphic.getAlignment();
-
- if (alignment == GraphicAttribute.BOTTOM_ALIGNMENT ||
- alignment == GraphicAttribute.TOP_ALIGNMENT) {
-
- float height = fGraphic.getAscent() + fGraphic.getDescent();
- return Math.max(0, height-ascent);
- }
- else {
-
- return fGraphic.getDescent();
- }
- }
-
- public float getLeading() {
-
- return GRAPHIC_LEADING;
- }
-
- public int getNumGlyphs() {
-
- return fGraphicCount;
- }
-
- public int getNumCharacters() {
-
- return fGraphicCount;
- }
-
- public byte getBaseline() {
-
- return getBaselineFromGraphic(fGraphic);
- }
-
- public float getXAdjust() {
-
- return fAdjust;
- }
-
- public float getGlyphXAdvance(int index) {
-
- return getGlyphAdvance(index);
- }
-
- public float getYAdjust() {
-
- return 0;
- }
-
- public float getGlyphYAdvance(int index) {
-
- checkIndex(index);
- return 0;
- }
-
- public float getGlyphAdvance(int index) {
-
- checkIndex(index);
- if (fAdvances == null) {
- return fGraphicAdvance;
- }
- else {
- return fAdvances[index];
- }
- }
-
- public int visualToLogicalIndex(int index) {
-
- checkIndex(index);
- if (fVisualOrder == null) {
- return index;
- }
- else {
- return fVisualOrder[index];
- }
- }
-
- public byte getLevel(int index) {
-
- checkIndex(index);
- if (fLevels == null) {
- return 0;
- }
- else {
- return fLevels[index];
- }
- }
-
- public boolean isCompletelyLTR() {
-
- return (fLevels == null);
- }
-
- public TextLayoutComponent applyJustification(
- float[] deltas, int index, boolean[] shouldRejustify) {
-
- shouldRejustify[0] = false;
-
- TextLayoutGraphic justified = new TextLayoutGraphic(this);
-
- justified.fTotalAdvance += deltas[index];
- justified.fAdjust = deltas[index++];
-
- if (justified.fAdvances == null) {
- justified.fAdvances = new float[fGraphicCount];
- for (int i=0; i < fGraphicCount; i++) {
- justified.fAdvances[i] = fGraphicAdvance;
- }
- }
-
- for (int i=0; i < fGraphicCount-1; i++) {
-
- justified.fTotalAdvance += deltas[index];
- justified.fAdvances[i] += deltas[index++];
-
- justified.fTotalAdvance += deltas[index];
- justified.fAdvances[i] += deltas[index++];
- }
-
- justified.fTotalAdvance += deltas[index];
- justified.fAdvances[fGraphicCount-1] += deltas[index];
-
- return justified;
- }
-
- public float getAdvanceBetween(int start, int limit) {
-
- if ((start < 0) || (start > limit) || (limit > fGraphicCount)) {
- throw new IllegalArgumentException(
- "Bad range passed to TextLayoutGraphic.getAdvanceBetween.");
- }
-
- float rval = 0;
-
- if (fAdvances == null) {
- rval += fGraphicAdvance * (limit-start);
- }
- else {
- for (int i=start; i<limit; i++) {
- rval += fAdvances[i];
- }
- }
-
- return rval;
- }
-
- public int getLineBreakIndex(int start, float hitAdvance) {
-
- checkIndex(start);
-
- if (hitAdvance >= fTotalAdvance)
- return fGraphicCount;
-
- if (start == 0) {
- hitAdvance -= fAdjust;
- }
-
- if (fAdvances == null) {
-
- int numGraphics = (int) (hitAdvance / fGraphicAdvance);
- return start + numGraphics;
- }
- else {
-
- int i;
- for (i = start; i < fGraphicCount; i++) {
-
- hitAdvance -= fAdvances[i];
- if (hitAdvance < 0) {
- return i;
- }
- }
-
- return i;
- }
- }
-
- public TextLayoutComponent subset(int start, int limit) {
-
- if ((start < 0) || (start >= limit) || (limit > fGraphicCount)) {
- throw new IllegalArgumentException(
- "Bad range passed to TextLayoutGraphic.subset.");
- }
-
- if (start == 0 && limit == fGraphicCount) {
- return this;
- }
-
- TextLayoutGraphic subset = new TextLayoutGraphic(this);
-
- subset.fGraphicCount = (limit-start);
-
- // copy advances, levels, visualOrder if they exist
- if (fAdvances != null) {
-
- subset.fAdvances = new float[limit-start];
- System.arraycopy(fAdvances, start, subset.fAdvances, 0, (limit-start));
- }
-
- if (fLevels != null) {
-
- subset.fLevels = new byte[limit-start];
- System.arraycopy(fLevels, start, subset.fLevels, 0, (limit-start));
- }
-
- if (fVisualOrder != null) {
-
- int[] inverse = GlyphSet.getInverseOrder(fVisualOrder);
- int[] normalizedLogToVis =
- GlyphSet.getNormalizedOrder(inverse, fLevels, start, limit);
-
- subset.fVisualOrder = GlyphSet.getInverseOrder(normalizedLogToVis);
- }
-
- // compute total advance
- subset.fAdjust = (start==0)? fAdjust : 0;
- float subsetAdvance = subset.fAdjust;
-
- if (fAdvances == null) {
- subsetAdvance += fGraphicAdvance * fGraphicCount;
- }
- else {
- for (int i=start; i < limit; i++) {
- subsetAdvance += fAdvances[i];
- }
- }
-
- subset.fTotalAdvance = subsetAdvance;
-
- return subset;
- }
-
- public TextLayoutComponent insertChar(
- AttributedCharacterIterator newText,
- int start, int limit,
- int insertPos,
- int[] order,
- byte[] levels) {
-
- if (insertPos < start || insertPos >= limit) {
- throw new IllegalArgumentException("insertPos is out of range.");
- }
-
- int newLength = limit - start;
-
- if (newLength != fGraphicCount + 1) {
- throw new IllegalArgumentException(
- "TextLayoutGraphic.insertChar can only insert a single character.");
- }
-
- TextLayoutGraphic newGraphic = new TextLayoutGraphic(this);
-
- // set new count, copy order and levels, modify advances array,
- // recompute fTotalAdvance
-
- newGraphic.fGraphicCount = newLength;
-
- // make start, limit, insertPos relative to context start
- {
- int textStart = newText.getBeginIndex();
- start -= textStart;
- limit -= textStart;
- insertPos -= textStart;
- }
-
- if (order == null) {
- newGraphic.fVisualOrder = null;
- }
- else {
- int[] logToVis =
- GlyphSet.getNormalizedOrder(order, levels, start, limit);
- newGraphic.fVisualOrder = GlyphSet.getInverseOrder(logToVis);
- }
-
- if (levels == null) {
- newGraphic.fLevels = null;
- }
- else {
- byte[] newLevels = new byte[newLength];
- System.arraycopy(levels, start, newLevels, 0, newLength);
- newGraphic.fLevels = newLevels;
- }
-
- if (fAdvances != null) {
- float[] newAdvances = new float[newLength];
- System.arraycopy(fAdvances, 0, newAdvances, 0, insertPos-start);
- System.arraycopy(fAdvances, insertPos-start,
- newAdvances, insertPos-start+1, limit-insertPos-1);
- newAdvances[insertPos] = fGraphicAdvance;
- newGraphic.fAdvances = newAdvances;
- }
-
- newGraphic.fTotalAdvance += fGraphicAdvance;
-
- return newGraphic;
- }
-
- public TextLayoutComponent deleteChar(
- AttributedCharacterIterator newText,
- int start, int limit,
- int deletePos,
- int[] order,
- byte[] levels) {
-
- if (deletePos < start || deletePos > limit) {
- throw new IllegalArgumentException(
- "insertPos is out of range in TextLayoutComponent.deleteChar.");
- }
-
- int newLength = limit-start;
-
- if (newLength != fGraphicCount-1) {
- throw new IllegalArgumentException(
- "TextLayoutComponent.deleteChar can only delete a single character.");
- }
-
- if (newLength == 0) {
- throw new IllegalArgumentException(
- "TextLayoutComponent.deleteChar was asked to produce a 0-length glyphset.");
- }
-
- TextLayoutGraphic newGraphic = new TextLayoutGraphic(this);
-
- // set new count, copy order and levels, modify advances array,
- // recompute fTotalAdvance
-
- newGraphic.fGraphicCount = newLength;
-
- // make start, limit, insertPos relative to context start
- {
- int textStart = newText.getBeginIndex();
- start -= textStart;
- limit -= textStart;
- deletePos -= textStart;
- }
-
- if (order == null) {
- newGraphic.fVisualOrder = null;
- }
- else {
- int[] logToVis =
- GlyphSet.getNormalizedOrder(order, levels, start, limit);
- newGraphic.fVisualOrder = GlyphSet.getInverseOrder(logToVis);
- }
-
-
- if (levels == null) {
- newGraphic.fLevels = null;
- }
- else {
- byte[] newLevels = new byte[newLength];
- System.arraycopy(levels, start, newLevels, 0, newLength);
- newGraphic.fLevels = newLevels;
- }
-
- if (fAdvances == null) {
- newGraphic.fTotalAdvance -= fGraphicAdvance;
- }
- else {
- newGraphic.fTotalAdvance -= fAdvances[deletePos-start];
- float[] newAdvances = new float[newLength];
- int gsDeletePos = deletePos-start;
-
- System.arraycopy(fAdvances, 0, newAdvances, 0, gsDeletePos);
- System.arraycopy(fAdvances, gsDeletePos+1,
- newAdvances, gsDeletePos, newLength-gsDeletePos);
- newGraphic.fAdvances = newAdvances;
- }
-
- if (deletePos != start) {
- newGraphic.fTotalAdvance -= newGraphic.fAdjust;
- newGraphic.fAdjust = 0;
- }
-
- return newGraphic;
- }
-
-
- public TextLayoutComponent reshape(
- AttributedCharacterIterator newText,
- int start, int limit,
- int changePos,
- int[] order,
- byte[] levels) {
-
- return this;
- }
-
- private float getGraphicYShift(TextLayout hostLayout) {
-
- float dy = 0;
-
- byte alignment = (byte) fGraphic.getAlignment();
-
- if (alignment == GraphicAttribute.BOTTOM_ALIGNMENT ||
- alignment == GraphicAttribute.TOP_ALIGNMENT) {
-
- byte baseline = getBaseline();
- float[] baselineOffsets = hostLayout.getBaselineOffsets();
-
- if (alignment == GraphicAttribute.TOP_ALIGNMENT) {
- dy = baselineOffsets[baseline] -
- hostLayout.getAscent() +
- fGraphic.getAscent();
- }
- else {
- dy = baselineOffsets[baseline] +
- hostLayout.getDescent() -
- fGraphic.getDescent();
- }
- }
-
- return dy;
- }
-
- public void draw(Graphics2D graphics, float x, float y, TextLayout hostLayout) {
-
- float locX = x, locY = y;
-
- locY += getGraphicYShift(hostLayout);
-
- for (int i=0; i < fGraphicCount; i++) {
-
- fGraphic.draw(graphics, x, y);
-
- if (fAdvances != null) {
- if (fVisualOrder != null) {
- locX += fAdvances[fVisualOrder[i]];
- }
- else {
- locX += fAdvances[i];
- }
- }
- else {
- locX += fGraphicAdvance;
- }
- }
- }
-
- public Rectangle2D getBounds(TextLayout hostLayout) {
-
- Rectangle2D graphicBounds = fGraphic.getBounds();
- float left = fAdjust + (float) graphicBounds.getLeft();
-
- float right = fAdjust + getAdvanceBetween(0, fGraphicCount-1);
- right += graphicBounds.getRight();
-
- float dy = getGraphicYShift(hostLayout);
-
- return new Rectangle2D.Float(
- left, (float) (graphicBounds.getTop()+dy),
- right-left, (float) (graphicBounds.getHeight()));
- }
-
- public TextLayoutComponent setDirection(boolean leftToRight) {
-
- if (leftToRight && fLevels == null && fVisualOrder == null) {
- return this;
- }
-
- TextLayoutGraphic dir = new TextLayoutGraphic(this);
-
- if (leftToRight) {
- dir.fLevels = null;
- dir.fVisualOrder = null;
- }
- else {
- dir.fLevels = new byte[fGraphicCount];
- dir.fVisualOrder = new int[fGraphicCount];
-
- for (int i=0; i < fGraphicCount; i++) {
- dir.fLevels[i] = (byte) 1;
- dir.fVisualOrder[i] = (fGraphicCount-i-1);
- }
- }
-
- return dir;
- }
-
- /**
- * Return GlyphMetrics for glyph at index.
- * Index is NOT a glyph code.
- */
- public GlyphMetrics getGlyphMetrics(int index, TextLayout hostLayout) {
-
- checkIndex(index);
-
- if (fGlyphMetrics == null) {
-
- Rectangle2D bounds = fGraphic.getBounds();
-
- float dy = getGraphicYShift(hostLayout);
-
- if (dy != 0) {
- // really protect lazy subclassers of GraphicAttribute?
- // ok since we only do this once
-
- // copy ctor would be nice...
- Rectangle2D temp = new Rectangle2D.Float();
- temp.setRect(bounds);
- bounds = temp;
-
- bounds.setRect(bounds.getX(), bounds.getY()+dy,
- bounds.getWidth(), bounds.getHeight());
- }
-
- fGlyphMetrics = new GlyphMetrics(fGraphicAdvance,
- bounds,
- GlyphMetrics.STANDARD);
- }
-
- return fGlyphMetrics;
- }
-
- public boolean isComponent(int index) {
-
- checkIndex(index);
- return false;
- }
-
- /**
- * Return GlyphJustificationInfo for glyph at index.
- * Index is NOT a glyph code.
- */
- public GlyphJustificationInfo getGlyphJustificationInfo(int index) {
-
- checkIndex(index);
- return fGraphic.getJustificationInfo();
- }
-
-
- public int hashCode() {
-
- return fGraphic.hashCode();
- }
-
- public boolean equals(TextLayoutComponent set) {
-
- try {
- return equals((TextLayoutGraphic) set);
- }
- catch(ClassCastException e) {
- return false;
- }
- }
-
- public boolean equals(TextLayoutGraphic rhs) {
-
- if (rhs == null) {
- return false;
- }
-
- if (rhs == this) {
- return true;
- }
-
- // compare graphics, graphic count, advances (if any),
- // total advance, adjust, levels (if any),
- // visual order (if any)
-
- if (!fGraphic.equals(rhs.fGraphic)) {
- return false;
- }
-
- if (fGraphicCount != rhs.fGraphicCount) {
- return false;
- }
-
- if (fAdjust != rhs.fAdjust) {
- return false;
- }
-
- if (fTotalAdvance != rhs.fTotalAdvance) {
- return false;
- }
-
- if (fAdvances == null ^ rhs.fAdvances == null) {
- return false;
- }
-
- if (fLevels == null ^ rhs.fLevels == null) {
- return false;
- }
-
- if (fVisualOrder == null ^ rhs.fVisualOrder == null) {
- return false;
- }
-
- if (fAdvances != null) {
- if (fAdvances != rhs.fAdvances) {
- for (int i=0; i < fGraphicCount; i++) {
- if (fAdvances[i] != rhs.fAdvances[i]) {
- return false;
- }
- }
- }
- }
-
- if (fLevels != null) {
- if (fLevels != rhs.fLevels) {
- for (int i=0; i < fGraphicCount; i++) {
- if (fLevels[i] != rhs.fLevels[i]) {
- return false;
- }
- }
- }
- }
-
- if (fVisualOrder != null) {
- if (fVisualOrder != rhs.fVisualOrder) {
- for (int i=0; i < fGraphicCount; i++) {
- if (fVisualOrder[i] != rhs.fVisualOrder[i]) {
- return false;
- }
- }
- }
- }
-
- return true;
- }
-
- public float getItalicAngle() {
-
- return 0;
- }
- }
-