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 17package android.graphics; 18 19import com.android.annotations.NonNull; 20import com.android.layoutlib.bridge.impl.DelegateManager; 21import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 22 23import android.graphics.FontFamily_Delegate.FontVariant; 24 25import java.awt.Font; 26import java.io.File; 27import java.util.ArrayList; 28import java.util.List; 29 30/** 31 * Delegate implementing the native methods of android.graphics.Typeface 32 * 33 * Through the layoutlib_create tool, the original native methods of Typeface have been replaced 34 * by calls to methods of the same name in this delegate class. 35 * 36 * This class behaves like the original native implementation, but in Java, keeping previously 37 * native data into its own objects and mapping them to int that are sent back and forth between 38 * it and the original Typeface class. 39 * 40 * @see DelegateManager 41 * 42 */ 43public final class Typeface_Delegate { 44 45 public static final String SYSTEM_FONTS = "/system/fonts/"; 46 47 // ---- delegate manager ---- 48 private static final DelegateManager<Typeface_Delegate> sManager = 49 new DelegateManager<Typeface_Delegate>(Typeface_Delegate.class); 50 51 // ---- delegate helper data ---- 52 private static String sFontLocation; 53 54 // ---- delegate data ---- 55 56 @NonNull 57 private final FontFamily_Delegate[] mFontFamilies; // the reference to FontFamily_Delegate. 58 /** @see Font#getStyle() */ 59 private final int mStyle; 60 private final int mWeight; 61 62 private static long sDefaultTypeface; 63 64 // ---- Public Helper methods ---- 65 public static synchronized void setFontLocation(String fontLocation) { 66 sFontLocation = fontLocation; 67 FontFamily_Delegate.setFontLocation(fontLocation); 68 } 69 70 public static Typeface_Delegate getDelegate(long nativeTypeface) { 71 return sManager.getDelegate(nativeTypeface); 72 } 73 74 /** 75 * Return a list of fonts that match the style and variant. The list is ordered according to 76 * preference of fonts. 77 * 78 * The list may contain null when the font failed to load. If null is reached when trying to 79 * render with this list of fonts, then a warning should be logged letting the user know that 80 * some font failed to load. 81 * 82 * @param variant The variant preferred. Can only be {@link FontVariant#COMPACT} or 83 * {@link FontVariant#ELEGANT} 84 */ 85 @NonNull 86 public List<Font> getFonts(FontVariant variant) { 87 assert variant != FontVariant.NONE; 88 89 // Calculate the required weight based on style and weight of this typeface. 90 int weight = mWeight + ((mStyle & Font.BOLD) == 0 ? 0 : FontFamily_Delegate.BOLD_FONT_WEIGHT_DELTA); 91 if (weight > 900) { 92 weight = 900; 93 } 94 final boolean isItalic = (mStyle & Font.ITALIC) != 0; 95 List<Font> fonts = new ArrayList<Font>(mFontFamilies.length); 96 for (int i = 0; i < mFontFamilies.length; i++) { 97 FontFamily_Delegate ffd = mFontFamilies[i]; 98 if (ffd != null && ffd.isValid()) { 99 Font font = ffd.getFont(weight, isItalic); 100 if (font != null) { 101 FontVariant ffdVariant = ffd.getVariant(); 102 if (ffdVariant == FontVariant.NONE) { 103 fonts.add(font); 104 continue; 105 } 106 // We cannot open each font and get locales supported, etc to match the fonts. 107 // As a workaround, we hardcode certain assumptions like Elegant and Compact 108 // always appear in pairs. 109 assert i < mFontFamilies.length - 1; 110 FontFamily_Delegate ffd2 = mFontFamilies[++i]; 111 assert ffd2 != null; 112 FontVariant ffd2Variant = ffd2.getVariant(); 113 Font font2 = ffd2.getFont(weight, isItalic); 114 assert ffd2Variant != FontVariant.NONE && ffd2Variant != ffdVariant 115 && font2 != null; 116 // Add the font with the matching variant to the list. 117 if (variant == ffd.getVariant()) { 118 fonts.add(font); 119 } else { 120 fonts.add(font2); 121 } 122 } else { 123 // The FontFamily is valid but doesn't contain any matching font. This means 124 // that the font failed to load. We add null to the list of fonts. Don't throw 125 // the warning just yet. If this is a non-english font, we don't want to warn 126 // users who are trying to render only english text. 127 fonts.add(null); 128 } 129 } 130 } 131 return fonts; 132 } 133 134 // ---- native methods ---- 135 136 @LayoutlibDelegate 137 /*package*/ static synchronized long nativeCreateFromTypeface(long native_instance, int style) { 138 Typeface_Delegate delegate = sManager.getDelegate(native_instance); 139 if (delegate == null) { 140 delegate = sManager.getDelegate(sDefaultTypeface); 141 } 142 if (delegate == null) { 143 return 0; 144 } 145 146 return sManager.addNewDelegate(new Typeface_Delegate(delegate.mFontFamilies, style, 147 delegate.mWeight)); 148 } 149 150 @LayoutlibDelegate 151 /*package*/ static long nativeCreateWeightAlias(long native_instance, int weight) { 152 Typeface_Delegate delegate = sManager.getDelegate(native_instance); 153 if (delegate == null) { 154 delegate = sManager.getDelegate(sDefaultTypeface); 155 } 156 if (delegate == null) { 157 return 0; 158 } 159 Typeface_Delegate weightAlias = 160 new Typeface_Delegate(delegate.mFontFamilies, delegate.mStyle, weight); 161 return sManager.addNewDelegate(weightAlias); 162 } 163 164 @LayoutlibDelegate 165 /*package*/ static synchronized long nativeCreateFromArray(long[] familyArray) { 166 FontFamily_Delegate[] fontFamilies = new FontFamily_Delegate[familyArray.length]; 167 for (int i = 0; i < familyArray.length; i++) { 168 fontFamilies[i] = FontFamily_Delegate.getDelegate(familyArray[i]); 169 } 170 Typeface_Delegate delegate = new Typeface_Delegate(fontFamilies, Typeface.NORMAL); 171 return sManager.addNewDelegate(delegate); 172 } 173 174 @LayoutlibDelegate 175 /*package*/ static void nativeUnref(long native_instance) { 176 sManager.removeJavaReferenceFor(native_instance); 177 } 178 179 @LayoutlibDelegate 180 /*package*/ static int nativeGetStyle(long native_instance) { 181 Typeface_Delegate delegate = sManager.getDelegate(native_instance); 182 if (delegate == null) { 183 return 0; 184 } 185 186 return delegate.mStyle; 187 } 188 189 @LayoutlibDelegate 190 /*package*/ static void nativeSetDefault(long native_instance) { 191 sDefaultTypeface = native_instance; 192 } 193 194 @LayoutlibDelegate 195 /*package*/ static File getSystemFontConfigLocation() { 196 return new File(sFontLocation); 197 } 198 199 // ---- Private delegate/helper methods ---- 200 201 private Typeface_Delegate(@NonNull FontFamily_Delegate[] fontFamilies, int style) { 202 this(fontFamilies, style, FontFamily_Delegate.DEFAULT_FONT_WEIGHT); 203 } 204 205 public Typeface_Delegate(@NonNull FontFamily_Delegate[] fontFamilies, int style, int weight) { 206 mFontFamilies = fontFamilies; 207 mStyle = style; 208 mWeight = weight; 209 } 210} 211