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       */
getNativePointSize()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 
NativeStrike(NativeFont nativeFont, FontStrikeDesc desc)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       */
usingIntGlyphImages()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 
getLongGlyphImages()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 
NativeStrike(NativeFont nativeFont, FontStrikeDesc desc, boolean nocache)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       */
getFontMetrics()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 
createScalerContext(byte[] nameBytes, int ptSize, double scale)207      private native long createScalerContext(byte[] nameBytes,
208                                              int ptSize, double scale);
209 
getMaxGlyph(long pScalerContext)210      private native int getMaxGlyph(long pScalerContext);
211 
createNullScalerContext()212      private native long createNullScalerContext();
213 
getGlyphImagePtrs(int[] glyphCodes, long[] images,int len)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 
getGlyphImagePtr(int glyphCode)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       */
getGlyphImagePtrNoCache(int glyphCode)267      long getGlyphImagePtrNoCache(int glyphCode) {
268          return nativeFont.getGlyphImageNoDefault(pScalerContext, glyphCode);
269      }
270 
getGlyphImageBounds(int glyphcode, Point2D.Float pt, Rectangle result)271      void getGlyphImageBounds(int glyphcode, Point2D.Float pt,
272                               Rectangle result) {
273      }
274 
getGlyphMetrics(int glyphCode)275      Point2D.Float getGlyphMetrics(int glyphCode) {
276          Point2D.Float pt = new Point2D.Float(getGlyphAdvance(glyphCode), 0f);
277          return pt;
278      }
279 
getGlyphAdvance(int glyphCode)280      float getGlyphAdvance(int glyphCode) {
281          return nativeFont.getGlyphAdvance(pScalerContext, glyphCode);
282      }
283 
getGlyphOutlineBounds(int glyphCode)284      Rectangle2D.Float getGlyphOutlineBounds(int glyphCode) {
285          return nativeFont.getGlyphOutlineBounds(pScalerContext, glyphCode);
286      }
287 
getGlyphOutline(int glyphCode, float x, float y)288      GeneralPath getGlyphOutline(int glyphCode, float x, float y) {
289          return new GeneralPath();
290      }
291 
getGlyphVectorOutline(int[] glyphs, float x, float y)292      GeneralPath getGlyphVectorOutline(int[] glyphs, float x, float y) {
293          return new GeneralPath();
294      }
295 
296 }
297