//////////////////////////////////////////////////////////////////////////////// // // 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 mx.core { import flash.system.Capabilities; import flash.text.FontStyle; import flash.text.TextField; import flash.text.TextFormat; import flash.text.engine.FontDescription; import flash.utils.Dictionary; import flash.utils.getQualifiedClassName; import mx.managers.ISystemManager; import mx.resources.IResourceManager; import mx.resources.ResourceManager; use namespace mx_internal; [ExcludeClass] /** * @private * A singleton to contain a list of all the embeded fonts in use * and the associated SWF/moduleFactory where the fonts are defined. */ public class EmbeddedFontRegistry implements IEmbeddedFontRegistry { include "../core/Version.as"; //-------------------------------------------------------------------------- // // Class variables // //-------------------------------------------------------------------------- /** * @private */ private static var fonts:Object = {}; /** * @private */ private static var cachedFontsForObjects:Dictionary = new Dictionary(true); /** * @private */ private static var instance:IEmbeddedFontRegistry; /** * @private * Used for accessing localized Error messages. */ private var _resourceManager:IResourceManager; /** * @private */ private static var staticTextFormat:TextFormat = new TextFormat(); /** * @private */ private static var flaggedObjects:Dictionary = new Dictionary(true); //-------------------------------------------------------------------------- // // Class methods // //-------------------------------------------------------------------------- /** * @private */ public static function getInstance():IEmbeddedFontRegistry { if (!instance) instance = new EmbeddedFontRegistry(); return instance; } /** * @private * Creates a key for the embedded font. * * @param font FlexFont object, may not be null. * * @return String key */ private static function createFontKey(font:EmbeddedFont):String { return font.fontName + font.fontStyle; } /** * Creates an EmbeddedFont from a font key. * * @param key A string that represents a key * created by createFontKey(); may not be null. * * @return An EmbeddedFont with the attributes from the key. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ private static function createEmbeddedFont(key:String):EmbeddedFont { var fontName:String; var fontBold:Boolean; var fontItalic:Boolean; var index:int = endsWith(key,FontStyle.REGULAR); if (index > 0) { fontName = key.substring(0, index); return new EmbeddedFont(fontName, false, false); } index = endsWith(key, FontStyle.BOLD); if (index > 0) { fontName = key.substring(0, index); return new EmbeddedFont(fontName, true, false); } index = endsWith(key, FontStyle.BOLD_ITALIC); if (index > 0) { fontName = key.substring(0, index); return new EmbeddedFont(fontName, true, true); } index = endsWith(key, FontStyle.ITALIC); if (index > 0) { fontName = key.substring(0, index); return new EmbeddedFont(fontName, false, true); } return new EmbeddedFont("", false, false); } /** * Tests if a string ends with another string. * * @returns index into string if it ends with the matching string, otherwise returns -1. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ private static function endsWith(s:String, match:String):int { var index:int = s.lastIndexOf(match); if (index > 0 && (index + match.length == s.length)) { return index; } return -1; } /** * @private * Registers fonts from the info["fonts"] startup information. * * @param fonts Object obtained from the info["fonts"] call * on a moduleFactory object. * * @param moduleFactory The module factory of the caller. */ public static function registerFonts(fonts:Object, moduleFactory:IFlexModuleFactory):void { var fontRegistry:IEmbeddedFontRegistry; try { fontRegistry = IEmbeddedFontRegistry( Singleton.getInstance("mx.core::IEmbeddedFontRegistry")); } catch (e:Error) { Singleton.registerClass("mx.core::IEmbeddedFontRegistry", EmbeddedFontRegistry); fontRegistry = IEmbeddedFontRegistry( Singleton.getInstance("mx.core::IEmbeddedFontRegistry")); } // Loop thru all the font objects and put them in the registry for (var f:Object in fonts) { var fontObj:Object = fonts[f]; // For each value of "regular", "bold", "italic", and "boldItalic" // register the font name. for (var fieldIter:String in fontObj) { if (fontObj[fieldIter] == false) continue; // no font to register var bold:Boolean; var italic:Boolean; if (fieldIter == "regular") { bold = false; italic = false; } else if (fieldIter == "boldItalic") { bold = true; italic = true; } else if (fieldIter == "bold") { bold = true; italic = false; } else if (fieldIter == "italic") { bold = false; italic = true; } fontRegistry.registerFont( new EmbeddedFont(String(f), bold, italic), moduleFactory); } } } //-------------------------------------------------------------------------- // // Properties // //-------------------------------------------------------------------------- /** * @private * * The EmbeddedFontRegistry can be created in frame1 when an RSL loads a font. Defer creating * a resource manager until it is needed. * */ private function get resourceManager():IResourceManager { if (!_resourceManager) _resourceManager = ResourceManager.getInstance(); return _resourceManager; } //-------------------------------------------------------------------------- // // Methods // //-------------------------------------------------------------------------- /** * Convert a font styles into a String as using by flash.text.FontStyle. * * @param bold true if the font is bold, false otherwise. * * @param italic true if the font is italic, false otherwise. * * @return A String that matches one of the values in flash.text.FontStyle. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function getFontStyle(bold:Boolean, italic:Boolean):String { var style:String = FontStyle.REGULAR; if (bold && italic) style = FontStyle.BOLD_ITALIC; else if (bold) style = FontStyle.BOLD; else if (italic) style = FontStyle.ITALIC; return style; } /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function registerFont(font:EmbeddedFont, moduleFactory:IFlexModuleFactory):void { var fontKey:String = createFontKey(font); var fontDictionary:Dictionary = fonts[fontKey]; if (!fontDictionary) { fontDictionary = new Dictionary(true); // use weak ref for keys fonts[fontKey] = fontDictionary; } fontDictionary[moduleFactory] = 1; } /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function deregisterFont(font:EmbeddedFont, moduleFactory:IFlexModuleFactory):void { var fontKey:String = createFontKey(font); var fontDictionary:Dictionary = fonts[fontKey]; if (fontDictionary != null) { delete fontDictionary[moduleFactory]; var count:int = 0; for (var obj:Object in fontDictionary) { count++; } if (count == 0) delete fonts[fontKey]; } } /** * Returns true if the embedded font with the given characteristics is * in the moduleFactory, otherwise returns false. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function isFontRegistered(font:EmbeddedFont, moduleFactory:IFlexModuleFactory):Boolean { var fontKey:String = createFontKey(font); var fontDictionary:Dictionary = fonts[fontKey]; return fontDictionary && fontDictionary[moduleFactory] == 1; } /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function getFonts():Array { var fontArray:Array = []; for (var key:String in fonts) { fontArray.push(createEmbeddedFont(key)); } return fontArray; } /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function getAssociatedModuleFactory( fontName:String, bold:Boolean, italic:Boolean, object:Object, defaultModuleFactory:IFlexModuleFactory, systemManager:ISystemManager, embeddedCff:*=undefined): IFlexModuleFactory { var font:EmbeddedFont; font = cachedFontsForObjects[object]; if (!font) { font = new EmbeddedFont(fontName, bold, italic); cachedFontsForObjects[object] = font; } else { // replace if not the same if (font.fontName != fontName || font.bold != bold || font.italic != italic) { font = new EmbeddedFont(fontName, bold, italic); cachedFontsForObjects[object] = font; } } var result:IFlexModuleFactory; var fontDictionary:Dictionary = fonts[createFontKey(font)]; if (fontDictionary) { // First lookup in the dictionary. If not found, then // take the first moduleFactory in the dictionary. // A module can register a font that is not unique and still // use that font as long as its components specify the moduleFactory. // A module can use fonts in other modules but // to get consistent behavior the font should be unique. var found:int = fontDictionary[defaultModuleFactory]; if (found) result = defaultModuleFactory; else { for (var iter:Object in fontDictionary) { result = iter as IFlexModuleFactory; break; } } } if (!result && systemManager) { // If we found the font, then it is embedded. Some fonts are not // listed in info() and are therefore not resolvable with our // registry, so we call isFontFaceEmbedded() which gets the list // of embedded fonts from the player. staticTextFormat.font = fontName; staticTextFormat.bold = bold; staticTextFormat.italic = italic; if (systemManager.isFontFaceEmbedded(staticTextFormat)) result = systemManager; } // We must ensure that the requested font is in fact valid for our // given usage and context. if (result && embeddedCff != undefined && Capabilities.isDebugger) { var compatible:Boolean = embeddedCff ? result.callInContext(FontDescription.isFontCompatible, null, [fontName, bold ? "bold" : "normal", italic ? "italic" : "normal"]) : result.callInContext(TextField.isFontCompatible, null, [fontName, getFontStyle(bold, italic)]); if (!compatible) { // We want to avoid reporting redundant warnings so we keep tabs // on which instances we've already flagged as incompatible. if (!flaggedObjects[object]) { var objName:String = getQualifiedClassName(object); objName += "name" in object && object.name != null ? " ("+object.name+") " : ""; trace(resourceManager.getString( "core", "fontIncompatible", [fontName, objName, embeddedCff])); flaggedObjects[object] = true; } } } return result; } } }