blob: 27c2cefb1b238ceba22e719cc48d74dc1272c7d6 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// 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 <code>moduleFactory</code>, 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;
}
}
}