1 /*
2 * Copyright (c) 2003, 2010, 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
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>
95 strikeCache = new ConcurrentHashMap<FontStrikeDesc, Reference>();
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 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
178 protected int getValidatedGlyphCode(int glyphCode) {
179 if (glyphCode < 0 || glyphCode >= getMapper().getNumGlyphs()) {
180 glyphCode = getMapper().getMissingGlyphCode();
181 }
182 return glyphCode;
183 }
184
185 /*
186 * Creates an appropriate strike for the Font2D subclass
187 */
188 abstract FontStrike createStrike(FontStrikeDesc desc);
189
190 /* this may be useful for APIs like canDisplay where the answer
191 * is dependent on the font and its scaler, but not the strike.
192 * If no strike has ever been returned, then create a one that matches
193 * this font with the default FRC. It will become the lastStrike and
194 * there's a good chance that the next call will be to get exactly that
195 * strike.
196 */
197 public FontStrike getStrike(Font font) {
198 FontStrike strike = (FontStrike)lastFontStrike.get();
199 if (strike != null) {
200 return strike;
201 } else {
202 return getStrike(font, DEFAULT_FRC);
203 }
204 }
205
206 /* SunGraphics2D has font, tx, aa and fm. From this info
207 * can get a Strike object from the cache, creating it if necessary.
208 * This code is designed for multi-threaded access.
209 * For that reason it creates a local FontStrikeDesc rather than filling
210 * in a shared one. Up to two AffineTransforms and one FontStrikeDesc will
211 * be created by every lookup. This appears to perform more than
212 * adequately. But it may make sense to expose FontStrikeDesc
213 * as a parameter so a caller can use its own.
214 * In such a case if a FontStrikeDesc is stored as a key then
215 * we would need to use a private copy.
216 *
217 * Note that this code doesn't prevent two threads from creating
218 * two different FontStrike instances and having one of the threads
290 }
291
292 FontStrike getStrike(FontStrikeDesc desc) {
293 return getStrike(desc, true);
294 }
295
296 private FontStrike getStrike(FontStrikeDesc desc, boolean copy) {
297 /* Before looking in the map, see if the descriptor matches the
298 * last strike returned from this Font2D. This should often be a win
299 * since its common for the same font, in the same size to be
300 * used frequently, for example in many parts of a UI.
301 *
302 * If its not the same then we use the descriptor to locate a
303 * Reference to the strike. If it exists and points to a strike,
304 * then we update the last strike to refer to that and return it.
305 *
306 * If the key isn't in the map, or its reference object has been
307 * collected, then we create a new strike, put it in the map and
308 * set it to be the last strike.
309 */
310 FontStrike strike = (FontStrike)lastFontStrike.get();
311 if (strike != null && desc.equals(strike.desc)) {
312 //strike.lastlookupTime = System.currentTimeMillis();
313 return strike;
314 } else {
315 Reference strikeRef = strikeCache.get(desc);
316 if (strikeRef != null) {
317 strike = (FontStrike)strikeRef.get();
318 if (strike != null) {
319 //strike.lastlookupTime = System.currentTimeMillis();
320 lastFontStrike = new SoftReference(strike);
321 StrikeCache.refStrike(strike);
322 return strike;
323 }
324 }
325 /* When we create a new FontStrike instance, we *must*
326 * ask the StrikeCache for a reference. We must then ensure
327 * this reference remains reachable, by storing it in the
328 * Font2D's strikeCache map.
329 * So long as the Reference is there (reachable) then if the
330 * reference is cleared, it will be enqueued for disposal.
331 * If for some reason we explicitly remove this reference, it
332 * must only be done when holding a strong reference to the
333 * referent (the FontStrike), or if the reference is cleared,
334 * then we must explicitly "dispose" of the native resources.
335 * The only place this currently happens is in this same method,
336 * where we find a cleared reference and need to overwrite it
337 * here with a new reference.
338 * Clearing the whilst holding a strong reference, should only
339 * be done if the
340 */
343 }
344 strike = createStrike(desc);
345 //StrikeCache.addStrike();
346 /* If we are creating many strikes on this font which
347 * involve non-quadrant rotations, or more general
348 * transforms which include shears, then force the use
349 * of weak references rather than soft references.
350 * This means that it won't live much beyond the next GC,
351 * which is what we want for what is likely a transient strike.
352 */
353 int txType = desc.glyphTx.getType();
354 if (txType == AffineTransform.TYPE_GENERAL_TRANSFORM ||
355 (txType & AffineTransform.TYPE_GENERAL_ROTATION) != 0 &&
356 strikeCache.size() > 10) {
357 strikeRef = StrikeCache.getStrikeRef(strike, true);
358 } else {
359 strikeRef = StrikeCache.getStrikeRef(strike);
360 }
361 strikeCache.put(desc, strikeRef);
362 //strike.lastlookupTime = System.currentTimeMillis();
363 lastFontStrike = new SoftReference(strike);
364 StrikeCache.refStrike(strike);
365 return strike;
366 }
367 }
368
369 void removeFromCache(FontStrikeDesc desc) {
370 Reference ref = strikeCache.get(desc);
371 if (ref != null) {
372 Object o = ref.get();
373 if (o == null) {
374 strikeCache.remove(desc);
375 }
376 }
377 }
378
379 /**
380 * The length of the metrics array must be >= 8. This method will
381 * store the following elements in that array before returning:
382 * metrics[0]: ascent
383 * metrics[1]: descent
384 * metrics[2]: leading
385 * metrics[3]: max advance
386 * metrics[4]: strikethrough offset
387 * metrics[5]: strikethrough thickness
388 * metrics[6]: underline offset
389 * metrics[7]: underline thickness
390 */
|
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
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
178 protected int getValidatedGlyphCode(int glyphCode) {
179 if (glyphCode < 0 || glyphCode >= getMapper().getNumGlyphs()) {
180 glyphCode = getMapper().getMissingGlyphCode();
181 }
182 return glyphCode;
183 }
184
185 /*
186 * Creates an appropriate strike for the Font2D subclass
187 */
188 abstract FontStrike createStrike(FontStrikeDesc desc);
189
190 /* this may be useful for APIs like canDisplay where the answer
191 * is dependent on the font and its scaler, but not the strike.
192 * If no strike has ever been returned, then create a one that matches
193 * this font with the default FRC. It will become the lastStrike and
194 * there's a good chance that the next call will be to get exactly that
195 * strike.
196 */
197 public FontStrike getStrike(Font font) {
198 FontStrike strike = lastFontStrike.get();
199 if (strike != null) {
200 return strike;
201 } else {
202 return getStrike(font, DEFAULT_FRC);
203 }
204 }
205
206 /* SunGraphics2D has font, tx, aa and fm. From this info
207 * can get a Strike object from the cache, creating it if necessary.
208 * This code is designed for multi-threaded access.
209 * For that reason it creates a local FontStrikeDesc rather than filling
210 * in a shared one. Up to two AffineTransforms and one FontStrikeDesc will
211 * be created by every lookup. This appears to perform more than
212 * adequately. But it may make sense to expose FontStrikeDesc
213 * as a parameter so a caller can use its own.
214 * In such a case if a FontStrikeDesc is stored as a key then
215 * we would need to use a private copy.
216 *
217 * Note that this code doesn't prevent two threads from creating
218 * two different FontStrike instances and having one of the threads
290 }
291
292 FontStrike getStrike(FontStrikeDesc desc) {
293 return getStrike(desc, true);
294 }
295
296 private FontStrike getStrike(FontStrikeDesc desc, boolean copy) {
297 /* Before looking in the map, see if the descriptor matches the
298 * last strike returned from this Font2D. This should often be a win
299 * since its common for the same font, in the same size to be
300 * used frequently, for example in many parts of a UI.
301 *
302 * If its not the same then we use the descriptor to locate a
303 * Reference to the strike. If it exists and points to a strike,
304 * then we update the last strike to refer to that and return it.
305 *
306 * If the key isn't in the map, or its reference object has been
307 * collected, then we create a new strike, put it in the map and
308 * set it to be the last strike.
309 */
310 FontStrike strike = lastFontStrike.get();
311 if (strike != null && desc.equals(strike.desc)) {
312 //strike.lastlookupTime = System.currentTimeMillis();
313 return strike;
314 } else {
315 Reference<FontStrike> strikeRef = strikeCache.get(desc);
316 if (strikeRef != null) {
317 strike = strikeRef.get();
318 if (strike != null) {
319 //strike.lastlookupTime = System.currentTimeMillis();
320 lastFontStrike = new SoftReference<>(strike);
321 StrikeCache.refStrike(strike);
322 return strike;
323 }
324 }
325 /* When we create a new FontStrike instance, we *must*
326 * ask the StrikeCache for a reference. We must then ensure
327 * this reference remains reachable, by storing it in the
328 * Font2D's strikeCache map.
329 * So long as the Reference is there (reachable) then if the
330 * reference is cleared, it will be enqueued for disposal.
331 * If for some reason we explicitly remove this reference, it
332 * must only be done when holding a strong reference to the
333 * referent (the FontStrike), or if the reference is cleared,
334 * then we must explicitly "dispose" of the native resources.
335 * The only place this currently happens is in this same method,
336 * where we find a cleared reference and need to overwrite it
337 * here with a new reference.
338 * Clearing the whilst holding a strong reference, should only
339 * be done if the
340 */
343 }
344 strike = createStrike(desc);
345 //StrikeCache.addStrike();
346 /* If we are creating many strikes on this font which
347 * involve non-quadrant rotations, or more general
348 * transforms which include shears, then force the use
349 * of weak references rather than soft references.
350 * This means that it won't live much beyond the next GC,
351 * which is what we want for what is likely a transient strike.
352 */
353 int txType = desc.glyphTx.getType();
354 if (txType == AffineTransform.TYPE_GENERAL_TRANSFORM ||
355 (txType & AffineTransform.TYPE_GENERAL_ROTATION) != 0 &&
356 strikeCache.size() > 10) {
357 strikeRef = StrikeCache.getStrikeRef(strike, true);
358 } else {
359 strikeRef = StrikeCache.getStrikeRef(strike);
360 }
361 strikeCache.put(desc, strikeRef);
362 //strike.lastlookupTime = System.currentTimeMillis();
363 lastFontStrike = new SoftReference<>(strike);
364 StrikeCache.refStrike(strike);
365 return strike;
366 }
367 }
368
369 void removeFromCache(FontStrikeDesc desc) {
370 Reference<FontStrike> ref = strikeCache.get(desc);
371 if (ref != null) {
372 Object o = ref.get();
373 if (o == null) {
374 strikeCache.remove(desc);
375 }
376 }
377 }
378
379 /**
380 * The length of the metrics array must be >= 8. This method will
381 * store the following elements in that array before returning:
382 * metrics[0]: ascent
383 * metrics[1]: descent
384 * metrics[2]: leading
385 * metrics[3]: max advance
386 * metrics[4]: strikethrough offset
387 * metrics[5]: strikethrough thickness
388 * metrics[6]: underline offset
389 * metrics[7]: underline thickness
390 */
|