1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.awt; 19 20import com.android.internal.awt.AndroidGraphics2D; 21 22import java.awt.font.FontRenderContext; 23import java.awt.font.GlyphVector; 24import java.awt.font.LineMetrics; 25import java.awt.font.TextAttribute; 26import java.awt.font.TransformAttribute; 27import java.awt.geom.AffineTransform; 28import java.awt.geom.Rectangle2D; 29import java.io.File; 30import java.io.FileInputStream; 31import java.io.BufferedInputStream; 32import java.io.FileOutputStream; 33import java.io.IOException; 34import java.io.InputStream; 35import java.io.Serializable; 36import java.text.CharacterIterator; 37import java.text.AttributedCharacterIterator.Attribute; 38import java.util.Hashtable; 39import java.util.Locale; 40import java.util.Map; 41import java.util.StringTokenizer; 42 43import org.apache.harmony.awt.gl.font.AndroidGlyphVector; 44import org.apache.harmony.awt.gl.font.CommonGlyphVector; 45import org.apache.harmony.awt.gl.font.FontPeerImpl; 46import org.apache.harmony.awt.gl.font.FontMetricsImpl; 47import org.apache.harmony.awt.gl.font.LineMetricsImpl; 48import org.apache.harmony.awt.internal.nls.Messages; 49import org.apache.harmony.luni.util.NotImplementedException; 50import org.apache.harmony.misc.HashCode; 51 52/** 53 * The Font class represents fonts for rendering text. This class allow to map 54 * characters to glyphs. 55 * <p> 56 * A glyph is a shape used to render a character or a sequence of characters. 57 * For example one character of Latin writing system represented by one glyph, 58 * but in complex writing system such as South and South-East Asian there is 59 * more complicated correspondence between characters and glyphs. 60 * <p> 61 * The Font object is identified by two types of names. The logical font name is 62 * the name that is used to construct the font. The font name is the name of a 63 * particular font face (for example, Arial Bold). The family name is the font's 64 * family name that specifies the typographic design across several faces (for 65 * example, Arial). In all the Font is identified by three attributes: the 66 * family name, the style (such as bold or italic), and the size. 67 * 68 * @since Android 1.0 69 */ 70public class Font implements Serializable { 71 72 /** 73 * The Constant serialVersionUID. 74 */ 75 private static final long serialVersionUID = -4206021311591459213L; 76 77 // Identity Transform attribute 78 /** 79 * The Constant IDENTITY_TRANSFORM. 80 */ 81 private static final TransformAttribute IDENTITY_TRANSFORM = new TransformAttribute( 82 new AffineTransform()); 83 84 /** 85 * The Constant PLAIN indicates font's plain style. 86 */ 87 public static final int PLAIN = 0; 88 89 /** 90 * The Constant BOLD indicates font's bold style. 91 */ 92 public static final int BOLD = 1; 93 94 /** 95 * The Constant ITALIC indicates font's italic style. 96 */ 97 public static final int ITALIC = 2; 98 99 /** 100 * The Constant ROMAN_BASELINE indicated roman baseline. 101 */ 102 public static final int ROMAN_BASELINE = 0; 103 104 /** 105 * The Constant CENTER_BASELINE indicates center baseline. 106 */ 107 public static final int CENTER_BASELINE = 1; 108 109 /** 110 * The Constant HANGING_BASELINE indicates hanging baseline. 111 */ 112 public static final int HANGING_BASELINE = 2; 113 114 /** 115 * The Constant TRUETYPE_FONT indicates a font resource of type TRUETYPE. 116 */ 117 public static final int TRUETYPE_FONT = 0; 118 119 /** 120 * The Constant TYPE1_FONT indicates a font resource of type TYPE1. 121 */ 122 public static final int TYPE1_FONT = 1; 123 124 /** 125 * The Constant LAYOUT_LEFT_TO_RIGHT indicates that text is left to right. 126 */ 127 public static final int LAYOUT_LEFT_TO_RIGHT = 0; 128 129 /** 130 * The Constant LAYOUT_RIGHT_TO_LEFT indicates that text is right to left. 131 */ 132 public static final int LAYOUT_RIGHT_TO_LEFT = 1; 133 134 /** 135 * The Constant LAYOUT_NO_START_CONTEXT indicates that the text in the char 136 * array before the indicated start should not be examined. 137 */ 138 public static final int LAYOUT_NO_START_CONTEXT = 2; 139 140 /** 141 * The Constant LAYOUT_NO_LIMIT_CONTEXT indicates that text in the char 142 * array after the indicated limit should not be examined. 143 */ 144 public static final int LAYOUT_NO_LIMIT_CONTEXT = 4; 145 146 /** 147 * The Constant DEFAULT_FONT. 148 */ 149 static final Font DEFAULT_FONT = new Font("Dialog", Font.PLAIN, 12); //$NON-NLS-1$ 150 151 /** 152 * The name of the Font. 153 */ 154 protected String name; 155 156 /** 157 * The style of the Font. 158 */ 159 protected int style; 160 161 /** 162 * The size of the Font. 163 */ 164 protected int size; 165 166 /** 167 * The point size of the Font. 168 */ 169 protected float pointSize; 170 171 // Flag if the Font object transformed 172 /** 173 * The transformed. 174 */ 175 private boolean transformed; 176 177 // Set of font attributes 178 /** 179 * The requested attributes. 180 */ 181 private Hashtable<Attribute, Object> fRequestedAttributes; 182 183 // font peer object corresponding to this Font 184 /** 185 * The font peer. 186 */ 187 private transient FontPeerImpl fontPeer; 188 189 // number of glyphs in this Font 190 /** 191 * The num glyphs. 192 */ 193 private transient int numGlyphs = -1; 194 195 // code for missing glyph for this Font 196 /** 197 * The missing glyph code. 198 */ 199 private transient int missingGlyphCode = -1; 200 201 /** 202 * Writes object to ObjectOutputStream. 203 * 204 * @param out 205 * ObjectOutputStream. 206 * @throws IOException 207 * Signals that an I/O exception has occurred. 208 */ 209 private void writeObject(java.io.ObjectOutputStream out) throws IOException { 210 out.defaultWriteObject(); 211 } 212 213 /** 214 * Reads object from ObjectInputStream object and set native platform 215 * dependent fields to default values. 216 * 217 * @param in 218 * ObjectInputStream object. 219 * @throws IOException 220 * Signals that an I/O exception has occurred. 221 * @throws ClassNotFoundException 222 * the class not found exception. 223 */ 224 private void readObject(java.io.ObjectInputStream in) throws IOException, 225 ClassNotFoundException { 226 in.defaultReadObject(); 227 228 numGlyphs = -1; 229 missingGlyphCode = -1; 230 231 } 232 233 /** 234 * Instantiates a new Font with the specified attributes. The Font will be 235 * created with default attributes if the attribute's parameter is null. 236 * 237 * @param attributes 238 * the attributes to be assigned to the new Font, or null. 239 */ 240 public Font(Map<? extends Attribute, ?> attributes) { 241 Object currAttr; 242 243 // Default values are taken from the documentation of the Font class. 244 // See Font constructor, decode and getFont sections. 245 246 this.name = "default"; //$NON-NLS-1$ 247 this.size = 12; 248 this.pointSize = 12; 249 this.style = Font.PLAIN; 250 251 if (attributes != null) { 252 253 fRequestedAttributes = new Hashtable<Attribute, Object>(attributes); 254 255 currAttr = attributes.get(TextAttribute.SIZE); 256 if (currAttr != null) { 257 this.pointSize = ((Float)currAttr).floatValue(); 258 this.size = (int)Math.ceil(this.pointSize); 259 } 260 261 currAttr = attributes.get(TextAttribute.POSTURE); 262 if (currAttr != null && currAttr.equals(TextAttribute.POSTURE_OBLIQUE)) { 263 this.style |= Font.ITALIC; 264 } 265 266 currAttr = attributes.get(TextAttribute.WEIGHT); 267 if ((currAttr != null) 268 && (((Float)currAttr).floatValue() >= (TextAttribute.WEIGHT_BOLD).floatValue())) { 269 this.style |= Font.BOLD; 270 } 271 272 currAttr = attributes.get(TextAttribute.FAMILY); 273 if (currAttr != null) { 274 this.name = (String)currAttr; 275 } 276 277 currAttr = attributes.get(TextAttribute.TRANSFORM); 278 if (currAttr != null) { 279 if (currAttr instanceof TransformAttribute) { 280 this.transformed = !((TransformAttribute)currAttr).getTransform().isIdentity(); 281 } else if (currAttr instanceof AffineTransform) { 282 this.transformed = !((AffineTransform)currAttr).isIdentity(); 283 } 284 } 285 286 } else { 287 fRequestedAttributes = new Hashtable<Attribute, Object>(5); 288 fRequestedAttributes.put(TextAttribute.TRANSFORM, IDENTITY_TRANSFORM); 289 290 this.transformed = false; 291 292 fRequestedAttributes.put(TextAttribute.FAMILY, name); 293 294 fRequestedAttributes.put(TextAttribute.SIZE, new Float(this.size)); 295 296 if ((this.style & Font.BOLD) != 0) { 297 fRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); 298 } else { 299 fRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_REGULAR); 300 } 301 if ((this.style & Font.ITALIC) != 0) { 302 fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); 303 } else { 304 fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR); 305 } 306 307 } 308 } 309 310 /** 311 * Instantiates a new Font with the specified name, style and size. 312 * 313 * @param name 314 * the name of font. 315 * @param style 316 * the style of font. 317 * @param size 318 * the size of font. 319 */ 320 public Font(String name, int style, int size) { 321 322 this.name = (name != null) ? name : "Default"; //$NON-NLS-1$ 323 this.size = (size >= 0) ? size : 0; 324 this.style = (style & ~0x03) == 0 ? style : Font.PLAIN; 325 this.pointSize = this.size; 326 327 fRequestedAttributes = new Hashtable<Attribute, Object>(5); 328 329 fRequestedAttributes.put(TextAttribute.TRANSFORM, IDENTITY_TRANSFORM); 330 331 this.transformed = false; 332 333 fRequestedAttributes.put(TextAttribute.FAMILY, this.name); 334 fRequestedAttributes.put(TextAttribute.SIZE, new Float(this.size)); 335 336 if ((this.style & Font.BOLD) != 0) { 337 fRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); 338 } else { 339 fRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_REGULAR); 340 } 341 if ((this.style & Font.ITALIC) != 0) { 342 fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); 343 } else { 344 fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR); 345 } 346 } 347 348 /** 349 * Returns true if this Font has a glyph for the specified character. 350 * 351 * @param c 352 * the character. 353 * @return true if this Font has a glyph for the specified character, false 354 * otherwise. 355 */ 356 public boolean canDisplay(char c) { 357 FontPeerImpl peer = (FontPeerImpl)this.getPeer(); 358 return peer.canDisplay(c); 359 } 360 361 /** 362 * Returns true if the Font can display the characters of the the specified 363 * text from the specified start position to the specified limit position. 364 * 365 * @param text 366 * the text. 367 * @param start 368 * the start offset (in the character array). 369 * @param limit 370 * the limit offset (in the character array). 371 * @return the a character's position in the text that this Font can not 372 * display, or -1 if this Font can display all characters in this 373 * text. 374 */ 375 public int canDisplayUpTo(char[] text, int start, int limit) { 376 int st = start; 377 int result; 378 while ((st < limit) && canDisplay(text[st])) { 379 st++; 380 } 381 382 if (st == limit) { 383 result = -1; 384 } else { 385 result = st; 386 } 387 388 return result; 389 } 390 391 /** 392 * Returns true if the Font can display the characters of the the specified 393 * CharacterIterator from the specified start position and the specified 394 * limit position. 395 * 396 * @param iter 397 * the CharacterIterator. 398 * @param start 399 * the start offset. 400 * @param limit 401 * the limit offset. 402 * @return the a character's position in the CharacterIterator that this 403 * Font can not display, or -1 if this Font can display all 404 * characters in this text. 405 */ 406 public int canDisplayUpTo(CharacterIterator iter, int start, int limit) { 407 int st = start; 408 char c = iter.setIndex(start); 409 int result; 410 411 while ((st < limit) && (canDisplay(c))) { 412 st++; 413 c = iter.next(); 414 } 415 if (st == limit) { 416 result = -1; 417 } else { 418 result = st; 419 } 420 421 return result; 422 } 423 424 /** 425 * Returns true if this Font can display a specified String. 426 * 427 * @param str 428 * the String. 429 * @return the a character's position in the String that this Font can not 430 * display, or -1 if this Font can display all characters in this 431 * text. 432 */ 433 public int canDisplayUpTo(String str) { 434 char[] chars = str.toCharArray(); 435 return canDisplayUpTo(chars, 0, chars.length); 436 } 437 438 /** 439 * Creates a GlyphVector of associating characters to glyphs based on the 440 * Unicode map of this Font. 441 * 442 * @param frc 443 * the FontRenderContext. 444 * @param chars 445 * the characters array. 446 * @return the GlyphVector of associating characters to glyphs based on the 447 * Unicode map of this Font. 448 */ 449 public GlyphVector createGlyphVector(FontRenderContext frc, char[] chars) { 450 return new AndroidGlyphVector(chars, frc, this, 0); 451 } 452 453 /** 454 * Creates a GlyphVector of associating characters contained in the 455 * specified CharacterIterator to glyphs based on the Unicode map of this 456 * Font. 457 * 458 * @param frc 459 * the FontRenderContext. 460 * @param iter 461 * the CharacterIterator. 462 * @return the GlyphVector of associating characters contained in the 463 * specified CharacterIterator to glyphs based on the Unicode map of 464 * this Font. 465 */ 466 public GlyphVector createGlyphVector(FontRenderContext frc, CharacterIterator iter) { 467 throw new RuntimeException("Not implemented!"); //$NON-NLS-1$ 468 } 469 470 /** 471 * Creates a GlyphVector of associating characters to glyphs based on the 472 * Unicode map of this Font. 473 * 474 * @param frc 475 * the FontRenderContext. 476 * @param glyphCodes 477 * the specified integer array of glyph codes. 478 * @return the GlyphVector of associating characters to glyphs based on the 479 * Unicode map of this Font. 480 * @throws NotImplementedException 481 * if this method is not implemented by a subclass. 482 */ 483 public GlyphVector createGlyphVector(FontRenderContext frc, int[] glyphCodes) 484 throws org.apache.harmony.luni.util.NotImplementedException { 485 throw new RuntimeException("Not implemented!"); //$NON-NLS-1$ 486 } 487 488 /** 489 * Creates a GlyphVector of associating characters to glyphs based on the 490 * Unicode map of this Font. 491 * 492 * @param frc 493 * the FontRenderContext. 494 * @param str 495 * the specified String. 496 * @return the GlyphVector of associating characters to glyphs based on the 497 * Unicode map of this Font. 498 */ 499 public GlyphVector createGlyphVector(FontRenderContext frc, String str) { 500 return new AndroidGlyphVector(str.toCharArray(), frc, this, 0); 501 502 } 503 504 /** 505 * Returns the font style constant value corresponding to one of the font 506 * style names ("BOLD", "ITALIC", "BOLDITALIC"). This method returns 507 * Font.PLAIN if the argument is not one of the predefined style names. 508 * 509 * @param fontStyleName 510 * font style name. 511 * @return font style constant value corresponding to the font style name 512 * specified. 513 */ 514 private static int getFontStyle(String fontStyleName) { 515 int result = Font.PLAIN; 516 517 if (fontStyleName.toUpperCase().equals("BOLDITALIC")) { //$NON-NLS-1$ 518 result = Font.BOLD | Font.ITALIC; 519 } else if (fontStyleName.toUpperCase().equals("BOLD")) { //$NON-NLS-1$ 520 result = Font.BOLD; 521 } else if (fontStyleName.toUpperCase().equals("ITALIC")) { //$NON-NLS-1$ 522 result = Font.ITALIC; 523 } 524 525 return result; 526 } 527 528 /** 529 * Decodes the specified string which described the Font. The string should 530 * have the following format: fontname-style-pointsize. The style can be 531 * PLAIN, BOLD, BOLDITALIC, or ITALIC. 532 * 533 * @param str 534 * the string which describes the font. 535 * @return the Font from the specified string. 536 */ 537 public static Font decode(String str) { 538 // XXX: Documentation doesn't describe all cases, e.g. fonts face names 539 // with 540 // symbols that are suggested as delimiters in the documentation. 541 // In this decode implementation only ***-***-*** format is used with 542 // '-' 543 // as the delimiter to avoid unexpected parse results of font face names 544 // with spaces. 545 546 if (str == null) { 547 return DEFAULT_FONT; 548 } 549 550 StringTokenizer strTokens; 551 String delim = "-"; //$NON-NLS-1$ 552 String substr; 553 554 int fontSize = DEFAULT_FONT.size; 555 int fontStyle = DEFAULT_FONT.style; 556 String fontName = DEFAULT_FONT.name; 557 558 strTokens = new StringTokenizer(str.trim(), delim); 559 560 // Font Name 561 if (strTokens.hasMoreTokens()) { 562 fontName = strTokens.nextToken(); // first token is the font name 563 } 564 565 // Font Style or Size (if the style is undefined) 566 if (strTokens.hasMoreTokens()) { 567 substr = strTokens.nextToken(); 568 569 try { 570 // if second token is the font size 571 fontSize = Integer.parseInt(substr); 572 } catch (NumberFormatException e) { 573 // then second token is the font style 574 fontStyle = getFontStyle(substr); 575 } 576 577 } 578 579 // Font Size 580 if (strTokens.hasMoreTokens()) { 581 try { 582 fontSize = Integer.parseInt(strTokens.nextToken()); 583 } catch (NumberFormatException e) { 584 } 585 } 586 587 return new Font(fontName, fontStyle, fontSize); 588 } 589 590 /** 591 * Performs the specified affine transform to the Font and returns a new 592 * Font. 593 * 594 * @param trans 595 * the AffineTransform. 596 * @return the Font object. 597 * @throws IllegalArgumentException 598 * if affine transform parameter is null. 599 */ 600 @SuppressWarnings("unchecked") 601 public Font deriveFont(AffineTransform trans) { 602 603 if (trans == null) { 604 // awt.94=transform can not be null 605 throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$ 606 } 607 608 Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes 609 .clone(); 610 611 derivefRequestedAttributes.put(TextAttribute.TRANSFORM, new TransformAttribute(trans)); 612 613 return new Font(derivefRequestedAttributes); 614 615 } 616 617 /** 618 * Returns a new Font that is a copy of the current Font modified so that 619 * the size is the specified size. 620 * 621 * @param size 622 * the size of font. 623 * @return the Font object. 624 */ 625 @SuppressWarnings("unchecked") 626 public Font deriveFont(float size) { 627 Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes 628 .clone(); 629 derivefRequestedAttributes.put(TextAttribute.SIZE, new Float(size)); 630 return new Font(derivefRequestedAttributes); 631 } 632 633 /** 634 * Returns a new Font that is a copy of the current Font modified so that 635 * the style is the specified style. 636 * 637 * @param style 638 * the style of font. 639 * @return the Font object. 640 */ 641 @SuppressWarnings("unchecked") 642 public Font deriveFont(int style) { 643 Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes 644 .clone(); 645 646 if ((style & Font.BOLD) != 0) { 647 derivefRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); 648 } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) { 649 derivefRequestedAttributes.remove(TextAttribute.WEIGHT); 650 } 651 652 if ((style & Font.ITALIC) != 0) { 653 derivefRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); 654 } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) { 655 derivefRequestedAttributes.remove(TextAttribute.POSTURE); 656 } 657 658 return new Font(derivefRequestedAttributes); 659 } 660 661 /** 662 * Returns a new Font that is a copy of the current Font modified to match 663 * the specified style and with the specified affine transform applied to 664 * its glyphs. 665 * 666 * @param style 667 * the style of font. 668 * @param trans 669 * the AffineTransform. 670 * @return the Font object. 671 */ 672 @SuppressWarnings("unchecked") 673 public Font deriveFont(int style, AffineTransform trans) { 674 675 if (trans == null) { 676 // awt.94=transform can not be null 677 throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$ 678 } 679 Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes 680 .clone(); 681 682 if ((style & BOLD) != 0) { 683 derivefRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); 684 } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) { 685 derivefRequestedAttributes.remove(TextAttribute.WEIGHT); 686 } 687 688 if ((style & ITALIC) != 0) { 689 derivefRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); 690 } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) { 691 derivefRequestedAttributes.remove(TextAttribute.POSTURE); 692 } 693 derivefRequestedAttributes.put(TextAttribute.TRANSFORM, new TransformAttribute(trans)); 694 695 return new Font(derivefRequestedAttributes); 696 } 697 698 /** 699 * Returns a new Font that is a copy of the current Font modified so that 700 * the size and style are the specified size and style. 701 * 702 * @param style 703 * the style of font. 704 * @param size 705 * the size of font. 706 * @return the Font object. 707 */ 708 @SuppressWarnings("unchecked") 709 public Font deriveFont(int style, float size) { 710 Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes 711 .clone(); 712 713 if ((style & BOLD) != 0) { 714 derivefRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); 715 } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) { 716 derivefRequestedAttributes.remove(TextAttribute.WEIGHT); 717 } 718 719 if ((style & ITALIC) != 0) { 720 derivefRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); 721 } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) { 722 derivefRequestedAttributes.remove(TextAttribute.POSTURE); 723 } 724 725 derivefRequestedAttributes.put(TextAttribute.SIZE, new Float(size)); 726 return new Font(derivefRequestedAttributes); 727 728 } 729 730 /** 731 * Returns a new Font object with a new set of font attributes. 732 * 733 * @param attributes 734 * the map of attributes. 735 * @return the Font. 736 */ 737 @SuppressWarnings("unchecked") 738 public Font deriveFont(Map<? extends Attribute, ?> attributes) { 739 Attribute[] avalAttributes = this.getAvailableAttributes(); 740 741 Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes 742 .clone(); 743 Object currAttribute; 744 for (Attribute element : avalAttributes) { 745 currAttribute = attributes.get(element); 746 if (currAttribute != null) { 747 derivefRequestedAttributes.put(element, currAttribute); 748 } 749 } 750 return new Font(derivefRequestedAttributes); 751 } 752 753 /** 754 * Compares the specified Object with the current Font. 755 * 756 * @param obj 757 * the Object to be compared. 758 * @return true, if the specified Object is an instance of Font with the 759 * same family, size, and style as this Font, false otherwise. 760 */ 761 @Override 762 public boolean equals(Object obj) { 763 if (obj == this) { 764 return true; 765 } 766 767 if (obj != null) { 768 try { 769 Font font = (Font)obj; 770 771 return ((this.style == font.style) && (this.size == font.size) 772 && this.name.equals(font.name) && (this.pointSize == font.pointSize) && (this 773 .getTransform()).equals(font.getTransform())); 774 } catch (ClassCastException e) { 775 } 776 } 777 778 return false; 779 } 780 781 /** 782 * Gets the map of font's attributes. 783 * 784 * @return the map of font's attributes. 785 */ 786 @SuppressWarnings("unchecked") 787 public Map<TextAttribute, ?> getAttributes() { 788 return (Map<TextAttribute, ?>)fRequestedAttributes.clone(); 789 } 790 791 /** 792 * Gets the keys of all available attributes. 793 * 794 * @return the keys array of all available attributes. 795 */ 796 public Attribute[] getAvailableAttributes() { 797 Attribute[] attrs = { 798 TextAttribute.FAMILY, TextAttribute.POSTURE, TextAttribute.SIZE, 799 TextAttribute.TRANSFORM, TextAttribute.WEIGHT, TextAttribute.SUPERSCRIPT, 800 TextAttribute.WIDTH 801 }; 802 return attrs; 803 } 804 805 /** 806 * Gets the baseline for this character. 807 * 808 * @param c 809 * the character. 810 * @return the baseline for this character. 811 */ 812 public byte getBaselineFor(char c) { 813 // TODO: implement using TT BASE table data 814 return 0; 815 } 816 817 /** 818 * Gets the family name of the Font. 819 * 820 * @return the family name of the Font. 821 */ 822 public String getFamily() { 823 if (fRequestedAttributes != null) { 824 fRequestedAttributes.get(TextAttribute.FAMILY); 825 } 826 return null; 827 } 828 829 /** 830 * Returns the family name of this Font associated with the specified 831 * locale. 832 * 833 * @param l 834 * the locale. 835 * @return the family name of this Font associated with the specified 836 * locale. 837 */ 838 public String getFamily(Locale l) { 839 if (l == null) { 840 // awt.01='{0}' parameter is null 841 throw new NullPointerException(Messages.getString("awt.01", "Locale")); //$NON-NLS-1$ //$NON-NLS-2$ 842 } 843 return getFamily(); 844 } 845 846 /** 847 * Gets a Font with the specified attribute set. 848 * 849 * @param attributes 850 * the attributes to be assigned to the new Font. 851 * @return the Font. 852 */ 853 public static Font getFont(Map<? extends Attribute, ?> attributes) { 854 Font fnt = (Font)attributes.get(TextAttribute.FONT); 855 if (fnt != null) { 856 return fnt; 857 } 858 return new Font(attributes); 859 } 860 861 /** 862 * Gets a Font object from the system properties list with the specified 863 * name or returns the specified Font if there is no such property. 864 * 865 * @param sp 866 * the specified property name. 867 * @param f 868 * the Font. 869 * @return the Font object from the system properties list with the 870 * specified name or the specified Font if there is no such 871 * property. 872 */ 873 public static Font getFont(String sp, Font f) { 874 String pr = System.getProperty(sp); 875 if (pr == null) { 876 return f; 877 } 878 return decode(pr); 879 } 880 881 /** 882 * Gets a Font object from the system properties list with the specified 883 * name. 884 * 885 * @param sp 886 * the system property name. 887 * @return the Font, or null if there is no such property with the specified 888 * name. 889 */ 890 public static Font getFont(String sp) { 891 return getFont(sp, null); 892 } 893 894 /** 895 * Gets the font name. 896 * 897 * @return the font name. 898 */ 899 public String getFontName() { 900 if (fRequestedAttributes != null) { 901 fRequestedAttributes.get(TextAttribute.FAMILY); 902 } 903 return null; 904 } 905 906 /** 907 * Returns the font name associated with the specified locale. 908 * 909 * @param l 910 * the locale. 911 * @return the font name associated with the specified locale. 912 */ 913 public String getFontName(Locale l) { 914 return getFamily(); 915 } 916 917 /** 918 * Returns a LineMetrics object created with the specified parameters. 919 * 920 * @param chars 921 * the chars array. 922 * @param start 923 * the start offset. 924 * @param end 925 * the end offset. 926 * @param frc 927 * the FontRenderContext. 928 * @return the LineMetrics for the specified parameters. 929 */ 930 public LineMetrics getLineMetrics(char[] chars, int start, int end, FontRenderContext frc) { 931 if (frc == null) { 932 // awt.00=FontRenderContext is null 933 throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ 934 } 935 936 // FontMetrics fm = AndroidGraphics2D.getInstance().getFontMetrics(); 937 FontMetrics fm = new FontMetricsImpl(this); 938 float[] fmet = { 939 fm.getAscent(), fm.getDescent(), fm.getLeading() 940 }; 941 return new LineMetricsImpl(chars.length, fmet, null); 942 } 943 944 /** 945 * Returns a LineMetrics object created with the specified parameters. 946 * 947 * @param iter 948 * the CharacterIterator. 949 * @param start 950 * the start offset. 951 * @param end 952 * the end offset. 953 * @param frc 954 * the FontRenderContext. 955 * @return the LineMetrics for the specified parameters. 956 */ 957 public LineMetrics getLineMetrics(CharacterIterator iter, int start, int end, 958 FontRenderContext frc) { 959 960 if (frc == null) { 961 // awt.00=FontRenderContext is null 962 throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ 963 } 964 965 String resultString; 966 int iterCount; 967 968 iterCount = end - start; 969 if (iterCount < 0) { 970 resultString = ""; //$NON-NLS-1$ 971 } else { 972 char[] chars = new char[iterCount]; 973 int i = 0; 974 for (char c = iter.setIndex(start); c != CharacterIterator.DONE && (i < iterCount); c = iter 975 .next()) { 976 chars[i] = c; 977 i++; 978 } 979 resultString = new String(chars); 980 } 981 return this.getLineMetrics(resultString, frc); 982 } 983 984 /** 985 * Returns a LineMetrics object created with the specified parameters. 986 * 987 * @param str 988 * the String. 989 * @param frc 990 * the FontRenderContext. 991 * @return the LineMetrics for the specified parameters. 992 */ 993 public LineMetrics getLineMetrics(String str, FontRenderContext frc) { 994 // FontMetrics fm = AndroidGraphics2D.getInstance().getFontMetrics(); 995 FontMetrics fm = new FontMetricsImpl(this); 996 float[] fmet = { 997 fm.getAscent(), fm.getDescent(), fm.getLeading() 998 }; 999 // Log.i("FONT FMET", fmet.toString()); 1000 return new LineMetricsImpl(str.length(), fmet, null); 1001 1002 } 1003 1004 /** 1005 * Returns a LineMetrics object created with the specified parameters. 1006 * 1007 * @param str 1008 * the String. 1009 * @param start 1010 * the start offset. 1011 * @param end 1012 * the end offset. 1013 * @param frc 1014 * the FontRenderContext. 1015 * @return the LineMetrics for the specified parameters. 1016 */ 1017 public LineMetrics getLineMetrics(String str, int start, int end, FontRenderContext frc) { 1018 return this.getLineMetrics(str.substring(start, end), frc); 1019 } 1020 1021 /** 1022 * Gets the logical bounds of the specified String in the specified 1023 * FontRenderContext. The logical bounds contains the origin, ascent, 1024 * advance, and height. 1025 * 1026 * @param ci 1027 * the specified CharacterIterator. 1028 * @param start 1029 * the start offset. 1030 * @param end 1031 * the end offset. 1032 * @param frc 1033 * the FontRenderContext. 1034 * @return a Rectangle2D object. 1035 */ 1036 public Rectangle2D getStringBounds(CharacterIterator ci, int start, int end, 1037 FontRenderContext frc) { 1038 int first = ci.getBeginIndex(); 1039 int finish = ci.getEndIndex(); 1040 char[] chars; 1041 1042 if (start < first) { 1043 // awt.95=Wrong start index: {0} 1044 throw new IndexOutOfBoundsException(Messages.getString("awt.95", start)); //$NON-NLS-1$ 1045 } 1046 if (end > finish) { 1047 // awt.96=Wrong finish index: {0} 1048 throw new IndexOutOfBoundsException(Messages.getString("awt.96", end)); //$NON-NLS-1$ 1049 } 1050 if (start > end) { 1051 // awt.97=Wrong range length: {0} 1052 throw new IndexOutOfBoundsException(Messages.getString("awt.97", //$NON-NLS-1$ 1053 (end - start))); 1054 } 1055 1056 if (frc == null) { 1057 throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ 1058 } 1059 1060 chars = new char[end - start]; 1061 1062 ci.setIndex(start); 1063 for (int i = 0; i < chars.length; i++) { 1064 chars[i] = ci.current(); 1065 ci.next(); 1066 } 1067 1068 return this.getStringBounds(chars, 0, chars.length, frc); 1069 1070 } 1071 1072 /** 1073 * Gets the logical bounds of the specified String in the specified 1074 * FontRenderContext. The logical bounds contains the origin, ascent, 1075 * advance, and height. 1076 * 1077 * @param str 1078 * the specified String. 1079 * @param frc 1080 * the FontRenderContext. 1081 * @return a Rectangle2D object. 1082 */ 1083 public Rectangle2D getStringBounds(String str, FontRenderContext frc) { 1084 char[] chars = str.toCharArray(); 1085 return this.getStringBounds(chars, 0, chars.length, frc); 1086 1087 } 1088 1089 /** 1090 * Gets the logical bounds of the specified String in the specified 1091 * FontRenderContext. The logical bounds contains the origin, ascent, 1092 * advance, and height. 1093 * 1094 * @param str 1095 * the specified String. 1096 * @param start 1097 * the start offset. 1098 * @param end 1099 * the end offset. 1100 * @param frc 1101 * the FontRenderContext. 1102 * @return a Rectangle2D object. 1103 */ 1104 public Rectangle2D getStringBounds(String str, int start, int end, FontRenderContext frc) { 1105 1106 return this.getStringBounds((str.substring(start, end)), frc); 1107 } 1108 1109 /** 1110 * Gets the logical bounds of the specified String in the specified 1111 * FontRenderContext. The logical bounds contains the origin, ascent, 1112 * advance, and height. 1113 * 1114 * @param chars 1115 * the specified character array. 1116 * @param start 1117 * the start offset. 1118 * @param end 1119 * the end offset. 1120 * @param frc 1121 * the FontRenderContext. 1122 * @return a Rectangle2D object. 1123 */ 1124 public Rectangle2D getStringBounds(char[] chars, int start, int end, FontRenderContext frc) { 1125 if (start < 0) { 1126 // awt.95=Wrong start index: {0} 1127 throw new IndexOutOfBoundsException(Messages.getString("awt.95", start)); //$NON-NLS-1$ 1128 } 1129 if (end > chars.length) { 1130 // awt.96=Wrong finish index: {0} 1131 throw new IndexOutOfBoundsException(Messages.getString("awt.96", end)); //$NON-NLS-1$ 1132 } 1133 if (start > end) { 1134 // awt.97=Wrong range length: {0} 1135 throw new IndexOutOfBoundsException(Messages.getString("awt.97", //$NON-NLS-1$ 1136 (end - start))); 1137 } 1138 1139 if (frc == null) { 1140 throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ 1141 } 1142 1143 FontPeerImpl peer = (FontPeerImpl)this.getPeer(); 1144 1145 final int TRANSFORM_MASK = AffineTransform.TYPE_GENERAL_ROTATION 1146 | AffineTransform.TYPE_GENERAL_TRANSFORM; 1147 Rectangle2D bounds; 1148 1149 AffineTransform transform = getTransform(); 1150 1151 // XXX: for transforms where an angle between basis vectors is not 90 1152 // degrees Rectanlge2D class doesn't fit as Logical bounds. 1153 if ((transform.getType() & TRANSFORM_MASK) == 0) { 1154 int width = 0; 1155 for (int i = start; i < end; i++) { 1156 width += peer.charWidth(chars[i]); 1157 } 1158 // LineMetrics nlm = peer.getLineMetrics(); 1159 1160 LineMetrics nlm = getLineMetrics(chars, start, end, frc); 1161 1162 bounds = transform.createTransformedShape( 1163 new Rectangle2D.Float(0, -nlm.getAscent(), width, nlm.getHeight())) 1164 .getBounds2D(); 1165 } else { 1166 int len = end - start; 1167 char[] subChars = new char[len]; 1168 System.arraycopy(chars, start, subChars, 0, len); 1169 bounds = createGlyphVector(frc, subChars).getLogicalBounds(); 1170 } 1171 return bounds; 1172 } 1173 1174 /** 1175 * Gets the character's maximum bounds as defined in the specified 1176 * FontRenderContext. 1177 * 1178 * @param frc 1179 * the FontRenderContext. 1180 * @return the character's maximum bounds. 1181 */ 1182 public Rectangle2D getMaxCharBounds(FontRenderContext frc) { 1183 if (frc == null) { 1184 // awt.00=FontRenderContext is null 1185 throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ 1186 } 1187 1188 FontPeerImpl peer = (FontPeerImpl)this.getPeer(); 1189 1190 Rectangle2D bounds = peer.getMaxCharBounds(frc); 1191 AffineTransform transform = getTransform(); 1192 // !! Documentation doesn't describe meaning of max char bounds 1193 // for the fonts that have rotate transforms. For all transforms 1194 // returned bounds are the bounds of transformed maxCharBounds 1195 // Rectangle2D that corresponds to the font with identity transform. 1196 // TODO: resolve this issue to return correct bounds 1197 bounds = transform.createTransformedShape(bounds).getBounds2D(); 1198 1199 return bounds; 1200 } 1201 1202 /** 1203 * Returns a new GlyphVector object performing full layout of the text. 1204 * 1205 * @param frc 1206 * the FontRenderContext. 1207 * @param chars 1208 * the character array to be layout. 1209 * @param start 1210 * the start offset of the text to use for the GlyphVector. 1211 * @param count 1212 * the count of characters to use for the GlyphVector. 1213 * @param flags 1214 * the flag indicating text direction: LAYOUT_RIGHT_TO_LEFT, 1215 * LAYOUT_LEFT_TO_RIGHT. 1216 * @return the GlyphVector. 1217 */ 1218 public GlyphVector layoutGlyphVector(FontRenderContext frc, char[] chars, int start, int count, 1219 int flags) { 1220 // TODO: implement method for bidirectional text. 1221 // At the moment only LTR and RTL texts supported. 1222 if (start < 0) { 1223 // awt.95=Wrong start index: {0} 1224 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.95", //$NON-NLS-1$ 1225 start)); 1226 } 1227 1228 if (count < 0) { 1229 // awt.98=Wrong count value, can not be negative: {0} 1230 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.98", //$NON-NLS-1$ 1231 count)); 1232 } 1233 1234 if (start + count > chars.length) { 1235 // awt.99=Wrong [start + count] is out of range: {0} 1236 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.99", //$NON-NLS-1$ 1237 (start + count))); 1238 } 1239 1240 char[] out = new char[count]; 1241 System.arraycopy(chars, start, out, 0, count); 1242 1243 return new CommonGlyphVector(out, frc, this, flags); 1244 } 1245 1246 /** 1247 * Returns the String representation of this Font. 1248 * 1249 * @return the String representation of this Font. 1250 */ 1251 @Override 1252 public String toString() { 1253 String stl = "plain"; //$NON-NLS-1$ 1254 String result; 1255 1256 if (this.isBold() && this.isItalic()) { 1257 stl = "bolditalic"; //$NON-NLS-1$ 1258 } 1259 if (this.isBold() && !this.isItalic()) { 1260 stl = "bold"; //$NON-NLS-1$ 1261 } 1262 1263 if (!this.isBold() && this.isItalic()) { 1264 stl = "italic"; //$NON-NLS-1$ 1265 } 1266 1267 result = this.getClass().getName() + "[family=" + this.getFamily() + //$NON-NLS-1$ 1268 ",name=" + this.name + //$NON-NLS-1$ 1269 ",style=" + stl + //$NON-NLS-1$ 1270 ",size=" + this.size + "]"; //$NON-NLS-1$ //$NON-NLS-2$ 1271 return result; 1272 } 1273 1274 /** 1275 * Gets the postscript name of this Font. 1276 * 1277 * @return the postscript name of this Font. 1278 */ 1279 public String getPSName() { 1280 FontPeerImpl peer = (FontPeerImpl)this.getPeer(); 1281 return peer.getPSName(); 1282 } 1283 1284 /** 1285 * Gets the logical name of this Font. 1286 * 1287 * @return the logical name of this Font. 1288 */ 1289 public String getName() { 1290 return (this.name); 1291 } 1292 1293 /** 1294 * Gets the peer of this Font. 1295 * 1296 * @return the peer of this Font. 1297 * @deprecated Font rendering is platform independent now. 1298 */ 1299 @Deprecated 1300 public java.awt.peer.FontPeer getPeer() { 1301 if (fontPeer == null) { 1302 fontPeer = (FontPeerImpl)Toolkit.getDefaultToolkit().getGraphicsFactory().getFontPeer( 1303 this); 1304 } 1305 return fontPeer; 1306 1307 } 1308 1309 /** 1310 * Gets the transform acting on this Font (from the Font's attributes). 1311 * 1312 * @return the transformation of this Font. 1313 */ 1314 public AffineTransform getTransform() { 1315 Object transform = fRequestedAttributes.get(TextAttribute.TRANSFORM); 1316 1317 if (transform != null) { 1318 if (transform instanceof TransformAttribute) { 1319 return ((TransformAttribute)transform).getTransform(); 1320 } 1321 if (transform instanceof AffineTransform) { 1322 return new AffineTransform((AffineTransform)transform); 1323 } 1324 } else { 1325 transform = new AffineTransform(); 1326 } 1327 return (AffineTransform)transform; 1328 1329 } 1330 1331 /** 1332 * Checks if this font is transformed or not. 1333 * 1334 * @return true, if this font is transformed, false otherwise. 1335 */ 1336 public boolean isTransformed() { 1337 return this.transformed; 1338 } 1339 1340 /** 1341 * Checks if this font has plain style or not. 1342 * 1343 * @return true, if this font has plain style, false otherwise. 1344 */ 1345 public boolean isPlain() { 1346 return (this.style == PLAIN); 1347 } 1348 1349 /** 1350 * Checks if this font has italic style or not. 1351 * 1352 * @return true, if this font has italic style, false otherwise. 1353 */ 1354 public boolean isItalic() { 1355 return (this.style & ITALIC) != 0; 1356 } 1357 1358 /** 1359 * Checks if this font has bold style or not. 1360 * 1361 * @return true, if this font has bold style, false otherwise. 1362 */ 1363 public boolean isBold() { 1364 return (this.style & BOLD) != 0; 1365 } 1366 1367 /** 1368 * Returns true if this Font has uniform line metrics. 1369 * 1370 * @return true if this Font has uniform line metrics, false otherwise. 1371 */ 1372 public boolean hasUniformLineMetrics() { 1373 FontPeerImpl peer = (FontPeerImpl)this.getPeer(); 1374 return peer.hasUniformLineMetrics(); 1375 } 1376 1377 /** 1378 * Returns hash code of this Font object. 1379 * 1380 * @return the hash code of this Font object. 1381 */ 1382 @Override 1383 public int hashCode() { 1384 HashCode hash = new HashCode(); 1385 1386 hash.append(this.name); 1387 hash.append(this.style); 1388 hash.append(this.size); 1389 1390 return hash.hashCode(); 1391 } 1392 1393 /** 1394 * Gets the style of this Font. 1395 * 1396 * @return the style of this Font. 1397 */ 1398 public int getStyle() { 1399 return this.style; 1400 } 1401 1402 /** 1403 * Gets the size of this Font. 1404 * 1405 * @return the size of this Font. 1406 */ 1407 public int getSize() { 1408 return this.size; 1409 } 1410 1411 /** 1412 * Gets the number of glyphs for this Font. 1413 * 1414 * @return the number of glyphs for this Font. 1415 */ 1416 public int getNumGlyphs() { 1417 if (numGlyphs == -1) { 1418 FontPeerImpl peer = (FontPeerImpl)this.getPeer(); 1419 this.numGlyphs = peer.getNumGlyphs(); 1420 } 1421 return this.numGlyphs; 1422 } 1423 1424 /** 1425 * Gets the glyphCode which is used as default glyph when this Font does not 1426 * have a glyph for a specified Unicode. 1427 * 1428 * @return the missing glyph code. 1429 */ 1430 public int getMissingGlyphCode() { 1431 if (missingGlyphCode == -1) { 1432 FontPeerImpl peer = (FontPeerImpl)this.getPeer(); 1433 this.missingGlyphCode = peer.getMissingGlyphCode(); 1434 } 1435 return this.missingGlyphCode; 1436 } 1437 1438 /** 1439 * Gets the float value of font's size. 1440 * 1441 * @return the float value of font's size. 1442 */ 1443 public float getSize2D() { 1444 return this.pointSize; 1445 } 1446 1447 /** 1448 * Gets the italic angle of this Font. 1449 * 1450 * @return the italic angle of this Font. 1451 */ 1452 public float getItalicAngle() { 1453 FontPeerImpl peer = (FontPeerImpl)this.getPeer(); 1454 return peer.getItalicAngle(); 1455 } 1456 1457 /** 1458 * Creates the font with the specified font format and font file. 1459 * 1460 * @param fontFormat 1461 * the font format. 1462 * @param fontFile 1463 * the file object represented the input data for the font. 1464 * @return the Font. 1465 * @throws FontFormatException 1466 * is thrown if fontFile does not contain the required font 1467 * tables for the specified format. 1468 * @throws IOException 1469 * signals that an I/O exception has occurred. 1470 */ 1471 public static Font createFont(int fontFormat, File fontFile) throws FontFormatException, 1472 IOException { 1473 // ???AWT not supported 1474 InputStream is = new FileInputStream(fontFile); 1475 try { 1476 return createFont(fontFormat, is); 1477 } finally { 1478 is.close(); 1479 } 1480 } 1481 1482 /** 1483 * Creates the font with the specified font format and input stream. 1484 * 1485 * @param fontFormat 1486 * the font format. 1487 * @param fontStream 1488 * the input stream represented input data for the font. 1489 * @return the Font. 1490 * @throws FontFormatException 1491 * is thrown if fontFile does not contain the required font 1492 * tables for the specified format. 1493 * @throws IOException 1494 * signals that an I/O exception has occurred. 1495 */ 1496 public static Font createFont(int fontFormat, InputStream fontStream) 1497 throws FontFormatException, IOException { 1498 1499 // ???AWT not supported 1500 1501 BufferedInputStream buffStream; 1502 int bRead = 0; 1503 int size = 8192; 1504 // memory page size, for the faster reading 1505 byte buf[] = new byte[size]; 1506 1507 if (fontFormat != TRUETYPE_FONT) { // awt.9A=Unsupported font format 1508 throw new IllegalArgumentException(Messages.getString("awt.9A")); //$NON-NLS-1$ 1509 } 1510 1511 /* Get font file in system-specific directory */ 1512 1513 File fontFile = Toolkit.getDefaultToolkit().getGraphicsFactory().getFontManager() 1514 .getTempFontFile(); 1515 1516 // BEGIN android-modified 1517 buffStream = new BufferedInputStream(fontStream, 8192); 1518 // END android-modified 1519 FileOutputStream fOutStream = new FileOutputStream(fontFile); 1520 1521 bRead = buffStream.read(buf, 0, size); 1522 1523 while (bRead != -1) { 1524 fOutStream.write(buf, 0, bRead); 1525 bRead = buffStream.read(buf, 0, size); 1526 } 1527 1528 buffStream.close(); 1529 fOutStream.close(); 1530 1531 Font font = null; 1532 1533 font = Toolkit.getDefaultToolkit().getGraphicsFactory().embedFont( 1534 fontFile.getAbsolutePath()); 1535 if (font == null) { // awt.9B=Can't create font - bad font data 1536 throw new FontFormatException(Messages.getString("awt.9B")); //$NON-NLS-1$ 1537 } 1538 return font; 1539 } 1540 1541} 1542