| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| package flash.fonts; |
| |
| import java.net.URL; |
| import java.util.List; |
| import java.util.Properties; |
| import java.util.Map; |
| import java.util.StringTokenizer; |
| |
| import flash.swf.tags.DefineFont; |
| import flash.util.Trace; |
| |
| /** |
| * The FontManager provides a common interface to locating fonts from |
| * either locally (i.e. from the Operating System) or externally |
| * (i.e. from URL locations). |
| */ |
| @SuppressWarnings("unchecked") |
| public abstract class FontManager |
| { |
| public static final String LOCAL_FONT_PATHS = "local-font-paths"; |
| |
| public static final int PLAIN = 0; |
| public static final int BOLD = 1; |
| public static final int ITALIC = 2; |
| |
| protected Properties languageRanges; |
| protected FontManager parent; |
| |
| protected int majorCompatibilityVersion = 4; |
| |
| /** |
| * Constructor |
| */ |
| protected FontManager() |
| { |
| } |
| |
| /** |
| * Initialization properties can be provided as name/value pairs. |
| * |
| * @param map |
| */ |
| public void initialize(Map map) |
| { |
| if (map != null) |
| { |
| String compatVersion = (String)map.get(CachedFontManager.COMPATIBILITY_VERSION); |
| if (compatVersion != null) |
| { |
| String[] parts = compatVersion.split("\\."); |
| if (parts.length > 0) |
| { |
| try |
| { |
| int major = Integer.parseInt(parts[0]); |
| majorCompatibilityVersion = major; |
| } |
| catch (Throwable t) |
| { |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Provides the ability to chain managers. |
| * |
| * @param parent |
| */ |
| public void setParent(FontManager parent) |
| { |
| this.parent = parent; |
| } |
| |
| public void setLanguageRange(Properties languageRanges) |
| { |
| this.languageRanges = languageRanges; |
| } |
| |
| /** |
| * If a given language token is registered, the corresponding unicode range |
| * (specified as a CSS-2 formatted string) is returned. |
| * |
| * @param lang |
| */ |
| public String getLanguageRange(String lang) |
| { |
| String range = null; |
| |
| if (languageRanges != null && lang != null) |
| range = languageRanges.getProperty(lang); |
| |
| return range; |
| } |
| |
| /** |
| * Create a SWF DefineFont tag from a font file location specified as a URL. |
| * |
| * @param tagCode Specifies the version of the DefineFont SWF tag to create. |
| * @return A DefineFont tag |
| */ |
| public DefineFont createDefineFont(int tagCode, FontDescription desc) |
| { |
| // No op |
| return null; |
| } |
| |
| /** |
| * Attempts to load a font from the cache by location or from disk if it is |
| * the first request at this address. The location is bound to a font family |
| * name and defineFont type after the initial loading, and the relationship |
| * exists for the lifetime of the cache. |
| * |
| * @param location |
| * @param style |
| * @return FontSet.FontFace |
| */ |
| public abstract FontFace getEntryFromLocation(URL location, int style, |
| boolean useTwips); |
| |
| /** |
| * Attempts to locate a font by family name, style, and defineFont type from |
| * the runtime's list of fonts, which are primarily operating system |
| * registered fonts. |
| * |
| * @param familyName |
| * @param style either FontFace.PLAIN, FontFace.BOLD, FontFace.ITALIC or |
| * FontFace.BOLD+FontFace.ITALIC |
| * @return FontFace |
| */ |
| public abstract FontFace getEntryFromSystem(String familyName, int style, |
| boolean useTwips); |
| |
| /** |
| * Allows a DefineFont SWF tag to be the basis of a FontFace. |
| * |
| * @param tag The DefineFont tag |
| * @param location The original location of the asset that created the |
| * DefineFont SWF tag. |
| */ |
| public void loadDefineFont(DefineFont tag, Object location) |
| { |
| // No-op |
| } |
| |
| /** |
| * Allows a DefineFont SWF tag to be the basis of a FontFace. |
| * |
| * @param tag The DefineFont tag. |
| */ |
| public void loadDefineFont(DefineFont tag) |
| { |
| loadDefineFont(tag, null); |
| } |
| |
| /** |
| * Parses a String representation of Unicode character ranges into an array |
| * of int arrays. e.g. U+0020-U+007F,U+20345. Note that int is used to |
| * support code points beyond the BMP. |
| * |
| * @param value String representation of unicode character ranges |
| * @return int[][] Array of an array of ints representing code points of |
| * the specified ranges. |
| * @see http://www.w3.org/TR/REC-CSS2/fonts.html#descdef-unicode-range |
| */ |
| public int[][] getUnicodeRanges(String value) |
| { |
| int[][] ranges = null; |
| |
| // Check if it's a registered language name |
| String langRange = getLanguageRange(value); |
| if (langRange != null) |
| value = langRange; |
| |
| if (value != null) |
| { |
| // Remove extraneous formatting first |
| value = value.replace(';', ' ').replace('\n', ' ').replace('\r', ' ').replace('\f', ' '); |
| |
| StringTokenizer st = new StringTokenizer(value, ","); |
| |
| int count = st.countTokens(); |
| ranges = new int[count][2]; |
| parseRanges(st, ranges); |
| } |
| |
| return ranges; |
| } |
| |
| public static boolean isItalic(int style) |
| { |
| return style == ITALIC || style == (BOLD + ITALIC); |
| } |
| |
| public static boolean isBold(int style) |
| { |
| return style == BOLD || style == (BOLD + ITALIC); |
| } |
| |
| /** |
| * Given a list of class names, this utility method attempts to construct a |
| * chain of FontManagers. The class must extend FontManager and have a |
| * public no-args constructor. Invalid classes are skipped. |
| * |
| * @param managerClasses |
| * @return the last FontManager in the chain |
| * @deprecated |
| */ |
| public static FontManager create(List managerClasses, Map map) |
| { |
| return FontManager.create(managerClasses, map, null); |
| } |
| |
| /** |
| * Given a list of class names, this utility method attempts to construct a |
| * chain of FontManagers. The class must extend FontManager and have a |
| * public no-args constructor. Invalid classes are skipped. |
| * |
| * @param managerClasses List of class names representing FontManager |
| * implementations. |
| * @param map A Map of settings to be passed to the FontManager instance |
| * during initialization. |
| * @param languageRanges List of unicode character ranges for a given |
| * language. |
| * @return the last FontManager in the chain |
| */ |
| public static FontManager create(List managerClasses, Map map, Properties languageRanges) |
| { |
| FontManager manager = null; |
| |
| if (managerClasses != null) |
| { |
| for (int i = 0; i < managerClasses.size(); i++) |
| { |
| try |
| { |
| Object className = managerClasses.get(i); |
| if (className != null) |
| { |
| Class clazz = Class.forName(className.toString()); |
| Object obj = clazz.newInstance(); |
| if (obj instanceof FontManager) |
| { |
| FontManager fm = (FontManager)obj; |
| fm.initialize(map); |
| |
| if (manager != null) |
| fm.setParent(manager); |
| |
| if (languageRanges != null) |
| fm.setLanguageRange(languageRanges); |
| |
| manager = fm; |
| } |
| } |
| } |
| catch (Throwable t) |
| { |
| if (Trace.font) |
| { |
| Trace.trace(t.getMessage()); |
| } |
| } |
| } |
| } |
| |
| return manager; |
| } |
| |
| |
| public static void throwFontNotFound(String alias, String fontFamily, int style, String location) |
| { |
| StringBuilder message = new StringBuilder("Font for alias '"); |
| message.append(alias).append("' "); |
| if (style == FontFace.BOLD) |
| { |
| message.append("with bold weight "); |
| } |
| else if (style == FontFace.ITALIC) |
| { |
| message.append("with italic style "); |
| } |
| else if (style == (FontFace.BOLD + FontFace.ITALIC)) |
| { |
| message.append("with bold weight and italic style "); |
| } |
| else |
| { |
| message.append("with plain weight and style "); |
| } |
| |
| if (location != null) |
| { |
| message.append("was not found at: ").append(location.toString()); |
| } |
| else |
| { |
| message.append("was not found by family name '").append(fontFamily).append("'"); |
| } |
| throw new FontNotFoundException(message.toString()); |
| } |
| |
| /** |
| * Values are expressed as hexadecimal numbers, prefixed with |
| * "U+". For single numbers, the character '?' is assumed to mean |
| * 'any value' which creates a range of character positions. Otherwise, the |
| * range can be specified explicitly using a hyphen, e.g. U+00A0-U+00FF |
| * |
| * @param st |
| * @param ranges |
| */ |
| private static void parseRanges(StringTokenizer st, int[][] ranges) |
| { |
| int i = 0; |
| while (st.hasMoreElements()) |
| { |
| String element = ((String)st.nextElement()).trim().toUpperCase(); |
| |
| if (element.startsWith("U+")) |
| { |
| String range = element.substring(2).trim(); |
| String low; |
| String high; |
| |
| if (range.indexOf('?') > 0) // Wild-Card Range, e.g. U+00?? |
| { |
| low = range.replace('?', '0'); |
| high = range.replace('?', 'F'); |
| } |
| else if (range.indexOf('-') > 0) // Basic Range, e.g. U+0020-007E |
| { |
| low = range.substring(0, range.indexOf('-')); |
| String temp = range.substring(range.indexOf('-') + 1).trim(); |
| |
| // Support Flex's legacy additional U+ prefix on the |
| // high range (but not part of the CSS-2 specification). |
| if (temp.startsWith("U+")) |
| { |
| high = temp.substring(2).trim(); |
| } |
| else |
| { |
| high = temp; |
| } |
| } |
| else if (range.length() <= 8) // Single Char, e.g. U+0041 |
| { |
| low = range; |
| high = range; |
| } |
| else |
| { |
| throw new InvalidUnicodeRangeException(range); |
| } |
| |
| try |
| { |
| ranges[i][0] = Integer.parseInt(low, 16); |
| ranges[i][1] = Integer.parseInt(high, 16); |
| } |
| catch (Exception ex) |
| { |
| throw new InvalidUnicodeRangeException(range); |
| } |
| |
| i++; |
| } |
| else if (element.length() == 0) |
| { |
| continue; |
| } |
| else |
| { |
| throw new InvalidUnicodeRangeException(element); |
| } |
| } |
| } |
| |
| public static final class FontNotFoundException extends RuntimeException |
| { |
| private static final long serialVersionUID = -2385779348825570473L; |
| |
| public FontNotFoundException(String message) |
| { |
| super(message); |
| } |
| } |
| |
| public static final class InvalidUnicodeRangeException extends |
| RuntimeException |
| { |
| private static final long serialVersionUID = 3173208110428813980L; |
| |
| public InvalidUnicodeRangeException(String range) |
| { |
| this.range = range; |
| } |
| |
| public String range; |
| } |
| } |