1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.graphics; 18 19 import com.android.ide.common.rendering.api.LayoutLog; 20 import com.android.layoutlib.bridge.Bridge; 21 import com.android.layoutlib.bridge.impl.DelegateManager; 22 import com.android.layoutlib.bridge.impl.FontLoader; 23 import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 24 25 import android.content.res.AssetManager; 26 27 import java.awt.Font; 28 import java.io.File; 29 import java.util.ArrayList; 30 import java.util.List; 31 32 /** 33 * Delegate implementing the native methods of android.graphics.Typeface 34 * 35 * Through the layoutlib_create tool, the original native methods of Typeface have been replaced 36 * by calls to methods of the same name in this delegate class. 37 * 38 * This class behaves like the original native implementation, but in Java, keeping previously 39 * native data into its own objects and mapping them to int that are sent back and forth between 40 * it and the original Typeface class. 41 * 42 * @see DelegateManager 43 * 44 */ 45 public final class Typeface_Delegate { 46 47 private static final String SYSTEM_FONTS = "/system/fonts/"; 48 49 // ---- delegate manager ---- 50 private static final DelegateManager<Typeface_Delegate> sManager = 51 new DelegateManager<Typeface_Delegate>(Typeface_Delegate.class); 52 53 // ---- delegate helper data ---- 54 private static final String DEFAULT_FAMILY = "sans-serif"; 55 56 private static FontLoader sFontLoader; 57 private static final List<Typeface_Delegate> sPostInitDelegate = 58 new ArrayList<Typeface_Delegate>(); 59 60 // ---- delegate data ---- 61 62 private final String mFamily; 63 private int mStyle; 64 private List<Font> mFonts; 65 66 67 // ---- Public Helper methods ---- 68 69 public static synchronized void init(FontLoader fontLoader) { 70 sFontLoader = fontLoader; 71 72 for (Typeface_Delegate delegate : sPostInitDelegate) { 73 delegate.init(); 74 } 75 sPostInitDelegate.clear(); 76 } 77 78 public static Typeface_Delegate getDelegate(int nativeTypeface) { 79 return sManager.getDelegate(nativeTypeface); 80 } 81 82 public static List<Font> getFonts(Typeface typeface) { 83 return getFonts(typeface.native_instance); 84 } 85 86 public static List<Font> getFonts(int native_int) { 87 Typeface_Delegate delegate = sManager.getDelegate(native_int); 88 if (delegate == null) { 89 return null; 90 } 91 92 return delegate.getFonts(); 93 } 94 95 public List<Font> getFonts() { 96 return mFonts; 97 } 98 99 // ---- native methods ---- 100 101 @LayoutlibDelegate 102 /*package*/ static synchronized int nativeCreate(String familyName, int style) { 103 if (familyName == null) { 104 familyName = DEFAULT_FAMILY; 105 } 106 107 Typeface_Delegate newDelegate = new Typeface_Delegate(familyName, style); 108 if (sFontLoader != null) { 109 newDelegate.init(); 110 } else { 111 // font loader has not been initialized yet, add the delegate to a list of delegates 112 // to init when the font loader is initialized. 113 // There won't be any rendering before this happens anyway. 114 sPostInitDelegate.add(newDelegate); 115 } 116 117 return sManager.addNewDelegate(newDelegate); 118 } 119 120 @LayoutlibDelegate 121 /*package*/ static synchronized int nativeCreateFromTypeface(int native_instance, int style) { 122 Typeface_Delegate delegate = sManager.getDelegate(native_instance); 123 if (delegate == null) { 124 return 0; 125 } 126 127 Typeface_Delegate newDelegate = new Typeface_Delegate(delegate.mFamily, style); 128 if (sFontLoader != null) { 129 newDelegate.init(); 130 } else { 131 // font loader has not been initialized yet, add the delegate to a list of delegates 132 // to init when the font loader is initialized. 133 // There won't be any rendering before this happens anyway. 134 sPostInitDelegate.add(newDelegate); 135 } 136 137 return sManager.addNewDelegate(newDelegate); 138 } 139 140 @LayoutlibDelegate 141 /*package*/ static synchronized int nativeCreateFromAsset(AssetManager mgr, String path) { 142 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 143 "Typeface.createFromAsset() is not supported.", null /*throwable*/, null /*data*/); 144 return 0; 145 } 146 147 @LayoutlibDelegate 148 /*package*/ static synchronized int nativeCreateFromFile(String path) { 149 if (path.startsWith(SYSTEM_FONTS) ) { 150 String relativePath = path.substring(SYSTEM_FONTS.length()); 151 File f = new File(sFontLoader.getOsFontsLocation(), relativePath); 152 153 try { 154 Font font = Font.createFont(Font.TRUETYPE_FONT, f); 155 if (font != null) { 156 Typeface_Delegate newDelegate = new Typeface_Delegate(font); 157 return sManager.addNewDelegate(newDelegate); 158 } 159 } catch (Exception e) { 160 Bridge.getLog().fidelityWarning(LayoutLog.TAG_BROKEN, 161 String.format("Unable to load font %1$s", relativePath), 162 null /*throwable*/, null /*data*/); 163 } 164 } else { 165 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 166 "Typeface.createFromFile() can only work with platform fonts located in " + 167 SYSTEM_FONTS, 168 null /*throwable*/, null /*data*/); 169 } 170 171 172 // return a copy of the base font 173 return nativeCreate(null, 0); 174 } 175 176 @LayoutlibDelegate 177 /*package*/ static void nativeUnref(int native_instance) { 178 sManager.removeJavaReferenceFor(native_instance); 179 } 180 181 @LayoutlibDelegate 182 /*package*/ static int nativeGetStyle(int native_instance) { 183 Typeface_Delegate delegate = sManager.getDelegate(native_instance); 184 if (delegate == null) { 185 return 0; 186 } 187 188 return delegate.mStyle; 189 } 190 191 // ---- Private delegate/helper methods ---- 192 193 private Typeface_Delegate(String family, int style) { 194 mFamily = family; 195 mStyle = style; 196 } 197 198 private Typeface_Delegate(Font font) { 199 mFamily = font.getFamily(); 200 mStyle = Typeface.NORMAL; 201 202 mFonts = sFontLoader.getFallbackFonts(mStyle); 203 204 // insert the font glyph first. 205 mFonts.add(0, font); 206 } 207 208 private void init() { 209 mFonts = sFontLoader.getFont(mFamily, mStyle); 210 } 211 } 212