1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 /* 27 * 28 * (C) Copyright IBM Corp. 2003 - All Rights Reserved 29 */ 30 31 package sun.font; 32 33 import sun.font.GlyphLayout.*; 34 import java.awt.geom.Point2D; 35 import java.lang.ref.SoftReference; 36 import java.util.concurrent.ConcurrentHashMap; 37 import java.util.Locale; 38 39 /* 40 * different ways to do this 41 * 1) each physical font2d keeps a hashtable mapping scripts to layout 42 * engines, we query and fill this cache. 43 * 2) we keep a mapping independent of font using the key Most likely 44 * few fonts will be used, so option 2 seems better 45 * 46 * Once we know which engine to use for a font, we always know, so we 47 * shouldn't have to recheck each time we do layout. So the cache is 48 * ok. 49 * 50 * Should we reuse engines? We could instantiate an engine for each 51 * font/script pair. The engine would hold onto the table(s) from the 52 * font that it needs. If we have multiple threads using the same 53 * engine, we still need to keep the state separate, so the native 54 * engines would still need to be allocated for each call, since they 55 * keep their state in themselves. If they used the passed-in GVData 56 * arrays directly (with some checks for space) then since each GVData 57 * is different per thread, we could reuse the layout engines. This 58 * still requires a separate layout engine per font, because of the 59 * table state in the engine. If we pushed that out too and passed it 60 * in with the native call as well, we'd be ok if the layout engines 61 * keep all their process state on the stack, but I don't know if this 62 * is true. Then we'd basically just be down to an engine index which 63 * we pass into native and then invoke the engine code (now a 64 * procedure call, not an object invocation) based on a switch on the 65 * index. There would be only half a dozen engine objects then, not 66 * potentially half a dozen per font. But we'd have to stack-allocate 67 * some state that included the pointer to the required font tables. 68 * 69 * Seems for now that the way to do things is to come in with a 70 * selector and the font. The selector indicates which engine to use, 71 * the engine is stack allocated and initialized with the required 72 * font tables (the selector indicates which). Then layout is called, 73 * the contents are copied (or not), and the stack is destroyed on 74 * exit. So the association is between the font/script (layout engine 75 * desc) and and one of a few permanent engine objects, which are 76 * handed the key when they need to process something. In the native 77 * case, the engine holds an index, and just passes it together with 78 * the key info down to native. Some default cases are the 'default 79 * layout' case that just runs the c2gmapper, this stays in java and 80 * just uses the mapper from the font/strike. Another default case 81 * might be the unicode arabic shaper, since this doesn't care about 82 * the font (or script or lang?) it wouldn't need to extract this 83 * data. It could be (yikes) ported back to java even to avoid 84 * upcalls to check if the font supports a particular unicode 85 * character. 86 * 87 * I'd expect that the majority of scripts use the default mapper for 88 * a particular font. Loading the hastable with 40 or so keys 30+ of 89 * which all map to the same object is unfortunate. It might be worth 90 * instead having a per-font list of 'scripts with non-default 91 * engines', e.g. the factory has a hashtable mapping fonts to 'script 92 * lists' (the factory has this since the design potentially has other 93 * factories, though I admit there's no client for this yet and no 94 * public api) and then the script list is queried for the script in 95 * question. it can be preloaded at creation time with all the 96 * scripts that don't have default engines-- either a list or a hash 97 * table, so a null return from the table means 'default' and not 'i 98 * don't know yet'. 99 * 100 * On the other hand, in most all cases the number of unique 101 * script/font combinations will be small, so a flat hashtable should 102 * suffice. 103 * */ 104 public final class SunLayoutEngine implements LayoutEngine, LayoutEngineFactory { 105 private static native void initGVIDs(); 106 static { 107 FontManagerNativeLibrary.load(); 108 initGVIDs(); 109 } 110 111 private LayoutEngineKey key; 112 113 private static LayoutEngineFactory instance; 114 115 public static LayoutEngineFactory instance() { 116 if (instance == null) { 117 instance = new SunLayoutEngine(); 118 } 119 return instance; 120 } 121 122 private SunLayoutEngine() { 123 // actually a factory, key is null so layout cannot be called on it 124 } 125 126 public LayoutEngine getEngine(Font2D font, int script, int lang) { 127 return getEngine(new LayoutEngineKey(font, script, lang)); 128 } 129 130 // !!! don't need this unless we have more than one sun layout engine... 131 public LayoutEngine getEngine(LayoutEngineKey key) { 132 ConcurrentHashMap cache = (ConcurrentHashMap)cacheref.get(); 133 if (cache == null) { 134 cache = new ConcurrentHashMap(); 135 cacheref = new SoftReference(cache); 136 } 137 138 LayoutEngine e = (LayoutEngine)cache.get(key); 139 if (e == null) { 140 LayoutEngineKey copy = key.copy(); 141 e = new SunLayoutEngine(copy); 142 cache.put(copy, e); 143 } 144 return e; 145 } 146 private SoftReference cacheref = new SoftReference(null); 147 148 private SunLayoutEngine(LayoutEngineKey key) { 149 this.key = key; 150 } 151 152 public void layout(FontStrikeDesc desc, float[] mat, int gmask, 153 int baseIndex, TextRecord tr, int typo_flags, 154 Point2D.Float pt, GVData data) { 155 Font2D font = key.font(); 156 FontStrike strike = font.getStrike(desc); 157 long layoutTables = 0; 158 if (font instanceof TrueTypeFont) { 159 layoutTables = ((TrueTypeFont) font).getLayoutTableCache(); 160 } 161 nativeLayout(font, strike, mat, gmask, baseIndex, 162 tr.text, tr.start, tr.limit, tr.min, tr.max, 163 key.script(), key.lang(), typo_flags, pt, data, 164 font.getUnitsPerEm(), layoutTables); 165 } 166 167 private static native void 168 nativeLayout(Font2D font, FontStrike strike, float[] mat, int gmask, 169 int baseIndex, char[] chars, int offset, int limit, 170 int min, int max, int script, int lang, int typo_flags, 171 Point2D.Float pt, GVData data, long upem, long layoutTables); 172 }