0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017: /**
0018: * @author Ilya S. Okomin
0019: * @version $Revision$
0020: */package org.apache.harmony.awt.gl.font;
0021:
0022: import java.awt.Font;
0023: import java.awt.Rectangle;
0024: import java.awt.Shape;
0025: import java.awt.font.FontRenderContext;
0026: import java.awt.font.GlyphJustificationInfo;
0027: import java.awt.font.GlyphMetrics;
0028: import java.awt.font.GlyphVector;
0029: import java.awt.geom.AffineTransform;
0030: import java.awt.geom.GeneralPath;
0031: import java.awt.geom.Point2D;
0032: import java.awt.geom.Rectangle2D;
0033:
0034: import org.apache.harmony.awt.internal.nls.Messages;
0035:
0036: /**
0037: * GlyphVector implementation
0038: */
0039: public class CommonGlyphVector extends GlyphVector {
0040:
0041: // array of transforms of glyphs in GlyphVector
0042: protected AffineTransform[] glsTransforms;
0043:
0044: // array of chars defined in constructor
0045: public char[] charVector;
0046:
0047: // array of Glyph objects, that describe information about glyphs
0048: public Glyph[] vector;
0049:
0050: // array of default positions of glyphs in GlyphVector
0051: // without applying GlyphVector's transform
0052: float[] defaultPositions;
0053:
0054: // array of logical positions of glyphs in GlyphVector
0055:
0056: float[] logicalPositions;
0057:
0058: // array of visual (real) positions of glyphs in GlyphVector
0059: public float[] visualPositions;
0060:
0061: // FontRenderContext for this vector.
0062: protected FontRenderContext vectorFRC;
0063:
0064: // layout flags mask
0065: protected int layoutFlags = 0;
0066:
0067: // array of cached glyph outlines
0068: protected Shape[] gvShapes;
0069:
0070: FontPeerImpl peer;
0071:
0072: // font corresponding to the GlyphVector
0073: Font font;
0074:
0075: // ascent of the font
0076: float ascent;
0077:
0078: // height of the font
0079: float height;
0080:
0081: // leading of the font
0082: float leading;
0083:
0084: // descent of the font
0085: float descent;
0086:
0087: // transform of the GlyphVector
0088: AffineTransform transform;
0089:
0090: /**
0091: * Creates new CommonGlyphVector object from the specified parameters.
0092: *
0093: * @param chars an array of chars
0094: * @param frc FontRenderContext object
0095: * @param fnt Font object
0096: * @param flags layout flags
0097: */
0098: @SuppressWarnings("deprecation")
0099: public CommonGlyphVector(char[] chars, FontRenderContext frc,
0100: Font fnt, int flags) {
0101: int len = chars.length;
0102:
0103: this .font = fnt;
0104: this .transform = fnt.getTransform();
0105: this .peer = (FontPeerImpl) fnt.getPeer();
0106:
0107: gvShapes = new Shape[len];
0108:
0109: // !! As pointed in API documentation for the
0110: // getGlyphPosisitions(int index,int numEntries, float[] positionReturn)
0111: // and getGlyphPosition(int index) methods, if the index is equals to
0112: // the number of glyphs the position after the last glyph must be
0113: // returned, thus there are n+1 positions and last (n+1) position
0114: // points to the end of GlyphVector.
0115:
0116: logicalPositions = new float[(len + 1) << 1];
0117: visualPositions = new float[(len + 1) << 1];
0118: defaultPositions = new float[(len + 1) << 1];
0119:
0120: // glsTransforms = new AffineTransform[len];
0121:
0122: this .charVector = chars;
0123: this .vectorFRC = frc;
0124: LineMetricsImpl lmImpl = (LineMetricsImpl) peer
0125: .getLineMetrics();
0126:
0127: this .ascent = lmImpl.getAscent();
0128: this .height = lmImpl.getHeight();
0129: this .leading = lmImpl.getLeading();
0130: this .descent = lmImpl.getDescent();
0131: this .layoutFlags = flags;
0132:
0133: if ((flags & Font.LAYOUT_RIGHT_TO_LEFT) != 0) {
0134: char vector[] = new char[len];
0135: for (int i = 0; i < len; i++) {
0136: vector[i] = chars[len - i - 1];
0137: }
0138: this .vector = peer.getGlyphs(vector);
0139:
0140: } else {
0141: this .vector = peer.getGlyphs(chars);
0142: }
0143:
0144: this .glsTransforms = new AffineTransform[len];
0145:
0146: setDefaultPositions();
0147: performDefaultLayout();
0148: }
0149:
0150: /**
0151: * Creates new CommonGlyphVector object from the specified parameters.
0152: * Layout flags set to default.
0153: *
0154: * @param chars an array of chars
0155: * @param frc FontRenderContext object
0156: * @param fnt Font object
0157: */
0158: public CommonGlyphVector(char[] chars, FontRenderContext frc,
0159: Font fnt) {
0160: this (chars, frc, fnt, 0);
0161: }
0162:
0163: /**
0164: * Creates new CommonGlyphVector object from the specified parameters.
0165: * Layout flags set to default.
0166: *
0167: * @param str specified string
0168: * @param frc FontRenderContext object
0169: * @param fnt Font object
0170: */
0171: public CommonGlyphVector(String str, FontRenderContext frc, Font fnt) {
0172: this (str.toCharArray(), frc, fnt, 0);
0173: }
0174:
0175: /**
0176: * Creates new CommonGlyphVector object from the specified parameters.
0177: *
0178: * @param str specified string
0179: * @param frc FontRenderContext object
0180: * @param fnt Font object
0181: * @param flags layout flags
0182: */
0183: public CommonGlyphVector(String str, FontRenderContext frc,
0184: Font fnt, int flags) {
0185: this (str.toCharArray(), frc, fnt, flags);
0186: }
0187:
0188: /**
0189: * Set array of logical positions of the glyphs to
0190: * default with their default advances and height.
0191: */
0192: void setDefaultPositions() {
0193: int len = getNumGlyphs();
0194:
0195: // First [x,y] is set into [0,0] position
0196: // for this reason start index is 1
0197: for (int i = 1; i <= len; i++) {
0198: int idx = i << 1;
0199: float advanceX = vector[i - 1].getGlyphPointMetrics()
0200: .getAdvanceX();
0201: float advanceY = vector[i - 1].getGlyphPointMetrics()
0202: .getAdvanceY();
0203:
0204: defaultPositions[idx] = defaultPositions[idx - 2]
0205: + advanceX;
0206: defaultPositions[idx + 1] = defaultPositions[idx - 1]
0207: + advanceY;
0208:
0209: }
0210: transform.transform(defaultPositions, 0, logicalPositions, 0,
0211: getNumGlyphs() + 1);
0212:
0213: }
0214:
0215: /**
0216: * Returnes the pixel bounds of this GlyphVector rendered at the
0217: * specified x,y location with the given FontRenderContext.
0218: *
0219: * @param frc a FontRenderContext that is used
0220: * @param x specified x coordinate value
0221: * @param y specified y coordinate value
0222: * @return a Rectangle that bounds pixels of this GlyphVector
0223: */
0224: @Override
0225: public Rectangle getPixelBounds(FontRenderContext frc, float x,
0226: float y) {
0227:
0228: double xM, yM, xm, ym;
0229:
0230: double minX = 0;
0231: double minY = 0;
0232: double maxX = 0;
0233: double maxY = 0;
0234:
0235: for (int i = 0; i < this .getNumGlyphs(); i++) {
0236: Rectangle glyphBounds = this .getGlyphPixelBounds(i, frc, 0,
0237: 0);
0238: xm = glyphBounds.getMinX();
0239: ym = glyphBounds.getMinY();
0240: xM = glyphBounds.getMaxX();
0241: yM = glyphBounds.getMaxY();
0242:
0243: if (i == 0) {
0244: minX = xm;
0245: minY = ym;
0246: maxX = xM;
0247: maxY = yM;
0248: }
0249:
0250: if (minX > xm) {
0251: minX = xm;
0252: }
0253: if (minY > ym) {
0254: minY = ym;
0255: }
0256: if (maxX < xM) {
0257: maxX = xM;
0258: }
0259: if (maxY < yM) {
0260: maxY = yM;
0261: }
0262: }
0263: return new Rectangle((int) (minX + x), (int) (minY + y),
0264: (int) (maxX - minX), (int) (maxY - minY));
0265:
0266: }
0267:
0268: /**
0269: * Returns the visual bounds of this GlyphVector.
0270: * The visual bounds is the bounds of the total outline of
0271: * this GlyphVector.
0272: * @return a Rectangle2D that id the visual bounds of this GlyphVector
0273: */
0274: @Override
0275: public Rectangle2D getVisualBounds() {
0276: float xM, yM, xm, ym;
0277: float minX = 0;
0278: float minY = 0;
0279: float maxX = 0;
0280: float maxY = 0;
0281: boolean firstIteration = true;
0282:
0283: for (int i = 0; i < this .getNumGlyphs(); i++) {
0284: Rectangle2D bounds = this .getGlyphVisualBounds(i)
0285: .getBounds2D();
0286: if (bounds.getWidth() == 0) {
0287: continue;
0288: }
0289: xm = (float) bounds.getX();
0290: ym = (float) bounds.getY();
0291:
0292: xM = (float) (xm + bounds.getWidth());
0293:
0294: yM = ym + (float) bounds.getHeight();
0295:
0296: if (firstIteration) {
0297: minX = xm;
0298: minY = ym;
0299: maxX = xM;
0300: maxY = yM;
0301: firstIteration = false;
0302: } else {
0303: if (minX > xm) {
0304: minX = xm;
0305: }
0306: if (minY > ym) {
0307: minY = ym;
0308: }
0309: if (maxX < xM) {
0310: maxX = xM;
0311: }
0312: if (maxY < yM) {
0313: maxY = yM;
0314: }
0315:
0316: }
0317: }
0318:
0319: return (this .getNumGlyphs() != 0) ? new Rectangle2D.Float(minX,
0320: minY, (maxX - minX), (maxY - minY)) : null;
0321: }
0322:
0323: /**
0324: * Sets new position to the specified glyph.
0325: */
0326: @Override
0327: public void setGlyphPosition(int glyphIndex, Point2D newPos) {
0328: if ((glyphIndex > vector.length) || (glyphIndex < 0)) {
0329: // awt.43=glyphIndex is out of vector's limits
0330: throw new IndexOutOfBoundsException(Messages
0331: .getString("awt.43")); //$NON-NLS-1$
0332: }
0333: float x = (float) newPos.getX();
0334: float y = (float) newPos.getY();
0335: int index = glyphIndex << 1;
0336:
0337: if ((x != visualPositions[index])
0338: || (y != visualPositions[index + 1])) {
0339: visualPositions[index] = x;
0340: visualPositions[index + 1] = y;
0341: layoutFlags = layoutFlags | FLAG_HAS_POSITION_ADJUSTMENTS;
0342: }
0343:
0344: }
0345:
0346: /**
0347: * Returns the position of the specified glyph relative to the origin of
0348: * this GlyphVector
0349: * @return a Point2D that the origin of the glyph with specified index
0350: */
0351: @Override
0352: public Point2D getGlyphPosition(int glyphIndex) {
0353: if ((glyphIndex > vector.length) || (glyphIndex < 0)) {
0354: // awt.43=glyphIndex is out of vector's limits
0355: throw new IndexOutOfBoundsException(Messages
0356: .getString("awt.43")); //$NON-NLS-1$
0357: }
0358: int index = glyphIndex << 1;
0359: Point2D pos = new Point2D.Float(visualPositions[index],
0360: visualPositions[index + 1]);
0361:
0362: // For last position we don't have to transform !!
0363: if (glyphIndex == vector.length) {
0364: return pos;
0365: }
0366:
0367: AffineTransform at = getGlyphTransform(glyphIndex);
0368: if ((at == null) || (at.isIdentity())) {
0369: return pos;
0370: }
0371:
0372: pos.setLocation(pos.getX() + at.getTranslateX(), pos.getY()
0373: + at.getTranslateY());
0374:
0375: return pos;
0376: }
0377:
0378: /**
0379: * Sets new transform to the specified glyph.
0380: *
0381: * @param glyphIndex specified index of the glyph
0382: * @param trans AffineTransform of the glyph with specified index
0383: */
0384: @Override
0385: public void setGlyphTransform(int glyphIndex, AffineTransform trans) {
0386: if ((glyphIndex >= vector.length) || (glyphIndex < 0)) {
0387: // awt.43=glyphIndex is out of vector's limits
0388: throw new IndexOutOfBoundsException(Messages
0389: .getString("awt.43")); //$NON-NLS-1$
0390: }
0391:
0392: if ((trans == null) || (trans.isIdentity())) {
0393: glsTransforms[glyphIndex] = null;
0394: } else {
0395: glsTransforms[glyphIndex] = new AffineTransform(trans);
0396: layoutFlags = layoutFlags | FLAG_HAS_TRANSFORMS;
0397: }
0398: }
0399:
0400: /**
0401: * Returns the affine transform of the specified glyph.
0402: *
0403: * @param glyphIndex specified index of the glyph
0404: * @return an AffineTransform of the glyph with specified index
0405: */
0406: @Override
0407: public AffineTransform getGlyphTransform(int glyphIndex) {
0408: if ((glyphIndex >= this .vector.length) || (glyphIndex < 0)) {
0409: // awt.43=glyphIndex is out of vector's limits
0410: throw new IndexOutOfBoundsException(Messages
0411: .getString("awt.43")); //$NON-NLS-1$
0412: }
0413: return this .glsTransforms[glyphIndex];
0414: }
0415:
0416: /**
0417: * Returns the metrics of the specified glyph.
0418: *
0419: * @param glyphIndex specified index of the glyph
0420: */
0421: @Override
0422: public GlyphMetrics getGlyphMetrics(int glyphIndex) {
0423:
0424: if ((glyphIndex < 0) || ((glyphIndex) >= this .getNumGlyphs())) {
0425: // awt.43=glyphIndex is out of vector's limits
0426: throw new IndexOutOfBoundsException(Messages
0427: .getString("awt.43")); //$NON-NLS-1$
0428: }
0429: // TODO: is there a sence in GlyphMetrics
0430: // if certain glyph or Font has a transform??
0431: return this .vector[glyphIndex].getGlyphMetrics();
0432: }
0433:
0434: /**
0435: * Returns a justification information for the glyph with specified glyph
0436: * index.
0437: * @param glyphIndex index of a glyph which GlyphJustificationInfo is to be
0438: * received
0439: * @return a GlyphJustificationInfo object that contains glyph justification
0440: * properties of the specified glyph
0441: */
0442: @Override
0443: public GlyphJustificationInfo getGlyphJustificationInfo(
0444: int glyphIndex) {
0445: // TODO : Find out the source of Justification info
0446: if (true) {
0447: throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
0448: }
0449: return null;
0450: }
0451:
0452: /**
0453: * Returns the FontRenderContext parameter of this GlyphVector.
0454: */
0455: @Override
0456: public FontRenderContext getFontRenderContext() {
0457: return this .vectorFRC;
0458: }
0459:
0460: /**
0461: * Returns the visual bounds of the specified glyph.
0462: *
0463: * @param glyphIndex specified index of the glyph
0464: */
0465: @Override
0466: public Shape getGlyphVisualBounds(int glyphIndex) {
0467: if ((glyphIndex < 0) || (glyphIndex >= this .getNumGlyphs())) {
0468: // awt.43=glyphIndex is out of vector's limits
0469: throw new IndexOutOfBoundsException(Messages
0470: .getString("awt.43")); //$NON-NLS-1$
0471: }
0472:
0473: int idx = glyphIndex << 1;
0474:
0475: AffineTransform fontTransform = this .transform;
0476: double xOffs = fontTransform.getTranslateX();
0477: double yOffs = fontTransform.getTranslateY();
0478:
0479: if (vector[glyphIndex].getWidth() == 0) {
0480: return new Rectangle2D.Float((float) xOffs, (float) yOffs,
0481: 0, 0);
0482: }
0483:
0484: AffineTransform at = AffineTransform.getTranslateInstance(
0485: xOffs, yOffs);
0486: AffineTransform glyphTransform = getGlyphTransform(glyphIndex);
0487:
0488: if (transform.isIdentity()
0489: && ((glyphTransform == null) || glyphTransform
0490: .isIdentity())) {
0491: Rectangle2D blackBox = vector[glyphIndex].getGlyphMetrics()
0492: .getBounds2D();
0493: at
0494: .translate(visualPositions[idx],
0495: visualPositions[idx + 1]);
0496: return (at.createTransformedShape(blackBox));
0497: }
0498:
0499: GeneralPath shape = (GeneralPath) this
0500: .getGlyphOutline(glyphIndex);
0501: shape.transform(at);
0502: return shape.getBounds2D();
0503: }
0504:
0505: /**
0506: * Returnes the pixel bounds of the specified glyph within GlyphVector
0507: * rendered at the specified x,y location.
0508: *
0509: * @param glyphIndex index of the glyph
0510: * @param frc a FontRenderContext that is used
0511: * @param x specified x coordinate value
0512: * @param y specified y coordinate value
0513: * @return a Rectangle that bounds pixels of the specified glyph
0514: */
0515: @Override
0516: public Rectangle getGlyphPixelBounds(int glyphIndex,
0517: FontRenderContext frc, float x, float y) {
0518:
0519: if ((glyphIndex < 0) || (glyphIndex >= this .getNumGlyphs())) {
0520: // awt.43=glyphIndex is out of vector's limits
0521: throw new IndexOutOfBoundsException(Messages
0522: .getString("awt.43")); //$NON-NLS-1$
0523: }
0524:
0525: int idx = glyphIndex << 1;
0526:
0527: if (vector[glyphIndex].getWidth() == 0) {
0528: AffineTransform fontTransform = this .transform;
0529: double xOffs = x + visualPositions[idx]
0530: + fontTransform.getTranslateX();
0531: double yOffs = y + visualPositions[idx + 1]
0532: + fontTransform.getTranslateY();
0533: return new Rectangle((int) xOffs, (int) yOffs, 0, 0);
0534: }
0535:
0536: GeneralPath shape = (GeneralPath) this
0537: .getGlyphOutline(glyphIndex);
0538:
0539: AffineTransform at = AffineTransform.getTranslateInstance(x, y);
0540:
0541: if (frc != null) {
0542: at.concatenate(frc.getTransform());
0543:
0544: /* if (frc.usesFractionalMetrics()){
0545: shape.transform(at);
0546: Rectangle2D bounds = shape.getBounds2D();
0547: Rectangle rect = new Rectangle();
0548: rect.setRect(bounds);
0549: return rect;
0550: }*/
0551: }
0552:
0553: shape.transform(at);
0554:
0555: Rectangle bounds = shape.getBounds();
0556: return new Rectangle((int) bounds.getX(), (int) bounds.getY(),
0557: (int) bounds.getWidth() - 1,
0558: (int) bounds.getHeight() - 1);
0559: }
0560:
0561: /**
0562: * Returns a Shape that encloses specified glyph.
0563: *
0564: * @param glyphIndex specified index of the glyph
0565: */
0566: @Override
0567: public Shape getGlyphOutline(int glyphIndex) {
0568: if ((glyphIndex < 0) || (glyphIndex >= this .getNumGlyphs())) {
0569: // awt.43=glyphIndex is out of vector's limits
0570: throw new IndexOutOfBoundsException(Messages
0571: .getString("awt.43")); //$NON-NLS-1$
0572: }
0573:
0574: if (gvShapes[glyphIndex] == null) {
0575: gvShapes[glyphIndex] = vector[glyphIndex].getShape();
0576: }
0577:
0578: GeneralPath gp = (GeneralPath) ((GeneralPath) gvShapes[glyphIndex])
0579: .clone();
0580:
0581: /* Applying GlyphVector font transform */
0582: AffineTransform at = (AffineTransform) this .transform.clone();
0583:
0584: /* Applying Glyph transform */
0585: AffineTransform glyphAT = getGlyphTransform(glyphIndex);
0586: if (glyphAT != null) {
0587: at.preConcatenate(glyphAT);
0588: }
0589:
0590: int idx = glyphIndex << 1;
0591:
0592: gp.transform(at);
0593: gp.transform(AffineTransform.getTranslateInstance(
0594: visualPositions[idx], visualPositions[idx + 1]));
0595: return gp;
0596: }
0597:
0598: /**
0599: * Returns a Shape that is the outline representation of this GlyphVector
0600: * rendered at the specified x,y coordinates.
0601: *
0602: * @param x specified x coordinate value
0603: * @param y specified y coordinate value
0604: * @return a Shape object that is the outline of this GlyphVector
0605: * at the specified coordinates.
0606: */
0607: @Override
0608: public Shape getOutline(float x, float y) {
0609: GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
0610: for (int i = 0; i < this .vector.length; i++) {
0611: GeneralPath outline = (GeneralPath) getGlyphOutline(i);
0612:
0613: /* Applying translation to actual visual bounds */
0614: outline.transform(AffineTransform
0615: .getTranslateInstance(x, y));
0616: gp.append(outline, false);
0617: }
0618:
0619: return gp;
0620: }
0621:
0622: /**
0623: * Returns a Shape that is the outline representation of this GlyphVector.
0624: *
0625: * @return a Shape object that is the outline of this GlyphVector
0626: */
0627: @Override
0628: public Shape getOutline() {
0629: return this .getOutline(0, 0);
0630: }
0631:
0632: /**
0633: * Returns an array of glyphcodes for the specified glyphs.
0634: *
0635: * @param beginGlyphIndex the start index
0636: * @param numEntries the number of glyph codes to get
0637: * @param codeReturn the array that receives glyph codes' values
0638: * @return an array that receives glyph codes' values
0639: */
0640: @Override
0641: public int[] getGlyphCodes(int beginGlyphIndex, int numEntries,
0642: int[] codeReturn) {
0643:
0644: if ((beginGlyphIndex < 0)
0645: || ((numEntries + beginGlyphIndex) > this
0646: .getNumGlyphs())) {
0647: // awt.44=beginGlyphIndex is out of vector's range
0648: throw new IndexOutOfBoundsException(Messages
0649: .getString("awt.44")); //$NON-NLS-1$
0650: }
0651:
0652: if (numEntries < 0) {
0653: // awt.45=numEntries is out of vector's range
0654: throw new IllegalArgumentException(Messages
0655: .getString("awt.45")); //$NON-NLS-1$
0656: }
0657:
0658: if (codeReturn == null) {
0659: codeReturn = new int[numEntries];
0660: }
0661:
0662: for (int i = beginGlyphIndex; i < beginGlyphIndex + numEntries; i++) {
0663: codeReturn[i - beginGlyphIndex] = this .vector[i]
0664: .getGlyphCode();
0665: }
0666:
0667: return codeReturn;
0668: }
0669:
0670: /**
0671: * Returns an array of numEntries character indices for the specified glyphs.
0672: *
0673: * @param beginGlyphIndex the start index
0674: * @param numEntries the number of glyph codes to get
0675: * @param codeReturn the array that receives glyph codes' values
0676: * @return an array that receives glyph char indices
0677: */
0678: @Override
0679: public int[] getGlyphCharIndices(int beginGlyphIndex,
0680: int numEntries, int[] codeReturn) {
0681: if ((beginGlyphIndex < 0)
0682: || (beginGlyphIndex >= this .getNumGlyphs())) {
0683: // awt.44=beginGlyphIndex is out of vector's range
0684: throw new IllegalArgumentException(Messages
0685: .getString("awt.44")); //$NON-NLS-1$
0686: }
0687:
0688: if ((numEntries < 0)
0689: || ((numEntries + beginGlyphIndex) > this
0690: .getNumGlyphs())) {
0691: // awt.45=numEntries is out of vector's range
0692: throw new IllegalArgumentException(Messages
0693: .getString("awt.45")); //$NON-NLS-1$
0694: }
0695:
0696: if (codeReturn == null) {
0697: codeReturn = new int[numEntries];
0698: }
0699:
0700: for (int i = 0; i < numEntries; i++) {
0701: codeReturn[i] = this .getGlyphCharIndex(i + beginGlyphIndex);
0702: }
0703: return codeReturn;
0704: }
0705:
0706: /**
0707: * Returns an array of numEntries glyphs positions from beginGlyphIndex
0708: * glyph in Glyph Vector.
0709: *
0710: * @param beginGlyphIndex the start index
0711: * @param numEntries the number of glyph codes to get
0712: * @param positionReturn the array that receives glyphs' positions
0713: * @return an array of floats that receives glyph char indices
0714: */
0715: @Override
0716: public float[] getGlyphPositions(int beginGlyphIndex,
0717: int numEntries, float[] positionReturn) {
0718:
0719: int len = (this .getNumGlyphs() + 1) << 1;
0720: beginGlyphIndex *= 2;
0721: numEntries *= 2;
0722:
0723: if ((beginGlyphIndex < 0)
0724: || ((numEntries + beginGlyphIndex) > len)) {
0725: // awt.44=beginGlyphIndex is out of vector's range
0726: throw new IndexOutOfBoundsException(Messages
0727: .getString("awt.44")); //$NON-NLS-1$
0728: }
0729:
0730: if (numEntries < 0) {
0731: // awt.45=numEntries is out of vector's range
0732: throw new IllegalArgumentException(Messages
0733: .getString("awt.45")); //$NON-NLS-1$
0734: }
0735:
0736: if (positionReturn == null) {
0737: positionReturn = new float[numEntries];
0738: }
0739:
0740: System.arraycopy(visualPositions, beginGlyphIndex,
0741: positionReturn, 0, numEntries);
0742:
0743: return positionReturn;
0744: }
0745:
0746: /**
0747: * Set numEntries elements of the visualPositions array from beginGlyphIndex
0748: * of numEntries glyphs positions from beginGlyphIndex glyph in Glyph Vector.
0749: *
0750: * @param beginGlyphIndex the start index
0751: * @param numEntries the number of glyph codes to get
0752: * @param setPositions the array of positions to set
0753: */
0754: public void setGlyphPositions(int beginGlyphIndex, int numEntries,
0755: float[] setPositions) {
0756:
0757: int len = (this .getNumGlyphs() + 1) << 1;
0758: beginGlyphIndex *= 2;
0759: numEntries *= 2;
0760:
0761: if ((beginGlyphIndex < 0)
0762: || ((numEntries + beginGlyphIndex) > len)) {
0763: // awt.44=beginGlyphIndex is out of vector's range
0764: throw new IndexOutOfBoundsException(Messages
0765: .getString("awt.44")); //$NON-NLS-1$
0766: }
0767:
0768: if (numEntries < 0) {
0769: // awt.45=numEntries is out of vector's range
0770: throw new IllegalArgumentException(Messages
0771: .getString("awt.45")); //$NON-NLS-1$
0772: }
0773:
0774: System.arraycopy(setPositions, 0, visualPositions,
0775: beginGlyphIndex, numEntries);
0776: layoutFlags = layoutFlags & FLAG_HAS_POSITION_ADJUSTMENTS;
0777:
0778: }
0779:
0780: /**
0781: * Set elements of the visualPositions array.
0782: *
0783: * @param setPositions the array of positions to set
0784: */
0785: public void setGlyphPositions(float[] setPositions) {
0786:
0787: int len = (this .getNumGlyphs() + 1) << 1;
0788: if (len != setPositions.length) {
0789: // awt.46=length of setPositions array differs from the length of positions array
0790: throw new IllegalArgumentException(Messages
0791: .getString("awt.46")); //$NON-NLS-1$
0792: }
0793:
0794: System.arraycopy(setPositions, 0, visualPositions, 0, len);
0795: layoutFlags = layoutFlags & FLAG_HAS_POSITION_ADJUSTMENTS;
0796:
0797: }
0798:
0799: /**
0800: * Returns glyph code of the specified glyph.
0801: *
0802: * @param glyphIndex specified index of the glyph
0803: */
0804: @Override
0805: public int getGlyphCode(int glyphIndex) {
0806: if (glyphIndex >= this .vector.length || glyphIndex < 0) {
0807: // awt.43=glyphIndex is out of vector's limits
0808: throw new IndexOutOfBoundsException(Messages
0809: .getString("awt.43")); //$NON-NLS-1$
0810: }
0811: return this .vector[glyphIndex].getGlyphCode();
0812: }
0813:
0814: /**
0815: * Returns character index of the specified glyph.
0816: *
0817: * @param glyphIndex specified index of the glyph
0818: */
0819: @Override
0820: public int getGlyphCharIndex(int glyphIndex) {
0821:
0822: if ((glyphIndex < 0) || (glyphIndex >= this .getNumGlyphs())) {
0823: // awt.43=glyphIndex is out of vector's limits
0824: throw new IllegalArgumentException(Messages
0825: .getString("awt.43")); //$NON-NLS-1$
0826: }
0827:
0828: if ((this .layoutFlags & Font.LAYOUT_RIGHT_TO_LEFT) != 0) {
0829: return this .charVector.length - glyphIndex - 1;
0830: }
0831:
0832: return glyphIndex;
0833: }
0834:
0835: /**
0836: * Returns a character value of the specified glyph.
0837: *
0838: * @param glyphIndex specified index of the glyph
0839: */
0840: public char getGlyphChar(int glyphIndex) {
0841:
0842: if ((glyphIndex < 0) || (glyphIndex >= this .getNumGlyphs())) {
0843: // awt.43=glyphIndex is out of vector's limits
0844: throw new IllegalArgumentException(Messages
0845: .getString("awt.43")); //$NON-NLS-1$
0846: }
0847: return this .charVector[glyphIndex];
0848: }
0849:
0850: /**
0851: * Assigns default positions to each glyph in this GlyphVector.
0852: */
0853: @Override
0854: public void performDefaultLayout() {
0855:
0856: System.arraycopy(logicalPositions, 0, visualPositions, 0,
0857: logicalPositions.length);
0858:
0859: // Set position changes flag to zero
0860: clearLayoutFlags(GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS);
0861: }
0862:
0863: /**
0864: * Returns the number of glyphs in this Glyph Vector
0865: */
0866: @Override
0867: public int getNumGlyphs() {
0868: return vector.length;
0869: }
0870:
0871: /**
0872: * Returns the logical bounds of this GlyphVector
0873: */
0874: @Override
0875: public Rectangle2D getLogicalBounds() {
0876: // XXX: for transforms where an angle between basis vectors is not 90 degrees
0877: // Rectanlge2D class doesn't fit as Logical bounds. For this reason we use
0878: // only non-transformed bounds!!
0879:
0880: float x = visualPositions[0];
0881: float width = visualPositions[visualPositions.length - 2];
0882:
0883: double scaleY = transform.getScaleY();
0884:
0885: Rectangle2D bounds = new Rectangle2D.Float(x,
0886: (float) ((-this .ascent - this .leading) * scaleY),
0887: width, (float) (this .height * scaleY));
0888: return bounds;
0889: }
0890:
0891: /**
0892: * Checks whether given GlyphVector equals to this GlyphVector.
0893: * @param glyphVector GlyphVector object to compare
0894: */
0895: @Override
0896: public boolean equals(GlyphVector glyphVector) {
0897: if (glyphVector == this ) {
0898: return true;
0899: }
0900:
0901: if (glyphVector != null) {
0902:
0903: if (!(glyphVector.getFontRenderContext().equals(
0904: this .vectorFRC) && glyphVector.getFont().equals(
0905: this .font))) {
0906: return false;
0907: }
0908:
0909: try {
0910: boolean eq = true;
0911: for (int i = 0; i < getNumGlyphs(); i++) {
0912:
0913: int idx = i * 2;
0914: eq = (((CommonGlyphVector) glyphVector).visualPositions[idx] == this .visualPositions[idx])
0915: && (((CommonGlyphVector) glyphVector).visualPositions[idx + 1] == this .visualPositions[idx + 1])
0916: && (glyphVector.getGlyphCharIndex(i) == this
0917: .getGlyphCharIndex(i));
0918:
0919: if (eq) {
0920: AffineTransform trans = glyphVector
0921: .getGlyphTransform(i);
0922: if (trans == null) {
0923: eq = (this .glsTransforms[i] == null);
0924: } else {
0925: eq = this .glsTransforms[i].equals(trans);
0926: }
0927: }
0928:
0929: if (!eq) {
0930: return false;
0931: }
0932: }
0933:
0934: return eq;
0935: } catch (ClassCastException e) {
0936: }
0937: }
0938:
0939: return false;
0940: }
0941:
0942: /**
0943: * Returns flags describing the state of the GlyphVector.
0944: */
0945: @Override
0946: public int getLayoutFlags() {
0947: return layoutFlags;
0948: }
0949:
0950: /**
0951: * Returns char with the specified index.
0952: *
0953: * @param index specified index of the char
0954: *
0955: */
0956: public char getChar(int index) {
0957: return this .charVector[index];
0958:
0959: }
0960:
0961: /**
0962: * Clear desired flags in layout flags describing the state.
0963: *
0964: * @param clearFlags flags mask to clear
0965: */
0966:
0967: private void clearLayoutFlags(int clearFlags) {
0968: layoutFlags &= ~clearFlags;
0969: }
0970:
0971: /**
0972: * Returns the logical bounds of the specified glyph within this CommonGlyphVector.
0973: *
0974: * @param glyphIndex index of the glyph to get it's logical bounds
0975: * @return logical bounds of the specified glyph
0976: */
0977: @Override
0978: public Shape getGlyphLogicalBounds(int glyphIndex) {
0979: if ((glyphIndex < 0) || (glyphIndex >= this .getNumGlyphs())) {
0980: // awt.43=glyphIndex is out of vector's limits
0981: throw new IndexOutOfBoundsException(Messages
0982: .getString("awt.43")); //$NON-NLS-1$
0983: }
0984: Glyph glyph = this .vector[glyphIndex];
0985:
0986: float x0 = visualPositions[glyphIndex * 2];
0987: float y0 = visualPositions[glyphIndex * 2 + 1];
0988: float advanceX = glyph.getGlyphPointMetrics().getAdvanceX();
0989:
0990: GeneralPath gp = new GeneralPath();
0991: gp.moveTo(0, -ascent - leading);
0992: gp.lineTo(advanceX, -ascent - leading);
0993: gp.lineTo(advanceX, descent);
0994: gp.lineTo(0, descent);
0995: gp.lineTo(0, -ascent - leading);
0996: gp.closePath();
0997:
0998: /* Applying GlyphVector font transform */
0999: AffineTransform at = (AffineTransform) this .transform.clone();
1000:
1001: /* Applying Glyph transform */
1002: AffineTransform glyphTransform = getGlyphTransform(glyphIndex);
1003: if (glyphTransform != null) {
1004: at.concatenate(glyphTransform);
1005: }
1006:
1007: /* Applying translation to actual visual bounds */
1008: at.preConcatenate(AffineTransform.getTranslateInstance(x0, y0));
1009: gp.transform(at);
1010: return gp;
1011: }
1012:
1013: /**
1014: * Returns the Font parameter of this GlyphVector
1015: */
1016: @Override
1017: public Font getFont() {
1018: return this.font;
1019: }
1020:
1021: }
|