1 /*
   2  * Copyright (c) 2003, 2012, 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.geom.AffineTransform;
  29 import java.awt.geom.GeneralPath;
  30 import java.awt.geom.Point2D;
  31 import java.awt.Rectangle;
  32 import java.awt.geom.Rectangle2D;
  33 import java.awt.geom.NoninvertibleTransformException;
  34 
  35 class NativeStrike extends PhysicalStrike {
  36 
  37      NativeFont nativeFont;
  38      int numGlyphs;
  39      AffineTransform invertDevTx;
  40      AffineTransform fontTx;
  41 
  42      /* The following method prepares data used in obtaining FontMetrics.
  43       * This is the one case in which we allow anything other than a
  44       * simple scale to be used with a native font. We do this because in
  45       * order to ensure that clients get the overall metrics they expect
  46       * for a font whatever coordinate system (combination of font and
  47       * device transform) they use.
  48       * X11 fonts can only have a scale applied (remind : non-uniform?)
  49       * We strip out everything else and if necessary obtain an inverse
  50       * tx which we use to return metrics for the font in the transformed
  51       * coordinate system of the font. ie we pass X11 a simple scale, and
  52       * then apply the non-scale part of the font TX to that result.
  53       */
  54      private int getNativePointSize() {
  55          /* Make a copy of the glyphTX in which we will store the
  56           * font transform, inverting the devTx if necessary
  57           */
  58          double[] mat = new double[4];
  59          desc.glyphTx.getMatrix(mat);
  60          fontTx = new AffineTransform(mat);
  61 
  62          /* Now work backwards to get the font transform */
  63          if (!desc.devTx.isIdentity() &&
  64              desc.devTx.getType() != AffineTransform.TYPE_TRANSLATION) {
  65              try {
  66                  invertDevTx = desc.devTx.createInverse();
  67                  fontTx.concatenate(invertDevTx);
  68              } catch (NoninvertibleTransformException e) {
  69                  e.printStackTrace();
  70              }
  71          }
  72 
  73          /* At this point the fontTx may be a simple +ve scale, or it
  74           * may be something more complex.
  75           */
  76          Point2D.Float pt = new Point2D.Float(1f,1f);
  77          fontTx.deltaTransform(pt, pt);
  78          double ptSize = Math.abs(pt.y);
  79          int ttype = fontTx.getType();
  80          if ((ttype & ~AffineTransform.TYPE_UNIFORM_SCALE) != 0 ||
  81              fontTx.getScaleY() <= 0) {
  82              /* We need to create an inverse transform that doesn't
  83               * include the point size (strictly the uniform scale)
  84               */
  85              fontTx.scale(1/ptSize, 1/ptSize);
  86          } else {
  87              fontTx = null; // no need
  88          }
  89          return (int)ptSize;
  90      }
  91 
  92      NativeStrike(NativeFont nativeFont, FontStrikeDesc desc) {
  93          super(nativeFont, desc);
  94          this.nativeFont = nativeFont;
  95 
  96 
  97          /* If this is a delegate for bitmaps, we expect to have
  98           * been invoked only for a simple scale. If that's not
  99           * true, just bail
 100           */
 101          if (nativeFont.isBitmapDelegate) {
 102              int ttype = desc.glyphTx.getType();
 103              if ((ttype & ~AffineTransform.TYPE_UNIFORM_SCALE) != 0 ||
 104                  desc.glyphTx.getScaleX() <= 0) {
 105              numGlyphs = 0;
 106              return;
 107              }
 108          }
 109 
 110          int ptSize = getNativePointSize();
 111          byte [] nameBytes = nativeFont.getPlatformNameBytes(ptSize);
 112          double scale = Math.abs(desc.devTx.getScaleX());
 113          pScalerContext = createScalerContext(nameBytes, ptSize, scale);
 114          if (pScalerContext == 0L) {
 115              SunFontManager.getInstance().deRegisterBadFont(nativeFont);
 116              pScalerContext = createNullScalerContext();
 117              numGlyphs = 0;
 118              if (FontUtilities.isLogging()) {
 119                  FontUtilities.getLogger()
 120                                    .severe("Could not create native strike " +
 121                                            new String(nameBytes));
 122              }
 123              return;
 124          }
 125          numGlyphs = nativeFont.getMapper().getNumGlyphs();
 126          this.disposer = new NativeStrikeDisposer(nativeFont, desc,
 127                                                   pScalerContext);
 128      }
 129 
 130      /* The asymmetry of the following methods is to help preserve
 131       * performance with minimal textual changes to the calling code
 132       * when moving initialisation of these arrays out of the constructor.
 133       * This may be restructured later when there's more room for changes
 134       */
 135      private boolean usingIntGlyphImages() {
 136          if (intGlyphImages != null) {
 137             return true;
 138         } else if (longAddresses) {
 139             return false;
 140         } else {
 141             /* We could obtain minGlyphIndex and index relative to that
 142              * if we need to save space.
 143              */
 144             int glyphLenArray = getMaxGlyph(pScalerContext);
 145 
 146             /* This shouldn't be necessary - its a precaution */
 147             if (glyphLenArray < numGlyphs) {
 148                 glyphLenArray = numGlyphs;
 149             }
 150             intGlyphImages = new int[glyphLenArray];
 151             this.disposer.intGlyphImages = intGlyphImages;
 152             return true;
 153         }
 154      }
 155 
 156      private long[] getLongGlyphImages() {
 157         if (longGlyphImages == null && longAddresses) {
 158 
 159             /* We could obtain minGlyphIndex and index relative to that
 160              * if we need to save space.
 161              */
 162             int glyphLenArray = getMaxGlyph(pScalerContext);
 163 
 164             /* This shouldn't be necessary - its a precaution */
 165             if (glyphLenArray < numGlyphs) {
 166                 glyphLenArray = numGlyphs;
 167             }
 168             longGlyphImages = new long[glyphLenArray];
 169             this.disposer.longGlyphImages = longGlyphImages;
 170         }
 171         return longGlyphImages;
 172      }
 173 
 174      NativeStrike(NativeFont nativeFont, FontStrikeDesc desc,
 175                   boolean nocache) {
 176          super(nativeFont, desc);
 177          this.nativeFont = nativeFont;
 178 
 179          int ptSize = (int)desc.glyphTx.getScaleY();
 180          double scale = desc.devTx.getScaleX(); // uniform scale
 181          byte [] nameBytes = nativeFont.getPlatformNameBytes(ptSize);
 182          pScalerContext = createScalerContext(nameBytes, ptSize, scale);
 183 
 184          int numGlyphs = nativeFont.getMapper().getNumGlyphs();
 185      }
 186 
 187      /* We want the native font to be responsible for reporting the
 188       * font metrics, even if it often delegates to another font.
 189       * The code here isn't yet implementing exactly that. If the glyph
 190       * transform was something native couldn't handle, there's no native
 191       * context from which to obtain metrics. Need to revise this to obtain
 192       * the metrics and transform them. But currently in such a case it
 193       * gets the metrics from a different font - its glyph delegate font.
 194       */
 195      StrikeMetrics getFontMetrics() {
 196          if (strikeMetrics == null) {
 197              if (pScalerContext != 0) {
 198                  strikeMetrics = nativeFont.getFontMetrics(pScalerContext);
 199              }
 200              if (strikeMetrics != null && fontTx != null) {
 201                  strikeMetrics.convertToUserSpace(fontTx);
 202              }
 203          }
 204          return strikeMetrics;
 205      }
 206 
 207      private native long createScalerContext(byte[] nameBytes,
 208                                              int ptSize, double scale);
 209 
 210      private native int getMaxGlyph(long pScalerContext);
 211 
 212      private native long createNullScalerContext();
 213 
 214      void getGlyphImagePtrs(int[] glyphCodes, long[] images,int  len) {
 215          for (int i=0; i<len; i++) {
 216              images[i] = getGlyphImagePtr(glyphCodes[i]);
 217          }
 218      }
 219 
 220      long getGlyphImagePtr(int glyphCode) {
 221          long glyphPtr;
 222 
 223          if (usingIntGlyphImages()) {
 224              if ((glyphPtr = intGlyphImages[glyphCode] & INTMASK) != 0L) {
 225                  return glyphPtr;
 226              } else {
 227                  glyphPtr = nativeFont.getGlyphImage(pScalerContext,glyphCode);
 228                  /* Synchronize in case some other thread has updated this
 229                   * cache entry already - unlikely but possible.
 230                   */
 231                  synchronized (this) {
 232                      if (intGlyphImages[glyphCode] == 0) {
 233                          intGlyphImages[glyphCode] = (int)glyphPtr;
 234                          return glyphPtr;
 235                      } else {
 236                          StrikeCache.freeIntPointer((int)glyphPtr);
 237                          return intGlyphImages[glyphCode] & INTMASK;
 238                      }
 239                  }
 240              }
 241          }
 242          /* must be using long (8 byte) addresses */
 243          else if ((glyphPtr = getLongGlyphImages()[glyphCode]) != 0L) {
 244              return glyphPtr;
 245          } else {
 246              glyphPtr = nativeFont.getGlyphImage(pScalerContext, glyphCode);
 247 
 248              synchronized (this) {
 249                  if (longGlyphImages[glyphCode] == 0L) {
 250                      longGlyphImages[glyphCode] = glyphPtr;
 251                      return glyphPtr;
 252                  } else {
 253                      StrikeCache.freeLongPointer(glyphPtr);
 254                      return longGlyphImages[glyphCode];
 255                  }
 256              }
 257          }
 258      }
 259 
 260      /* This is used when a FileFont uses the native names to create a
 261       * delegate NativeFont/Strike to get images from native. This is used
 262       * because Solaris TrueType fonts have external PCF bitmaps rather than
 263       * embedded bitmaps. This is really only important for CJK fonts as
 264       * for most scripts the external X11 bitmaps aren't much better - if
 265       * at all - than the results from hinting the outlines.
 266       */
 267      long getGlyphImagePtrNoCache(int glyphCode) {
 268          return nativeFont.getGlyphImageNoDefault(pScalerContext, glyphCode);
 269      }
 270 
 271      void getGlyphImageBounds(int glyphcode, Point2D.Float pt,
 272                               Rectangle result) {
 273      }
 274 
 275      Point2D.Float getGlyphMetrics(int glyphCode) {
 276          Point2D.Float pt = new Point2D.Float(getGlyphAdvance(glyphCode), 0f);
 277          return pt;
 278      }
 279 
 280      float getGlyphAdvance(int glyphCode) {
 281          return nativeFont.getGlyphAdvance(pScalerContext, glyphCode);
 282      }
 283 
 284      Rectangle2D.Float getGlyphOutlineBounds(int glyphCode) {
 285          return nativeFont.getGlyphOutlineBounds(pScalerContext, glyphCode);
 286      }
 287 
 288      GeneralPath getGlyphOutline(int glyphCode, float x, float y) {
 289          return new GeneralPath();
 290      }
 291 
 292      GeneralPath getGlyphVectorOutline(int[] glyphs, float x, float y) {
 293          return new GeneralPath();
 294      }
 295 
 296 }