blob: b6cd9a04458a9579856748bc52c9e27b9b254e80 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2004 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.font;
27
28import java.awt.geom.AffineTransform;
29import java.awt.geom.GeneralPath;
30import java.awt.geom.Point2D;
31import java.awt.Rectangle;
32import java.awt.geom.Rectangle2D;
33import 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 FontManager.deRegisterBadFont(nativeFont);
116 pScalerContext = createNullScalerContext();
117 numGlyphs = 0;
118 if (FontManager.logging) {
119 FontManager.logger.severe("Could not create native strike " +
120 new String(nameBytes));
121 }
122 return;
123 }
124 numGlyphs = nativeFont.getMapper().getNumGlyphs();
125 this.disposer = new NativeStrikeDisposer(nativeFont, desc,
126 pScalerContext);
127 }
128
129 /* The asymmetry of the following methods is to help preserve
130 * performance with minimal textual changes to the calling code
131 * when moving initialisation of these arrays out of the constructor.
132 * This may be restructured later when there's more room for changes
133 */
134 private boolean usingIntGlyphImages() {
135 if (intGlyphImages != null) {
136 return true;
137 } else if (FontManager.longAddresses) {
138 return false;
139 } else {
140 /* We could obtain minGlyphIndex and index relative to that
141 * if we need to save space.
142 */
143 int glyphLenArray = getMaxGlyph(pScalerContext);
144
145 /* This shouldn't be necessary - its a precaution */
146 if (glyphLenArray < numGlyphs) {
147 glyphLenArray = numGlyphs;
148 }
149 intGlyphImages = new int[glyphLenArray];
150 this.disposer.intGlyphImages = intGlyphImages;
151 return true;
152 }
153 }
154
155 private long[] getLongGlyphImages() {
156 if (longGlyphImages == null && FontManager.longAddresses) {
157
158 /* We could obtain minGlyphIndex and index relative to that
159 * if we need to save space.
160 */
161 int glyphLenArray = getMaxGlyph(pScalerContext);
162
163 /* This shouldn't be necessary - its a precaution */
164 if (glyphLenArray < numGlyphs) {
165 glyphLenArray = numGlyphs;
166 }
167 longGlyphImages = new long[glyphLenArray];
168 this.disposer.longGlyphImages = longGlyphImages;
169 }
170 return longGlyphImages;
171 }
172
173 NativeStrike(NativeFont nativeFont, FontStrikeDesc desc,
174 boolean nocache) {
175 super(nativeFont, desc);
176 this.nativeFont = nativeFont;
177
178 int ptSize = (int)desc.glyphTx.getScaleY();
179 double scale = desc.devTx.getScaleX(); // uniform scale
180 byte [] nameBytes = nativeFont.getPlatformNameBytes(ptSize);
181 pScalerContext = createScalerContext(nameBytes, ptSize, scale);
182
183 int numGlyphs = nativeFont.getMapper().getNumGlyphs();
184 }
185
186 /* We want the native font to be responsible for reporting the
187 * font metrics, even if it often delegates to another font.
188 * The code here isn't yet implementing exactly that. If the glyph
189 * transform was something native couldn't handle, there's no native
190 * context from which to obtain metrics. Need to revise this to obtain
191 * the metrics and transform them. But currently in such a case it
192 * gets the metrics from a different font - its glyph delegate font.
193 */
194 StrikeMetrics getFontMetrics() {
195 if (strikeMetrics == null) {
196 if (pScalerContext != 0) {
197 strikeMetrics = nativeFont.getFontMetrics(pScalerContext);
198 }
199 if (strikeMetrics != null && fontTx != null) {
200 strikeMetrics.convertToUserSpace(fontTx);
201 }
202 }
203 return strikeMetrics;
204 }
205
206 private native long createScalerContext(byte[] nameBytes,
207 int ptSize, double scale);
208
209 private native int getMaxGlyph(long pScalerContext);
210
211 private native long createNullScalerContext();
212
213 void getGlyphImagePtrs(int[] glyphCodes, long[] images,int len) {
214 for (int i=0; i<len; i++) {
215 images[i] = getGlyphImagePtr(glyphCodes[i]);
216 }
217 }
218
219 long getGlyphImagePtr(int glyphCode) {
220 long glyphPtr;
221
222 if (usingIntGlyphImages()) {
223 if ((glyphPtr = intGlyphImages[glyphCode] & INTMASK) != 0L) {
224 return glyphPtr;
225 } else {
226 glyphPtr = nativeFont.getGlyphImage(pScalerContext,glyphCode);
227 /* Synchronize in case some other thread has updated this
228 * cache entry already - unlikely but possible.
229 */
230 synchronized (this) {
231 if (intGlyphImages[glyphCode] == 0) {
232 intGlyphImages[glyphCode] = (int)glyphPtr;
233 return glyphPtr;
234 } else {
235 StrikeCache.freeIntPointer((int)glyphPtr);
236 return intGlyphImages[glyphCode] & INTMASK;
237 }
238 }
239 }
240 }
241 /* must be using long (8 byte) addresses */
242 else if ((glyphPtr = getLongGlyphImages()[glyphCode]) != 0L) {
243 return glyphPtr;
244 } else {
245 glyphPtr = nativeFont.getGlyphImage(pScalerContext, glyphCode);
246
247 synchronized (this) {
248 if (longGlyphImages[glyphCode] == 0L) {
249 longGlyphImages[glyphCode] = glyphPtr;
250 return glyphPtr;
251 } else {
252 StrikeCache.freeLongPointer(glyphPtr);
253 return longGlyphImages[glyphCode];
254 }
255 }
256 }
257 }
258
259 /* This is used when a FileFont uses the native names to create a
260 * delegate NativeFont/Strike to get images from native. This is used
261 * because Solaris TrueType fonts have external PCF bitmaps rather than
262 * embedded bitmaps. This is really only important for CJK fonts as
263 * for most scripts the external X11 bitmaps aren't much better - if
264 * at all - than the results from hinting the outlines.
265 */
266 long getGlyphImagePtrNoCache(int glyphCode) {
267 return nativeFont.getGlyphImageNoDefault(pScalerContext, glyphCode);
268 }
269
270 void getGlyphImageBounds(int glyphcode, Point2D.Float pt,
271 Rectangle result) {
272 }
273
274 Point2D.Float getGlyphMetrics(int glyphCode) {
275 Point2D.Float pt = new Point2D.Float(getGlyphAdvance(glyphCode), 0f);
276 return pt;
277 }
278
279 float getGlyphAdvance(int glyphCode) {
280 return nativeFont.getGlyphAdvance(pScalerContext, glyphCode);
281 }
282
283 Rectangle2D.Float getGlyphOutlineBounds(int glyphCode) {
284 return nativeFont.getGlyphOutlineBounds(pScalerContext, glyphCode);
285 }
286
287 GeneralPath getGlyphOutline(int glyphCode, float x, float y) {
288 return new GeneralPath();
289 }
290
291 GeneralPath getGlyphVectorOutline(int[] glyphs, float x, float y) {
292 return new GeneralPath();
293 }
294
295}
296
297/* Returned instead of a NativeStrike.
298 * It can intercept any request it wants, but mostly
299 * passes them on to its delegate strike. It is important that
300 * it override all the inherited FontStrike methods to delegate them
301 * appropriately.
302 */
303
304class DelegateStrike extends NativeStrike {
305
306 private FontStrike delegateStrike;
307
308 DelegateStrike(NativeFont nativeFont, FontStrikeDesc desc,
309 FontStrike delegate) {
310 super(nativeFont, desc);
311 this.delegateStrike = delegate;
312 }
313
314 /* We want the native font to be responsible for reporting the
315 * font metrics, even if it often delegates to another font.
316 * The code here isn't yet implementing exactly that. If the glyph
317 * transform was something native couldn't handle, there's no native
318 * context from which to obtain metrics. Need to revise this to obtain
319 * the metrics and transform them. But currently in such a case it
320 * gets the metrics from a different font - its glyph delegate font.
321 */
322 StrikeMetrics getFontMetrics() {
323 if (strikeMetrics == null) {
324 if (pScalerContext != 0) {
325 strikeMetrics = super.getFontMetrics();
326 }
327 if (strikeMetrics == null) {
328 strikeMetrics = delegateStrike.getFontMetrics();
329 }
330 }
331 return strikeMetrics;
332 }
333
334 void getGlyphImagePtrs(int[] glyphCodes, long[] images,int len) {
335 delegateStrike.getGlyphImagePtrs(glyphCodes, images, len);
336 }
337
338 long getGlyphImagePtr(int glyphCode) {
339 return delegateStrike.getGlyphImagePtr(glyphCode);
340 }
341
342 void getGlyphImageBounds(int glyphCode,
343 Point2D.Float pt, Rectangle result) {
344 delegateStrike.getGlyphImageBounds(glyphCode, pt, result);
345 }
346
347 Point2D.Float getGlyphMetrics(int glyphCode) {
348 return delegateStrike.getGlyphMetrics(glyphCode);
349 }
350
351 float getGlyphAdvance(int glyphCode) {
352 return delegateStrike.getGlyphAdvance(glyphCode);
353 }
354
355 Point2D.Float getCharMetrics(char ch) {
356 return delegateStrike.getCharMetrics(ch);
357 }
358
359 float getCodePointAdvance(int cp) {
360 if (cp < 0 || cp >= 0x10000) {
361 cp = 0xffff;
362 }
363 return delegateStrike.getGlyphAdvance(cp);
364 }
365
366 Rectangle2D.Float getGlyphOutlineBounds(int glyphCode) {
367 return delegateStrike.getGlyphOutlineBounds(glyphCode);
368 }
369
370 GeneralPath getGlyphOutline(int glyphCode, float x, float y) {
371 return delegateStrike.getGlyphOutline(glyphCode, x, y);
372 }
373
374 GeneralPath getGlyphVectorOutline(int[] glyphs, float x, float y) {
375 return delegateStrike.getGlyphVectorOutline(glyphs, x, y);
376 }
377
378}