001: /*
002: * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.font;
027:
028: import java.awt.geom.AffineTransform;
029: import java.awt.geom.GeneralPath;
030: import java.awt.geom.Point2D;
031: import java.awt.Rectangle;
032: import java.awt.geom.Rectangle2D;
033: import java.awt.geom.NoninvertibleTransformException;
034:
035: class NativeStrike extends PhysicalStrike {
036:
037: NativeFont nativeFont;
038: int numGlyphs;
039: AffineTransform invertDevTx;
040: AffineTransform fontTx;
041:
042: /* The following method prepares data used in obtaining FontMetrics.
043: * This is the one case in which we allow anything other than a
044: * simple scale to be used with a native font. We do this because in
045: * order to ensure that clients get the overall metrics they expect
046: * for a font whatever coordinate system (combination of font and
047: * device transform) they use.
048: * X11 fonts can only have a scale applied (remind : non-uniform?)
049: * We strip out everything else and if necessary obtain an inverse
050: * tx which we use to return metrics for the font in the transformed
051: * coordinate system of the font. ie we pass X11 a simple scale, and
052: * then apply the non-scale part of the font TX to that result.
053: */
054: private int getNativePointSize() {
055: /* Make a copy of the glyphTX in which we will store the
056: * font transform, inverting the devTx if necessary
057: */
058: double[] mat = new double[4];
059: desc.glyphTx.getMatrix(mat);
060: fontTx = new AffineTransform(mat);
061:
062: /* Now work backwards to get the font transform */
063: if (!desc.devTx.isIdentity()
064: && desc.devTx.getType() != AffineTransform.TYPE_TRANSLATION) {
065: try {
066: invertDevTx = desc.devTx.createInverse();
067: fontTx.concatenate(invertDevTx);
068: } catch (NoninvertibleTransformException e) {
069: e.printStackTrace();
070: }
071: }
072:
073: /* At this point the fontTx may be a simple +ve scale, or it
074: * may be something more complex.
075: */
076: Point2D.Float pt = new Point2D.Float(1f, 1f);
077: fontTx.deltaTransform(pt, pt);
078: double ptSize = Math.abs(pt.y);
079: int ttype = fontTx.getType();
080: if ((ttype & ~AffineTransform.TYPE_UNIFORM_SCALE) != 0
081: || fontTx.getScaleY() <= 0) {
082: /* We need to create an inverse transform that doesn't
083: * include the point size (strictly the uniform scale)
084: */
085: fontTx.scale(1 / ptSize, 1 / ptSize);
086: } else {
087: fontTx = null; // no need
088: }
089: return (int) ptSize;
090: }
091:
092: NativeStrike(NativeFont nativeFont, FontStrikeDesc desc) {
093: super (nativeFont, desc);
094: this .nativeFont = nativeFont;
095:
096: /* If this is a delegate for bitmaps, we expect to have
097: * been invoked only for a simple scale. If that's not
098: * true, just bail
099: */
100: if (nativeFont.isBitmapDelegate) {
101: int ttype = desc.glyphTx.getType();
102: if ((ttype & ~AffineTransform.TYPE_UNIFORM_SCALE) != 0
103: || desc.glyphTx.getScaleX() <= 0) {
104: numGlyphs = 0;
105: return;
106: }
107: }
108:
109: int ptSize = getNativePointSize();
110: byte[] nameBytes = nativeFont.getPlatformNameBytes(ptSize);
111: double scale = Math.abs(desc.devTx.getScaleX());
112: pScalerContext = createScalerContext(nameBytes, ptSize, scale);
113: if (pScalerContext == 0L) {
114: FontManager.deRegisterBadFont(nativeFont);
115: pScalerContext = createNullScalerContext();
116: numGlyphs = 0;
117: if (FontManager.logging) {
118: FontManager.logger
119: .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
198: .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,
228: glyphCode);
229: /* Synchronize in case some other thread has updated this
230: * cache entry already - unlikely but possible.
231: */
232: synchronized (this ) {
233: if (intGlyphImages[glyphCode] == 0) {
234: intGlyphImages[glyphCode] = (int) glyphPtr;
235: return glyphPtr;
236: } else {
237: StrikeCache.freeIntPointer((int) glyphPtr);
238: return intGlyphImages[glyphCode] & INTMASK;
239: }
240: }
241: }
242: }
243: /* must be using long (8 byte) addresses */
244: else if ((glyphPtr = getLongGlyphImages()[glyphCode]) != 0L) {
245: return glyphPtr;
246: } else {
247: glyphPtr = nativeFont.getGlyphImage(pScalerContext,
248: glyphCode);
249:
250: synchronized (this ) {
251: if (longGlyphImages[glyphCode] == 0L) {
252: longGlyphImages[glyphCode] = glyphPtr;
253: return glyphPtr;
254: } else {
255: StrikeCache.freeLongPointer(glyphPtr);
256: return longGlyphImages[glyphCode];
257: }
258: }
259: }
260: }
261:
262: /* This is used when a FileFont uses the native names to create a
263: * delegate NativeFont/Strike to get images from native. This is used
264: * because Solaris TrueType fonts have external PCF bitmaps rather than
265: * embedded bitmaps. This is really only important for CJK fonts as
266: * for most scripts the external X11 bitmaps aren't much better - if
267: * at all - than the results from hinting the outlines.
268: */
269: long getGlyphImagePtrNoCache(int glyphCode) {
270: return nativeFont.getGlyphImageNoDefault(pScalerContext,
271: glyphCode);
272: }
273:
274: void getGlyphImageBounds(int glyphcode, Point2D.Float pt,
275: Rectangle result) {
276: }
277:
278: Point2D.Float getGlyphMetrics(int glyphCode) {
279: Point2D.Float pt = new Point2D.Float(
280: getGlyphAdvance(glyphCode), 0f);
281: return pt;
282: }
283:
284: float getGlyphAdvance(int glyphCode) {
285: return nativeFont.getGlyphAdvance(pScalerContext, glyphCode);
286: }
287:
288: Rectangle2D.Float getGlyphOutlineBounds(int glyphCode) {
289: return nativeFont.getGlyphOutlineBounds(pScalerContext,
290: glyphCode);
291: }
292:
293: GeneralPath getGlyphOutline(int glyphCode, float x, float y) {
294: return new GeneralPath();
295: }
296:
297: GeneralPath getGlyphVectorOutline(int[] glyphs, float x, float y) {
298: return new GeneralPath();
299: }
300:
301: }
302:
303: /* Returned instead of a NativeStrike.
304: * It can intercept any request it wants, but mostly
305: * passes them on to its delegate strike. It is important that
306: * it override all the inherited FontStrike methods to delegate them
307: * appropriately.
308: */
309:
310: class DelegateStrike extends NativeStrike {
311:
312: private FontStrike delegateStrike;
313:
314: DelegateStrike(NativeFont nativeFont, FontStrikeDesc desc,
315: FontStrike delegate) {
316: super (nativeFont, desc);
317: this .delegateStrike = delegate;
318: }
319:
320: /* We want the native font to be responsible for reporting the
321: * font metrics, even if it often delegates to another font.
322: * The code here isn't yet implementing exactly that. If the glyph
323: * transform was something native couldn't handle, there's no native
324: * context from which to obtain metrics. Need to revise this to obtain
325: * the metrics and transform them. But currently in such a case it
326: * gets the metrics from a different font - its glyph delegate font.
327: */
328: StrikeMetrics getFontMetrics() {
329: if (strikeMetrics == null) {
330: if (pScalerContext != 0) {
331: strikeMetrics = super .getFontMetrics();
332: }
333: if (strikeMetrics == null) {
334: strikeMetrics = delegateStrike.getFontMetrics();
335: }
336: }
337: return strikeMetrics;
338: }
339:
340: void getGlyphImagePtrs(int[] glyphCodes, long[] images, int len) {
341: delegateStrike.getGlyphImagePtrs(glyphCodes, images, len);
342: }
343:
344: long getGlyphImagePtr(int glyphCode) {
345: return delegateStrike.getGlyphImagePtr(glyphCode);
346: }
347:
348: void getGlyphImageBounds(int glyphCode, Point2D.Float pt,
349: Rectangle result) {
350: delegateStrike.getGlyphImageBounds(glyphCode, pt, result);
351: }
352:
353: Point2D.Float getGlyphMetrics(int glyphCode) {
354: return delegateStrike.getGlyphMetrics(glyphCode);
355: }
356:
357: float getGlyphAdvance(int glyphCode) {
358: return delegateStrike.getGlyphAdvance(glyphCode);
359: }
360:
361: Point2D.Float getCharMetrics(char ch) {
362: return delegateStrike.getCharMetrics(ch);
363: }
364:
365: float getCodePointAdvance(int cp) {
366: if (cp < 0 || cp >= 0x10000) {
367: cp = 0xffff;
368: }
369: return delegateStrike.getGlyphAdvance(cp);
370: }
371:
372: Rectangle2D.Float getGlyphOutlineBounds(int glyphCode) {
373: return delegateStrike.getGlyphOutlineBounds(glyphCode);
374: }
375:
376: GeneralPath getGlyphOutline(int glyphCode, float x, float y) {
377: return delegateStrike.getGlyphOutline(glyphCode, x, y);
378: }
379:
380: GeneralPath getGlyphVectorOutline(int[] glyphs, float x, float y) {
381: return delegateStrike.getGlyphVectorOutline(glyphs, x, y);
382: }
383:
384: }
|