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: package java.awt;
0019:
0020: import java.awt.font.FontRenderContext;
0021: import java.awt.font.GlyphVector;
0022: import java.awt.font.LineMetrics;
0023: import java.awt.font.TextAttribute;
0024: import java.awt.font.TransformAttribute;
0025: import java.awt.geom.AffineTransform;
0026: import java.awt.geom.Rectangle2D;
0027: import java.awt.peer.FontPeer;
0028: import java.io.BufferedInputStream;
0029: import java.io.File;
0030: import java.io.FileInputStream;
0031: import java.io.FileOutputStream;
0032: import java.io.IOException;
0033: import java.io.InputStream;
0034: import java.io.Serializable;
0035: import java.text.CharacterIterator;
0036: import java.text.AttributedCharacterIterator.Attribute;
0037: import java.util.Hashtable;
0038: import java.util.Locale;
0039: import java.util.Map;
0040: import java.util.StringTokenizer;
0041:
0042: import org.apache.harmony.awt.gl.font.CommonGlyphVector;
0043: import org.apache.harmony.awt.gl.font.FontManager;
0044: import org.apache.harmony.awt.gl.font.FontPeerImpl;
0045: import org.apache.harmony.awt.gl.font.fontlib.FLFontManager;
0046: import org.apache.harmony.awt.internal.nls.Messages;
0047: import org.apache.harmony.luni.util.NotImplementedException;
0048: import org.apache.harmony.misc.HashCode;
0049:
0050: public class Font implements Serializable {
0051: private static final long serialVersionUID = -4206021311591459213L;
0052:
0053: // Identity Transform attribute
0054: private static final TransformAttribute IDENTITY_TRANSFORM = new TransformAttribute(
0055: new AffineTransform());
0056:
0057: public static final int PLAIN = 0;
0058:
0059: public static final int BOLD = 1;
0060:
0061: public static final int ITALIC = 2;
0062:
0063: public static final int ROMAN_BASELINE = 0;
0064:
0065: public static final int CENTER_BASELINE = 1;
0066:
0067: public static final int HANGING_BASELINE = 2;
0068:
0069: public static final int TRUETYPE_FONT = 0;
0070:
0071: public static final int TYPE1_FONT = 1;
0072:
0073: public static final int LAYOUT_LEFT_TO_RIGHT = 0;
0074:
0075: public static final int LAYOUT_RIGHT_TO_LEFT = 1;
0076:
0077: public static final int LAYOUT_NO_START_CONTEXT = 2;
0078:
0079: public static final int LAYOUT_NO_LIMIT_CONTEXT = 4;
0080:
0081: static final Font DEFAULT_FONT = new Font("Dialog", Font.PLAIN, 12); //$NON-NLS-1$
0082:
0083: protected String name;
0084:
0085: protected int style;
0086:
0087: protected int size;
0088:
0089: protected float pointSize;
0090:
0091: // Flag if the Font object transformed
0092: private boolean transformed;
0093:
0094: // Set of font attributes
0095: private Hashtable<Attribute, Object> fRequestedAttributes;
0096:
0097: // font peer object corresponding to this Font
0098: private transient FontPeerImpl fontPeer;
0099:
0100: // number of glyphs in this Font
0101: private transient int numGlyphs = -1;
0102:
0103: // code for missing glyph for this Font
0104: private transient int missingGlyphCode = -1;
0105:
0106: /**
0107: * Writes object to ObjectOutputStream.
0108: *
0109: * @param out ObjectOutputStream
0110: * @throws IOException
0111: */
0112: private void writeObject(java.io.ObjectOutputStream out)
0113: throws IOException {
0114: out.defaultWriteObject();
0115: }
0116:
0117: /**
0118: * Reads object from ObjectInputStream object and set native platform
0119: * dependent fields to default values.
0120: *
0121: * @param in ObjectInputStream object
0122: * @throws IOException
0123: * @throws ClassNotFoundException
0124: */
0125: private void readObject(java.io.ObjectInputStream in)
0126: throws IOException, ClassNotFoundException {
0127: in.defaultReadObject();
0128:
0129: numGlyphs = -1;
0130: missingGlyphCode = -1;
0131:
0132: }
0133:
0134: public Font(Map<? extends Attribute, ?> attributes) {
0135: Object currAttr;
0136:
0137: // Default values are taken from the documentation of the Font class.
0138: // See Font constructor, decode and getFont sections.
0139:
0140: this .name = "default"; //$NON-NLS-1$
0141: this .size = 12;
0142: this .pointSize = 12;
0143: this .style = Font.PLAIN;
0144:
0145: if (attributes != null) {
0146:
0147: fRequestedAttributes = new Hashtable<Attribute, Object>(
0148: attributes);
0149:
0150: currAttr = attributes.get(TextAttribute.SIZE);
0151: if (currAttr != null) {
0152: this .pointSize = ((Float) currAttr).floatValue();
0153: this .size = (int) Math.ceil(this .pointSize);
0154: }
0155:
0156: currAttr = attributes.get(TextAttribute.POSTURE);
0157: if (currAttr != null
0158: && currAttr.equals(TextAttribute.POSTURE_OBLIQUE)) {
0159: this .style |= Font.ITALIC;
0160: }
0161:
0162: currAttr = attributes.get(TextAttribute.WEIGHT);
0163: if ((currAttr != null)
0164: && (((Float) currAttr).floatValue() >= (TextAttribute.WEIGHT_BOLD)
0165: .floatValue())) {
0166: this .style |= Font.BOLD;
0167: }
0168:
0169: currAttr = attributes.get(TextAttribute.FAMILY);
0170: if (currAttr != null) {
0171: this .name = (String) currAttr;
0172: }
0173:
0174: currAttr = attributes.get(TextAttribute.TRANSFORM);
0175: if (currAttr != null) {
0176: if (currAttr instanceof TransformAttribute) {
0177: this .transformed = !((TransformAttribute) currAttr)
0178: .getTransform().isIdentity();
0179: } else if (currAttr instanceof AffineTransform) {
0180: this .transformed = !((AffineTransform) currAttr)
0181: .isIdentity();
0182: }
0183: }
0184:
0185: } else {
0186: fRequestedAttributes = new Hashtable<Attribute, Object>(5);
0187: fRequestedAttributes.put(TextAttribute.TRANSFORM,
0188: IDENTITY_TRANSFORM);
0189:
0190: this .transformed = false;
0191:
0192: fRequestedAttributes.put(TextAttribute.FAMILY, name);
0193:
0194: fRequestedAttributes.put(TextAttribute.SIZE, new Float(
0195: this .size));
0196:
0197: if ((this .style & Font.BOLD) != 0) {
0198: fRequestedAttributes.put(TextAttribute.WEIGHT,
0199: TextAttribute.WEIGHT_BOLD);
0200: } else {
0201: fRequestedAttributes.put(TextAttribute.WEIGHT,
0202: TextAttribute.WEIGHT_REGULAR);
0203: }
0204: if ((this .style & Font.ITALIC) != 0) {
0205: fRequestedAttributes.put(TextAttribute.POSTURE,
0206: TextAttribute.POSTURE_OBLIQUE);
0207: } else {
0208: fRequestedAttributes.put(TextAttribute.POSTURE,
0209: TextAttribute.POSTURE_REGULAR);
0210: }
0211:
0212: }
0213: }
0214:
0215: public Font(String name, int style, int size) {
0216: this .name = (name != null) ? name : "Default"; //$NON-NLS-1$
0217: this .size = (size >= 0) ? size : 0;
0218: this .style = (style & ~0x03) == 0 ? style : Font.PLAIN;
0219: this .pointSize = this .size;
0220:
0221: fRequestedAttributes = new Hashtable<Attribute, Object>(5);
0222:
0223: fRequestedAttributes.put(TextAttribute.TRANSFORM,
0224: IDENTITY_TRANSFORM);
0225:
0226: this .transformed = false;
0227:
0228: fRequestedAttributes.put(TextAttribute.FAMILY, this .name);
0229: fRequestedAttributes.put(TextAttribute.SIZE, new Float(
0230: this .size));
0231:
0232: if ((this .style & Font.BOLD) != 0) {
0233: fRequestedAttributes.put(TextAttribute.WEIGHT,
0234: TextAttribute.WEIGHT_BOLD);
0235: } else {
0236: fRequestedAttributes.put(TextAttribute.WEIGHT,
0237: TextAttribute.WEIGHT_REGULAR);
0238: }
0239: if ((this .style & Font.ITALIC) != 0) {
0240: fRequestedAttributes.put(TextAttribute.POSTURE,
0241: TextAttribute.POSTURE_OBLIQUE);
0242: } else {
0243: fRequestedAttributes.put(TextAttribute.POSTURE,
0244: TextAttribute.POSTURE_REGULAR);
0245: }
0246: }
0247:
0248: public boolean canDisplay(char c) {
0249: FontPeerImpl peer = (FontPeerImpl) this .getPeer();
0250: return peer.canDisplay(c);
0251: }
0252:
0253: public boolean canDisplay(int i) {
0254: if (!Character.isValidCodePoint(i)) {
0255: throw new IllegalArgumentException();
0256: }
0257:
0258: if (!FontManager.IS_FONTLIB) {
0259: //TODO implement true code point support
0260: return canDisplay((char) i);
0261: } else {
0262: FontPeerImpl peer = (FontPeerImpl) this .getPeer();
0263: return peer.canDisplay(peer.getUnicodeByIndex(i));
0264: }
0265: }
0266:
0267: public int canDisplayUpTo(char[] text, int start, int limit) {
0268: int st = start;
0269: int result;
0270: while ((st < limit) && canDisplay(text[st])) {
0271: st++;
0272: }
0273:
0274: if (st == limit) {
0275: result = -1;
0276: } else {
0277: result = st;
0278: }
0279:
0280: return result;
0281: }
0282:
0283: public int canDisplayUpTo(CharacterIterator iter, int start,
0284: int limit) {
0285: int st = start;
0286: char c = iter.setIndex(start);
0287: int result;
0288:
0289: while ((st < limit) && (canDisplay(c))) {
0290: st++;
0291: c = iter.next();
0292: }
0293: if (st == limit) {
0294: result = -1;
0295: } else {
0296: result = st;
0297: }
0298:
0299: return result;
0300: }
0301:
0302: public int canDisplayUpTo(String str) {
0303: char[] chars = str.toCharArray();
0304: return canDisplayUpTo(chars, 0, chars.length);
0305: }
0306:
0307: public GlyphVector createGlyphVector(FontRenderContext frc,
0308: char[] chars) {
0309: return new CommonGlyphVector(chars, frc, this , 0);
0310: }
0311:
0312: public GlyphVector createGlyphVector(FontRenderContext frc,
0313: CharacterIterator iter) {
0314: char[] chars;
0315: int index = 0;
0316: if (iter.getEndIndex() != -1) {
0317: chars = new char[iter.getEndIndex()];
0318: } else {
0319: return null;
0320: }
0321: for (char c = iter.first(); c != CharacterIterator.DONE; c = iter
0322: .next(), index++) {
0323: chars[index] = c;
0324: }
0325:
0326: return this .createGlyphVector(frc, chars);
0327: }
0328:
0329: public GlyphVector createGlyphVector(FontRenderContext frc,
0330: int[] glyphCodes) {
0331: int length = glyphCodes.length;
0332: char[] chars = new char[length];
0333: FontPeerImpl peer = (FontPeerImpl) getPeer();
0334:
0335: for (int i = 0; i < length; i++) {
0336: chars[i] = peer.getUnicodeByIndex(glyphCodes[i]);
0337: }
0338:
0339: return new CommonGlyphVector(chars, frc, this , 0);
0340: }
0341:
0342: public GlyphVector createGlyphVector(FontRenderContext frc,
0343: String str) {
0344: return new CommonGlyphVector(str.toCharArray(), frc, this , 0);
0345: }
0346:
0347: /**
0348: * Returns font style constant value corresponding to one of the font style
0349: * names ("BOLD", "ITALIC", "BOLDITALIC"). Method returns Font.PLAIN if there
0350: * was no coincidence with predefined style names.
0351: *
0352: * @param fontStyleName font style name
0353: * @return font style constant value according to the font style name specified.
0354: */
0355: private static int getFontStyle(String fontStyleName) {
0356: int result = Font.PLAIN;
0357:
0358: if (fontStyleName.toUpperCase().equals("BOLDITALIC")) { //$NON-NLS-1$
0359: result = Font.BOLD | Font.ITALIC;
0360: } else if (fontStyleName.toUpperCase().equals("BOLD")) { //$NON-NLS-1$
0361: result = Font.BOLD;
0362: } else if (fontStyleName.toUpperCase().equals("ITALIC")) { //$NON-NLS-1$
0363: result = Font.ITALIC;
0364: }
0365:
0366: return result;
0367: }
0368:
0369: public static Font decode(String str) {
0370: // XXX: Documentation doesn't describe all cases, e.g. fonts face names with
0371: // symbols that are suggested as delimiters in the documentation.
0372: // In this decode implementation only ***-***-*** format is used with '-'
0373: // as the delimiter to avoid unexpected parse results of font face names
0374: // with spaces.
0375:
0376: if (str == null) {
0377: return DEFAULT_FONT;
0378: }
0379:
0380: StringTokenizer strTokens;
0381: String delim = "-"; //$NON-NLS-1$
0382: String substr;
0383:
0384: int fontSize = DEFAULT_FONT.size;
0385: int fontStyle = DEFAULT_FONT.style;
0386: String fontName = DEFAULT_FONT.name;
0387:
0388: strTokens = new StringTokenizer(str.trim(), delim);
0389:
0390: // Font Name
0391: if (strTokens.hasMoreTokens()) {
0392: fontName = strTokens.nextToken(); // first token is the font name
0393: }
0394:
0395: // Font Style or Size (if the style is undefined)
0396: if (strTokens.hasMoreTokens()) {
0397: substr = strTokens.nextToken();
0398:
0399: try {
0400: // if second token is the font size
0401: fontSize = Integer.valueOf(substr).intValue();
0402: } catch (NumberFormatException e) {
0403: // then second token is the font style
0404: fontStyle = getFontStyle(substr);
0405: }
0406:
0407: }
0408:
0409: // Font Size
0410: if (strTokens.hasMoreTokens()) {
0411: try {
0412: fontSize = Integer.valueOf(strTokens.nextToken())
0413: .intValue();
0414: } catch (NumberFormatException e) {
0415: }
0416: }
0417:
0418: return new Font(fontName, fontStyle, fontSize);
0419: }
0420:
0421: @SuppressWarnings("unchecked")
0422: public Font deriveFont(AffineTransform trans) {
0423:
0424: if (trans == null) {
0425: // awt.94=transform can not be null
0426: throw new IllegalArgumentException(Messages
0427: .getString("awt.94")); //$NON-NLS-1$
0428: }
0429:
0430: Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
0431: .clone();
0432:
0433: derivefRequestedAttributes.put(TextAttribute.TRANSFORM,
0434: new TransformAttribute(trans));
0435:
0436: return new Font(derivefRequestedAttributes);
0437:
0438: }
0439:
0440: @SuppressWarnings("unchecked")
0441: public Font deriveFont(float size) {
0442: Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
0443: .clone();
0444: derivefRequestedAttributes.put(TextAttribute.SIZE, new Float(
0445: size));
0446: return new Font(derivefRequestedAttributes);
0447: }
0448:
0449: @SuppressWarnings("unchecked")
0450: public Font deriveFont(int style) {
0451: Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
0452: .clone();
0453:
0454: if ((style & Font.BOLD) != 0) {
0455: derivefRequestedAttributes.put(TextAttribute.WEIGHT,
0456: TextAttribute.WEIGHT_BOLD);
0457: } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) {
0458: derivefRequestedAttributes.remove(TextAttribute.WEIGHT);
0459: }
0460:
0461: if ((style & Font.ITALIC) != 0) {
0462: derivefRequestedAttributes.put(TextAttribute.POSTURE,
0463: TextAttribute.POSTURE_OBLIQUE);
0464: } else if (derivefRequestedAttributes
0465: .get(TextAttribute.POSTURE) != null) {
0466: derivefRequestedAttributes.remove(TextAttribute.POSTURE);
0467: }
0468:
0469: return new Font(derivefRequestedAttributes);
0470: }
0471:
0472: @SuppressWarnings("unchecked")
0473: public Font deriveFont(int style, AffineTransform trans) {
0474:
0475: if (trans == null) {
0476: // awt.94=transform can not be null
0477: throw new IllegalArgumentException(Messages
0478: .getString("awt.94")); //$NON-NLS-1$
0479: }
0480: Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
0481: .clone();
0482:
0483: if ((style & BOLD) != 0) {
0484: derivefRequestedAttributes.put(TextAttribute.WEIGHT,
0485: TextAttribute.WEIGHT_BOLD);
0486: } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) {
0487: derivefRequestedAttributes.remove(TextAttribute.WEIGHT);
0488: }
0489:
0490: if ((style & ITALIC) != 0) {
0491: derivefRequestedAttributes.put(TextAttribute.POSTURE,
0492: TextAttribute.POSTURE_OBLIQUE);
0493: } else if (derivefRequestedAttributes
0494: .get(TextAttribute.POSTURE) != null) {
0495: derivefRequestedAttributes.remove(TextAttribute.POSTURE);
0496: }
0497: derivefRequestedAttributes.put(TextAttribute.TRANSFORM,
0498: new TransformAttribute(trans));
0499:
0500: return new Font(derivefRequestedAttributes);
0501: }
0502:
0503: @SuppressWarnings("unchecked")
0504: public Font deriveFont(int style, float size) {
0505: Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
0506: .clone();
0507:
0508: if ((style & BOLD) != 0) {
0509: derivefRequestedAttributes.put(TextAttribute.WEIGHT,
0510: TextAttribute.WEIGHT_BOLD);
0511: } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) {
0512: derivefRequestedAttributes.remove(TextAttribute.WEIGHT);
0513: }
0514:
0515: if ((style & ITALIC) != 0) {
0516: derivefRequestedAttributes.put(TextAttribute.POSTURE,
0517: TextAttribute.POSTURE_OBLIQUE);
0518: } else if (derivefRequestedAttributes
0519: .get(TextAttribute.POSTURE) != null) {
0520: derivefRequestedAttributes.remove(TextAttribute.POSTURE);
0521: }
0522:
0523: derivefRequestedAttributes.put(TextAttribute.SIZE, new Float(
0524: size));
0525: return new Font(derivefRequestedAttributes);
0526:
0527: }
0528:
0529: @SuppressWarnings("unchecked")
0530: public Font deriveFont(Map<? extends Attribute, ?> attributes) {
0531: Attribute[] avalAttributes = this .getAvailableAttributes();
0532:
0533: Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
0534: .clone();
0535: Object currAttribute;
0536: for (Attribute element : avalAttributes) {
0537: currAttribute = attributes.get(element);
0538: if (currAttribute != null) {
0539: derivefRequestedAttributes.put(element, currAttribute);
0540: }
0541: }
0542: return new Font(derivefRequestedAttributes);
0543: }
0544:
0545: @Override
0546: public boolean equals(Object obj) {
0547: if (obj == this ) {
0548: return true;
0549: }
0550:
0551: if (obj != null) {
0552: try {
0553: Font font = (Font) obj;
0554:
0555: return ((this .style == font.style)
0556: && (this .size == font.size)
0557: && this .name.equals(font.name)
0558: && (this .pointSize == font.pointSize) && (this
0559: .getTransform()).equals(font.getTransform()));
0560: } catch (ClassCastException e) {
0561: }
0562: }
0563:
0564: return false;
0565: }
0566:
0567: @SuppressWarnings("unchecked")
0568: public Map<TextAttribute, ?> getAttributes() {
0569: return (Map<TextAttribute, ?>) fRequestedAttributes.clone();
0570: }
0571:
0572: public Attribute[] getAvailableAttributes() {
0573: Attribute[] attrs = { TextAttribute.FAMILY,
0574: TextAttribute.POSTURE, TextAttribute.SIZE,
0575: TextAttribute.TRANSFORM, TextAttribute.WEIGHT,
0576: TextAttribute.SUPERSCRIPT, TextAttribute.WIDTH };
0577: return attrs;
0578: }
0579:
0580: public byte getBaselineFor(char c) {
0581: // TODO: implement using TT BASE table data
0582: return 0;
0583: }
0584:
0585: public String getFamily() {
0586: FontPeerImpl peer = (FontPeerImpl) this .getPeer();
0587: return peer.getFamily();
0588:
0589: }
0590:
0591: public String getFamily(Locale l) {
0592: if (l == null) {
0593: // awt.01='{0}' parameter is null
0594: throw new NullPointerException(Messages.getString(
0595: "awt.01", "Locale")); //$NON-NLS-1$ //$NON-NLS-2$
0596: }
0597:
0598: FontPeerImpl peer = (FontPeerImpl) this .getPeer();
0599: return peer.getFamily(l);
0600: }
0601:
0602: public static Font getFont(Map<? extends Attribute, ?> attributes) {
0603: Font fnt = (Font) attributes.get(TextAttribute.FONT);
0604: if (fnt != null) {
0605: return fnt;
0606: }
0607: return new Font(attributes);
0608: }
0609:
0610: public static Font getFont(String sp, Font f) {
0611: String pr = System.getProperty(sp);
0612: if (pr == null) {
0613: return f;
0614: }
0615: return decode(pr);
0616: }
0617:
0618: public static Font getFont(String sp) {
0619: return getFont(sp, null);
0620: }
0621:
0622: public String getFontName() {
0623: FontPeerImpl peer = (FontPeerImpl) this .getPeer();
0624: return peer.getFontName();
0625: }
0626:
0627: public String getFontName(Locale l) {
0628: FontPeerImpl peer = (FontPeerImpl) this .getPeer();
0629: return peer.getFontName(l);
0630: }
0631:
0632: public LineMetrics getLineMetrics(char[] chars, int start, int end,
0633: FontRenderContext frc) {
0634:
0635: if (frc == null) {
0636: // awt.00=FontRenderContext is null
0637: throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
0638: }
0639:
0640: FontPeerImpl peer = (FontPeerImpl) this .getPeer();
0641:
0642: return peer.getLineMetrics((new String(chars)).substring(start,
0643: end), frc, this .getTransform());
0644: }
0645:
0646: public LineMetrics getLineMetrics(CharacterIterator iter,
0647: int start, int end, FontRenderContext frc) {
0648:
0649: if (frc == null) {
0650: // awt.00=FontRenderContext is null
0651: throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
0652: }
0653:
0654: String resultString;
0655: int iterCount;
0656:
0657: iterCount = end - start;
0658: if (iterCount < 0) {
0659: resultString = ""; //$NON-NLS-1$
0660: } else {
0661: char[] chars = new char[iterCount];
0662: int i = 0;
0663: for (char c = iter.setIndex(start); c != CharacterIterator.DONE
0664: && (i < iterCount); c = iter.next()) {
0665: chars[i] = c;
0666: i++;
0667: }
0668: resultString = new String(chars);
0669: }
0670: return this .getLineMetrics(resultString, frc);
0671: }
0672:
0673: public LineMetrics getLineMetrics(String str, FontRenderContext frc) {
0674:
0675: if (frc == null) {
0676: // awt.00=FontRenderContext is null
0677: throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
0678: }
0679:
0680: FontPeerImpl peer = (FontPeerImpl) this .getPeer();
0681: return peer.getLineMetrics(str, frc, getTransform());
0682: }
0683:
0684: public LineMetrics getLineMetrics(String str, int start, int end,
0685: FontRenderContext frc) {
0686: return this .getLineMetrics(str.substring(start, end), frc);
0687: }
0688:
0689: public Rectangle2D getStringBounds(CharacterIterator ci, int start,
0690: int end, FontRenderContext frc) {
0691: int first = ci.getBeginIndex();
0692: int finish = ci.getEndIndex();
0693: char[] chars;
0694:
0695: if (start < first) {
0696: // awt.95=Wrong start index: {0}
0697: throw new IndexOutOfBoundsException(Messages.getString(
0698: "awt.95", start)); //$NON-NLS-1$
0699: }
0700: if (end > finish) {
0701: // awt.96=Wrong finish index: {0}
0702: throw new IndexOutOfBoundsException(Messages.getString(
0703: "awt.96", end)); //$NON-NLS-1$
0704: }
0705: if (start > end) {
0706: // awt.97=Wrong range length: {0}
0707: throw new IndexOutOfBoundsException(Messages.getString(
0708: "awt.97", //$NON-NLS-1$
0709: (end - start)));
0710: }
0711:
0712: if (frc == null) {
0713: throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
0714: }
0715:
0716: chars = new char[end - start];
0717:
0718: ci.setIndex(start);
0719: for (int i = 0; i < chars.length; i++) {
0720: chars[i] = ci.current();
0721: ci.next();
0722: }
0723:
0724: return this .getStringBounds(chars, 0, chars.length, frc);
0725:
0726: }
0727:
0728: public Rectangle2D getStringBounds(String str, FontRenderContext frc) {
0729: char[] chars = str.toCharArray();
0730: return this .getStringBounds(chars, 0, chars.length, frc);
0731:
0732: }
0733:
0734: public Rectangle2D getStringBounds(String str, int start, int end,
0735: FontRenderContext frc) {
0736:
0737: return this .getStringBounds((str.substring(start, end)), frc);
0738: }
0739:
0740: public Rectangle2D getStringBounds(char[] chars, int start,
0741: int end, FontRenderContext frc) {
0742: if (start < 0) {
0743: // awt.95=Wrong start index: {0}
0744: throw new IndexOutOfBoundsException(Messages.getString(
0745: "awt.95", start)); //$NON-NLS-1$
0746: }
0747: if (end > chars.length) {
0748: // awt.96=Wrong finish index: {0}
0749: throw new IndexOutOfBoundsException(Messages.getString(
0750: "awt.96", end)); //$NON-NLS-1$
0751: }
0752: if (start > end) {
0753: // awt.97=Wrong range length: {0}
0754: throw new IndexOutOfBoundsException(Messages.getString(
0755: "awt.97", //$NON-NLS-1$
0756: (end - start)));
0757: }
0758:
0759: if (frc == null) {
0760: throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
0761: }
0762:
0763: FontPeerImpl peer = (FontPeerImpl) this .getPeer();
0764:
0765: final int TRANSFORM_MASK = AffineTransform.TYPE_GENERAL_ROTATION
0766: | AffineTransform.TYPE_GENERAL_TRANSFORM;
0767: Rectangle2D bounds;
0768:
0769: AffineTransform transform = getTransform();
0770: AffineTransform frcTransform = frc.getTransform();
0771:
0772: // XXX: for transforms where an angle between basis vectors is not 90
0773: // degrees Rectanlge2D class doesn't fit as Logical bounds.
0774: if ((transform.getType() & TRANSFORM_MASK) == 0) {
0775: int width = 0;
0776: for (int i = start; i < end; i++) {
0777: width += peer.charWidth(chars[i]);
0778: }
0779: LineMetrics nlm = peer.getLineMetrics();
0780: bounds = transform.createTransformedShape(
0781: new Rectangle2D.Float(0, -nlm.getAscent(), width,
0782: nlm.getHeight())).getBounds2D();
0783: } else {
0784: int len = end - start;
0785: char[] subChars = new char[len];
0786: System.arraycopy(chars, start, subChars, 0, len);
0787: bounds = createGlyphVector(frc, subChars)
0788: .getLogicalBounds();
0789: }
0790:
0791: if (!(frcTransform.isIdentity()))
0792: return frcTransform.createTransformedShape(bounds)
0793: .getBounds2D();
0794:
0795: return bounds;
0796: }
0797:
0798: public Rectangle2D getMaxCharBounds(FontRenderContext frc) {
0799: if (frc == null) {
0800: // awt.00=FontRenderContext is null
0801: throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
0802: }
0803:
0804: FontPeerImpl peer = (FontPeerImpl) this .getPeer();
0805:
0806: Rectangle2D bounds = peer.getMaxCharBounds(frc);
0807: AffineTransform transform = getTransform();
0808: // !! Documentation doesn't describe meaning of max char bounds
0809: // for the fonts that have rotate transforms. For all transforms
0810: // returned bounds are the bounds of transformed maxCharBounds
0811: // Rectangle2D that corresponds to the font with identity transform.
0812: // TODO: resolve this issue to return correct bounds
0813: bounds = transform.createTransformedShape(bounds).getBounds2D();
0814:
0815: return bounds;
0816: }
0817:
0818: public GlyphVector layoutGlyphVector(FontRenderContext frc,
0819: char[] chars, int start, int count, int flags) {
0820: // TODO: implement method for bidirectional text.
0821: // At the moment only LTR and RTL texts supported.
0822: if (start < 0) {
0823: // awt.95=Wrong start index: {0}
0824: throw new ArrayIndexOutOfBoundsException(Messages
0825: .getString("awt.95", //$NON-NLS-1$
0826: start));
0827: }
0828:
0829: if (count < 0) {
0830: // awt.98=Wrong count value, can not be negative: {0}
0831: throw new ArrayIndexOutOfBoundsException(Messages
0832: .getString("awt.98", //$NON-NLS-1$
0833: count));
0834: }
0835:
0836: if (start + count > chars.length) {
0837: // awt.99=Wrong [start + count] is out of range: {0}
0838: throw new ArrayIndexOutOfBoundsException(Messages
0839: .getString("awt.99", //$NON-NLS-1$
0840: (start + count)));
0841: }
0842:
0843: char[] out = new char[count];
0844: System.arraycopy(chars, start, out, 0, count);
0845:
0846: return new CommonGlyphVector(out, frc, this , flags);
0847: }
0848:
0849: @Override
0850: public String toString() {
0851: String stl = "plain"; //$NON-NLS-1$
0852: String result;
0853:
0854: if (this .isBold() && this .isItalic()) {
0855: stl = "bolditalic"; //$NON-NLS-1$
0856: }
0857: if (this .isBold() && !this .isItalic()) {
0858: stl = "bold"; //$NON-NLS-1$
0859: }
0860:
0861: if (!this .isBold() && this .isItalic()) {
0862: stl = "italic"; //$NON-NLS-1$
0863: }
0864:
0865: result = this .getClass().getName()
0866: + "[family=" + this .getFamily() + //$NON-NLS-1$
0867: ",name=" + this .name + //$NON-NLS-1$
0868: ",style=" + stl + //$NON-NLS-1$
0869: ",size=" + this .size + "]"; //$NON-NLS-1$ //$NON-NLS-2$
0870: return result;
0871: }
0872:
0873: public String getPSName() {
0874: FontPeerImpl peer = (FontPeerImpl) this .getPeer();
0875: return peer.getPSName();
0876: }
0877:
0878: public String getName() {
0879: return (this .name);
0880: }
0881:
0882: /**
0883: * @deprecated
0884: */
0885: @Deprecated
0886: public FontPeer getPeer() {
0887: if (fontPeer == null) {
0888: fontPeer = (FontPeerImpl) FontManager.getInstance()
0889: .getFontPeer(this .getName(), this .getStyle(),
0890: this .getSize());
0891:
0892: }
0893: return fontPeer;
0894: }
0895:
0896: public AffineTransform getTransform() {
0897: Object transform = fRequestedAttributes
0898: .get(TextAttribute.TRANSFORM);
0899:
0900: if (transform != null) {
0901: if (transform instanceof TransformAttribute) {
0902: return ((TransformAttribute) transform).getTransform();
0903: }
0904: if (transform instanceof AffineTransform) {
0905: return new AffineTransform((AffineTransform) transform);
0906: }
0907: } else {
0908: transform = new AffineTransform();
0909: }
0910: return (AffineTransform) transform;
0911:
0912: }
0913:
0914: public boolean isTransformed() {
0915: return this .transformed;
0916: }
0917:
0918: public boolean isPlain() {
0919: return (this .style == PLAIN);
0920: }
0921:
0922: public boolean isItalic() {
0923: return (this .style & ITALIC) != 0;
0924: }
0925:
0926: public boolean isBold() {
0927: return (this .style & BOLD) != 0;
0928: }
0929:
0930: public boolean hasUniformLineMetrics() {
0931: FontPeerImpl peer = (FontPeerImpl) this .getPeer();
0932: return peer.hasUniformLineMetrics();
0933: }
0934:
0935: @Override
0936: public int hashCode() {
0937: HashCode hash = new HashCode();
0938:
0939: hash.append(this .name);
0940: hash.append(this .style);
0941: hash.append(this .size);
0942:
0943: return hash.hashCode();
0944: }
0945:
0946: public int getStyle() {
0947: return this .style;
0948: }
0949:
0950: public int getSize() {
0951: return this .size;
0952: }
0953:
0954: public int getNumGlyphs() {
0955: if (numGlyphs == -1) {
0956: FontPeerImpl peer = (FontPeerImpl) this .getPeer();
0957: this .numGlyphs = peer.getNumGlyphs();
0958: }
0959: return this .numGlyphs;
0960: }
0961:
0962: public int getMissingGlyphCode() {
0963: if (missingGlyphCode == -1) {
0964: FontPeerImpl peer = (FontPeerImpl) this .getPeer();
0965: this .missingGlyphCode = peer.getMissingGlyphCode();
0966: }
0967: return this .missingGlyphCode;
0968: }
0969:
0970: public float getSize2D() {
0971: return this .pointSize;
0972: }
0973:
0974: public float getItalicAngle() {
0975: FontPeerImpl peer = (FontPeerImpl) this .getPeer();
0976: return peer.getItalicAngle();
0977: }
0978:
0979: public static Font createFont(int fontFormat, File fontFile)
0980: throws FontFormatException, IOException {
0981: if (fontFile == null)
0982: throw new NullPointerException();
0983:
0984: if (FontManager.IS_FONTLIB) {
0985: if (fontFormat != TRUETYPE_FONT && fontFormat != TYPE1_FONT) {
0986: // awt.9A=Unsupported font format
0987: throw new IllegalArgumentException(Messages
0988: .getString("awt.9A")); //$NON-NLS-1$
0989: }
0990:
0991: return ((FLFontManager) FontManager.getInstance())
0992: .embedFont(fontFile.getAbsolutePath(), fontFormat);
0993: } else {
0994: InputStream is = new FileInputStream(fontFile);
0995: try {
0996: return createFont(fontFormat, is);
0997: } finally {
0998: is.close();
0999: }
1000: }
1001: }
1002:
1003: public static Font createFont(int fontFormat, InputStream fontStream)
1004: throws FontFormatException, IOException {
1005:
1006: BufferedInputStream buffStream;
1007: int bRead = 0;
1008: int size = 8192; // memory page size, for the faster reading
1009: byte buf[] = new byte[size];
1010:
1011: if (fontFormat != TRUETYPE_FONT && !FontManager.IS_FONTLIB) {
1012: // awt.9A=Unsupported font format
1013: throw new IllegalArgumentException(Messages
1014: .getString("awt.9A")); //$NON-NLS-1$
1015: }
1016:
1017: /* Get font file in system-specific directory */
1018: File fontFile = FontManager.getInstance().getTempFontFile();
1019: // File fontFile = Toolkit.getDefaultToolkit().getGraphicsFactory().getFontManager().getTempFontFile();
1020:
1021: buffStream = new BufferedInputStream(fontStream);
1022: FileOutputStream fOutStream = new FileOutputStream(fontFile);
1023:
1024: bRead = buffStream.read(buf, 0, size);
1025:
1026: while (bRead != -1) {
1027: fOutStream.write(buf, 0, bRead);
1028: bRead = buffStream.read(buf, 0, size);
1029: }
1030:
1031: buffStream.close();
1032: fOutStream.close();
1033:
1034: Font font = null;
1035:
1036: if (FontManager.IS_FONTLIB) {
1037: font = ((FLFontManager) FontManager.getInstance())
1038: .embedFont(fontFile.getAbsolutePath(), fontFormat);
1039: } else {
1040: font = Toolkit.getDefaultToolkit().getGraphicsFactory()
1041: .embedFont(fontFile.getAbsolutePath());
1042: }
1043: if (font == null) {
1044: // awt.9B=Can't create font - bad font data
1045: throw new FontFormatException(Messages.getString("awt.9B")); //$NON-NLS-1$
1046: }
1047: return font;
1048: }
1049:
1050: }
|