1 /*
   2  * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.font;
  27 
  28 import java.awt.Font;
  29 import java.awt.font.FontRenderContext;
  30 import java.awt.geom.AffineTransform;
  31 import java.lang.ref.Reference;
  32 import java.lang.ref.SoftReference;
  33 import java.util.concurrent.ConcurrentHashMap;
  34 import java.util.Locale;
  35 
  36 public abstract class Font2D {
  37 
  38     /* Note: JRE and FONT_CONFIG ranks are identical. I don't know of a reason
  39      * to distingish these. Possibly if a user adds fonts to the JRE font
  40      * directory that are the same font as the ones specified in the font
  41      * configuration but that is more likely to be the legitimate intention
  42      * than a problem. One reason why these should be the same is that on
  43      * Linux the JRE fonts ARE the font configuration fonts, and although I
  44      * believe all are assigned FONT_CONFIG rank, it is conceivable that if
  45      * this were not so, that some JRE font would not be allowed to joint the
  46      * family of its siblings which were assigned FONT_CONFIG rank. Giving
  47      * them the same rank is the easy solution for now at least.
  48      */
  49     public static final int FONT_CONFIG_RANK   = 2;
  50     public static final int JRE_RANK     = 2;
  51     public static final int TTF_RANK     = 3;
  52     public static final int TYPE1_RANK   = 4;
  53     public static final int NATIVE_RANK  = 5;
  54     public static final int UNKNOWN_RANK = 6;
  55     public static final int DEFAULT_RANK = 4;
  56 
  57     private static final String[] boldNames = {
  58         "bold", "demibold", "demi-bold", "demi bold", "negreta", "demi", };
  59 
  60     private static final String[] italicNames = {
  61         "italic", "cursiva", "oblique", "inclined", };
  62 
  63     private static final String[] boldItalicNames = {
  64           "bolditalic", "bold-italic", "bold italic",
  65           "boldoblique", "bold-oblique", "bold oblique",
  66           "demibold italic", "negreta cursiva","demi oblique", };
  67 
  68     private static final FontRenderContext DEFAULT_FRC =
  69         new FontRenderContext(null, false, false);
  70 
  71     public Font2DHandle handle;
  72     protected String familyName;           /* Family font name (english) */
  73     protected String fullName;             /* Full font name (english)   */
  74     protected int style = Font.PLAIN;
  75     protected FontFamily family;
  76     protected int fontRank = DEFAULT_RANK;
  77 
  78     /*
  79      * A mapper can be independent of the strike.
  80      * Perhaps the reference to the mapper ought to be held on the
  81      * scaler, as it may be implemented via scaler functionality anyway
  82      * and so the mapper would be useless if its native portion was
  83      * freed when the scaler was GC'd.
  84      */
  85     protected CharToGlyphMapper mapper;
  86 
  87     /*
  88      * The strike cache is maintained per "Font2D" as that is the
  89      * principal object by which you look up fonts.
  90      * It means more Hashmaps, but look ups can be quicker because
  91      * the map will have fewer entries, and there's no need to try to
  92      * make the Font2D part of the key.
  93      */
  94     protected ConcurrentHashMap<FontStrikeDesc, Reference<FontStrike>>
  95         strikeCache = new ConcurrentHashMap<>();
  96 
  97     /* Store the last Strike in a Reference object.
  98      * Similarly to the strike that was stored on a C++ font object,
  99      * this is an optimisation which helps if multiple clients (ie
 100      * typically SunGraphics2D instances) are using the same font, then
 101      * as may be typical of many UIs, they are probably using it in the
 102      * same style, so it can be a win to first quickly check if the last
 103      * strike obtained from this Font2D satifies the needs of the next
 104      * client too.
 105      * This pre-supposes that a FontStrike is a shareable object, which
 106      * it should.
 107      */
 108     protected Reference<FontStrike> lastFontStrike = new SoftReference<>(null);
 109 
 110     /*
 111      * POSSIBLE OPTIMISATION:
 112      * Array of length 1024 elements of 64 bits indicating if a font
 113      * contains these. This kind of information can be shared between
 114      * all point sizes.
 115      * if corresponding bit in knownBitmaskMap is set then canDisplayBitmaskMap
 116      * is valid. This is 16Kbytes of data per composite font style.
 117      * What about UTF-32 and surrogates?
 118      * REMIND: This is too much storage. Probably can only cache this
 119      * information for latin range, although possibly OK to store all
 120      * for just the "logical" fonts.
 121      * Or instead store arrays of subranges of 1024 bits (128 bytes) in
 122      * the range below surrogate pairs.
 123      */
 124 //     protected long[] knownBitmaskMap;
 125 //     protected long[] canDisplayBitmaskMap;
 126 
 127     /* Returns the "real" style of this Font2D. Eg the font face
 128      * Lucida Sans Bold" has a real style of Font.BOLD, even though
 129      * it may be able to used to simulate bold italic
 130      */
 131     public int getStyle() {
 132         return style;
 133     }
 134     protected void setStyle() {
 135 
 136         String fName = fullName.toLowerCase();
 137 
 138         for (int i=0; i < boldItalicNames.length; i++) {
 139             if (fName.indexOf(boldItalicNames[i]) != -1) {
 140                 style = Font.BOLD|Font.ITALIC;
 141                 return;
 142             }
 143         }
 144 
 145         for (int i=0; i < italicNames.length; i++) {
 146             if (fName.indexOf(italicNames[i]) != -1) {
 147                 style = Font.ITALIC;
 148                 return;
 149             }
 150         }
 151 
 152         for (int i=0; i < boldNames.length; i++) {
 153             if (fName.indexOf(boldNames[i]) != -1 ) {
 154                 style = Font.BOLD;
 155                 return;
 156             }
 157         }
 158     }
 159 
 160     public static final int FWIDTH_NORMAL = 5;    // OS/2 usWidthClass
 161     public static final int FWEIGHT_NORMAL = 400; // OS/2 usWeightClass
 162     public static final int FWEIGHT_BOLD   = 700; // OS/2 usWeightClass
 163 
 164     public int getWidth() {
 165         return FWIDTH_NORMAL;
 166     }
 167 
 168     public int getWeight() {
 169         if ((style & Font.BOLD) !=0) {
 170             return FWEIGHT_BOLD;
 171         } else {
 172             return FWEIGHT_NORMAL;
 173         }
 174     }
 175 
 176     int getRank() {
 177         return fontRank;
 178     }
 179 
 180     void setRank(int rank) {
 181         fontRank = rank;
 182     }
 183 
 184     abstract CharToGlyphMapper getMapper();
 185 
 186 
 187 
 188     /* This isn't very efficient but its infrequently used.
 189      * StandardGlyphVector uses it when the client assigns the glyph codes.
 190      * These may not be valid. This validates them substituting the missing
 191      * glyph elsewhere.
 192      */
 193     protected int getValidatedGlyphCode(int glyphCode) {
 194         if (glyphCode < 0 || glyphCode >= getMapper().getNumGlyphs()) {
 195             glyphCode = getMapper().getMissingGlyphCode();
 196         }
 197         return glyphCode;
 198     }
 199 
 200     /*
 201      * Creates an appropriate strike for the Font2D subclass
 202      */
 203     abstract FontStrike createStrike(FontStrikeDesc desc);
 204 
 205     /* this may be useful for APIs like canDisplay where the answer
 206      * is dependent on the font and its scaler, but not the strike.
 207      * If no strike has ever been returned, then create a one that matches
 208      * this font with the default FRC. It will become the lastStrike and
 209      * there's a good chance that the next call will be to get exactly that
 210      * strike.
 211      */
 212     public FontStrike getStrike(Font font) {
 213         FontStrike strike = lastFontStrike.get();
 214         if (strike != null) {
 215             return strike;
 216         } else {
 217             return getStrike(font, DEFAULT_FRC);
 218         }
 219     }
 220 
 221     /* SunGraphics2D has font, tx, aa and fm. From this info
 222      * can get a Strike object from the cache, creating it if necessary.
 223      * This code is designed for multi-threaded access.
 224      * For that reason it creates a local FontStrikeDesc rather than filling
 225      * in a shared one. Up to two AffineTransforms and one FontStrikeDesc will
 226      * be created by every lookup. This appears to perform more than
 227      * adequately. But it may make sense to expose FontStrikeDesc
 228      * as a parameter so a caller can use its own.
 229      * In such a case if a FontStrikeDesc is stored as a key then
 230      * we would need to use a private copy.
 231      *
 232      * Note that this code doesn't prevent two threads from creating
 233      * two different FontStrike instances and having one of the threads
 234      * overwrite the other in the map. This is likely to be a rare
 235      * occurrence and the only consequence is that these callers will have
 236      * different instances of the strike, and there'd be some duplication of
 237      * population of the strikes. However since users of these strikes are
 238      * transient, then the one that was overwritten would soon be freed.
 239      * If there is any problem then a small synchronized block would be
 240      * required with its attendant consequences for MP scaleability.
 241      */
 242     public FontStrike getStrike(Font font, AffineTransform devTx,
 243                                 int aa, int fm) {
 244 
 245         /* Create the descriptor which is used to identify a strike
 246          * in the strike cache/map. A strike is fully described by
 247          * the attributes of this descriptor.
 248          */
 249         /* REMIND: generating garbage and doing computation here in order
 250          * to include pt size in the tx just for a lookup! Figure out a
 251          * better way.
 252          */
 253         double ptSize = font.getSize2D();
 254         AffineTransform glyphTx = (AffineTransform)devTx.clone();
 255         glyphTx.scale(ptSize, ptSize);
 256         if (font.isTransformed()) {
 257             glyphTx.concatenate(font.getTransform());
 258         }
 259         if (glyphTx.getTranslateX() != 0 || glyphTx.getTranslateY() != 0) {
 260             glyphTx.setTransform(glyphTx.getScaleX(),
 261                                  glyphTx.getShearY(),
 262                                  glyphTx.getShearX(),
 263                                  glyphTx.getScaleY(),
 264                                  0.0, 0.0);
 265         }
 266         FontStrikeDesc desc = new FontStrikeDesc(devTx, glyphTx,
 267                                                  font.getStyle(), aa, fm);
 268         return getStrike(desc, false);
 269     }
 270 
 271     public FontStrike getStrike(Font font, AffineTransform devTx,
 272                                 AffineTransform glyphTx,
 273                                 int aa, int fm) {
 274 
 275         /* Create the descriptor which is used to identify a strike
 276          * in the strike cache/map. A strike is fully described by
 277          * the attributes of this descriptor.
 278          */
 279         FontStrikeDesc desc = new FontStrikeDesc(devTx, glyphTx,
 280                                                  font.getStyle(), aa, fm);
 281         return getStrike(desc, false);
 282     }
 283 
 284     public FontStrike getStrike(Font font, FontRenderContext frc) {
 285 
 286         AffineTransform at = frc.getTransform();
 287         double ptSize = font.getSize2D();
 288         at.scale(ptSize, ptSize);
 289         if (font.isTransformed()) {
 290             at.concatenate(font.getTransform());
 291             if (at.getTranslateX() != 0 || at.getTranslateY() != 0) {
 292                 at.setTransform(at.getScaleX(),
 293                                 at.getShearY(),
 294                                 at.getShearX(),
 295                                 at.getScaleY(),
 296                                 0.0, 0.0);
 297             }
 298         }
 299         int aa = FontStrikeDesc.getAAHintIntVal(this, font, frc);
 300         int fm = FontStrikeDesc.getFMHintIntVal(frc.getFractionalMetricsHint());
 301         FontStrikeDesc desc = new FontStrikeDesc(frc.getTransform(),
 302                                                  at, font.getStyle(),
 303                                                  aa, fm);
 304         return getStrike(desc, false);
 305     }
 306 
 307     FontStrike getStrike(FontStrikeDesc desc) {
 308         return getStrike(desc, true);
 309     }
 310 
 311     private FontStrike getStrike(FontStrikeDesc desc, boolean copy) {
 312         /* Before looking in the map, see if the descriptor matches the
 313          * last strike returned from this Font2D. This should often be a win
 314          * since its common for the same font, in the same size to be
 315          * used frequently, for example in many parts of a UI.
 316          *
 317          * If its not the same then we use the descriptor to locate a
 318          * Reference to the strike. If it exists and points to a strike,
 319          * then we update the last strike to refer to that and return it.
 320          *
 321          * If the key isn't in the map, or its reference object has been
 322          * collected, then we create a new strike, put it in the map and
 323          * set it to be the last strike.
 324          */
 325         FontStrike strike = lastFontStrike.get();
 326         if (strike != null && desc.equals(strike.desc)) {
 327             //strike.lastlookupTime = System.currentTimeMillis();
 328             return strike;
 329         } else {
 330             Reference<FontStrike> strikeRef = strikeCache.get(desc);
 331             if (strikeRef != null) {
 332                 strike = strikeRef.get();
 333                 if (strike != null) {
 334                     //strike.lastlookupTime = System.currentTimeMillis();
 335                     lastFontStrike = new SoftReference<>(strike);
 336                     StrikeCache.refStrike(strike);
 337                     return strike;
 338                 }
 339             }
 340             /* When we create a new FontStrike instance, we *must*
 341              * ask the StrikeCache for a reference. We must then ensure
 342              * this reference remains reachable, by storing it in the
 343              * Font2D's strikeCache map.
 344              * So long as the Reference is there (reachable) then if the
 345              * reference is cleared, it will be enqueued for disposal.
 346              * If for some reason we explicitly remove this reference, it
 347              * must only be done when holding a strong reference to the
 348              * referent (the FontStrike), or if the reference is cleared,
 349              * then we must explicitly "dispose" of the native resources.
 350              * The only place this currently happens is in this same method,
 351              * where we find a cleared reference and need to overwrite it
 352              * here with a new reference.
 353              * Clearing the whilst holding a strong reference, should only
 354              * be done if the
 355              */
 356             if (copy) {
 357                 desc = new FontStrikeDesc(desc);
 358             }
 359             strike = createStrike(desc);
 360             //StrikeCache.addStrike();
 361             /* If we are creating many strikes on this font which
 362              * involve non-quadrant rotations, or more general
 363              * transforms which include shears, then force the use
 364              * of weak references rather than soft references.
 365              * This means that it won't live much beyond the next GC,
 366              * which is what we want for what is likely a transient strike.
 367              */
 368             int txType = desc.glyphTx.getType();
 369             if (txType == AffineTransform.TYPE_GENERAL_TRANSFORM ||
 370                 (txType & AffineTransform.TYPE_GENERAL_ROTATION) != 0 &&
 371                 strikeCache.size() > 10) {
 372                 strikeRef = StrikeCache.getStrikeRef(strike, true);
 373             } else {
 374                 strikeRef = StrikeCache.getStrikeRef(strike);
 375             }
 376             strikeCache.put(desc, strikeRef);
 377             //strike.lastlookupTime = System.currentTimeMillis();
 378             lastFontStrike = new SoftReference<>(strike);
 379             StrikeCache.refStrike(strike);
 380             return strike;
 381         }
 382     }
 383 
 384     void removeFromCache(FontStrikeDesc desc) {
 385         Reference<FontStrike> ref = strikeCache.get(desc);
 386         if (ref != null) {
 387             Object o = ref.get();
 388             if (o == null) {
 389                 strikeCache.remove(desc);
 390             }
 391         }
 392     }
 393 
 394     /**
 395      * The length of the metrics array must be >= 8.  This method will
 396      * store the following elements in that array before returning:
 397      *    metrics[0]: ascent
 398      *    metrics[1]: descent
 399      *    metrics[2]: leading
 400      *    metrics[3]: max advance
 401      *    metrics[4]: strikethrough offset
 402      *    metrics[5]: strikethrough thickness
 403      *    metrics[6]: underline offset
 404      *    metrics[7]: underline thickness
 405      */
 406     public void getFontMetrics(Font font, AffineTransform at,
 407                                Object aaHint, Object fmHint,
 408                                float metrics[]) {
 409         /* This is called in just one place in Font with "at" == identity.
 410          * Perhaps this can be eliminated.
 411          */
 412         int aa = FontStrikeDesc.getAAHintIntVal(aaHint, this, font.getSize());
 413         int fm = FontStrikeDesc.getFMHintIntVal(fmHint);
 414         FontStrike strike = getStrike(font, at, aa, fm);
 415         StrikeMetrics strikeMetrics = strike.getFontMetrics();
 416         metrics[0] = strikeMetrics.getAscent();
 417         metrics[1] = strikeMetrics.getDescent();
 418         metrics[2] = strikeMetrics.getLeading();
 419         metrics[3] = strikeMetrics.getMaxAdvance();
 420 
 421         getStyleMetrics(font.getSize2D(), metrics, 4);
 422     }
 423 
 424     /**
 425      * The length of the metrics array must be >= offset+4, and offset must be
 426      * >= 0.  Typically offset is 4.  This method will
 427      * store the following elements in that array before returning:
 428      *    metrics[off+0]: strikethrough offset
 429      *    metrics[off+1]: strikethrough thickness
 430      *    metrics[off+2]: underline offset
 431      *    metrics[off+3]: underline thickness
 432      *
 433      * Note that this implementation simply returns default values;
 434      * subclasses can override this method to provide more accurate values.
 435      */
 436     public void getStyleMetrics(float pointSize, float[] metrics, int offset) {
 437         metrics[offset] = -metrics[0] / 2.5f;
 438         metrics[offset+1] = pointSize / 12;
 439         metrics[offset+2] = metrics[offset+1] / 1.5f;
 440         metrics[offset+3] = metrics[offset+1];
 441     }
 442 
 443     /**
 444      * The length of the metrics array must be >= 4.  This method will
 445      * store the following elements in that array before returning:
 446      *    metrics[0]: ascent
 447      *    metrics[1]: descent
 448      *    metrics[2]: leading
 449      *    metrics[3]: max advance
 450      */
 451     public void getFontMetrics(Font font, FontRenderContext frc,
 452                                float metrics[]) {
 453         StrikeMetrics strikeMetrics = getStrike(font, frc).getFontMetrics();
 454         metrics[0] = strikeMetrics.getAscent();
 455         metrics[1] = strikeMetrics.getDescent();
 456         metrics[2] = strikeMetrics.getLeading();
 457         metrics[3] = strikeMetrics.getMaxAdvance();
 458     }
 459 
 460     /* Currently the layout code calls this. May be better for layout code
 461      * to check the font class before attempting to run, rather than needing
 462      * to promote this method up from TrueTypeFont
 463      */
 464     protected byte[] getTableBytes(int tag) {
 465         return null;
 466     }
 467 
 468     /* implemented for fonts backed by an sfnt that has
 469      * OpenType or AAT layout tables.
 470      */
 471     protected long getLayoutTableCache() {
 472         return 0L;
 473     }
 474 
 475     /* Used only on OS X.
 476      */
 477     protected long getPlatformNativeFontPtr() {
 478         return 0L;
 479     }
 480 
 481     /* for layout code */
 482     protected long getUnitsPerEm() {
 483         return 2048;
 484     }
 485 
 486     boolean supportsEncoding(String encoding) {
 487         return false;
 488     }
 489 
 490     public boolean canDoStyle(int style) {
 491         return (style == this.style);
 492     }
 493 
 494     /*
 495      * All the important subclasses override this which is principally for
 496      * the TrueType 'gasp' table.
 497      */
 498     public boolean useAAForPtSize(int ptsize) {
 499         return true;
 500     }
 501 
 502     public boolean hasSupplementaryChars() {
 503         return false;
 504     }
 505 
 506     /* The following methods implement public methods on java.awt.Font */
 507     public String getPostscriptName() {
 508         return fullName;
 509     }
 510 
 511     public String getFontName(Locale l) {
 512         return fullName;
 513     }
 514 
 515     public String getFamilyName(Locale l) {
 516         return familyName;
 517     }
 518 
 519     public int getNumGlyphs() {
 520         return getMapper().getNumGlyphs();
 521     }
 522 
 523     public int charToGlyph(int wchar) {
 524         return getMapper().charToGlyph(wchar);
 525     }
 526 
 527     public int getMissingGlyphCode() {
 528         return getMapper().getMissingGlyphCode();
 529     }
 530 
 531     public boolean canDisplay(char c) {
 532         return getMapper().canDisplay(c);
 533     }
 534 
 535     public boolean canDisplay(int cp) {
 536         return getMapper().canDisplay(cp);
 537     }
 538 
 539     public byte getBaselineFor(char c) {
 540         return Font.ROMAN_BASELINE;
 541     }
 542 
 543     public float getItalicAngle(Font font, AffineTransform at,
 544                                 Object aaHint, Object fmHint) {
 545         /* hardwire psz=12 as that's typical and AA vs non-AA for 'gasp' mode
 546          * isn't important for the caret slope of this rarely used API.
 547          */
 548         int aa = FontStrikeDesc.getAAHintIntVal(aaHint, this, 12);
 549         int fm = FontStrikeDesc.getFMHintIntVal(fmHint);
 550         FontStrike strike = getStrike(font, at, aa, fm);
 551         StrikeMetrics metrics = strike.getFontMetrics();
 552         if (metrics.ascentY == 0 || metrics.ascentX == 0) {
 553             return 0f;
 554         } else {
 555             /* ascent is "up" from the baseline so its typically
 556              * a negative value, so we need to compensate
 557              */
 558             return metrics.ascentX/-metrics.ascentY;
 559         }
 560     }
 561 
 562 }