blob: 21a8a13c3ef3f905659a90c224d7e6fb7c2c7f33 [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 flash.fonts;
import flash.swf.TagValues;
import flash.swf.builder.tags.FontBuilder;
import flash.swf.tags.DefineFont;
import flash.swf.tags.DefineFont3;
import flash.swf.types.GlyphEntry;
import flash.util.LRUCache;
import java.net.URL;
import java.util.Map;
/**
* Provides a simple LRU caching mechanism for Font Manager implementations.
*
* A manager's caches and cache's members should be thread safe.
*
* @author Peter Farland
*/
@SuppressWarnings("unchecked")
public abstract class CachedFontManager extends FontManager
{
public static final short PURGE_SIZE = 2;
public static final float DEFAULT_FONT_SIZE = 240f; //12pt * 20 - authoring tool multiplies size by 20 to increase granularity in twips
public static final Float DEFAULT_FONT_SIZE_OBJECT = new Float(DEFAULT_FONT_SIZE);
public static final String DEFAULT_FONT_SIZE_STRING = "240";
public static final String COMPATIBILITY_VERSION = "CompatibilityVersion";
public static final String MAX_CACHED_FONTS_KEY = "max-cached-fonts";
public static final String MAX_GLYPHS_PER_FACE_KEY = "max-glyphs-per-face";
public short maxEntries = 20;
public short maxGlyphsPerFace = 1000;
public short maxFacesPerFont = 4; // Note that Flash only supports PLAIN, BOLD, ITALIC, and BOLD+ITALIC
private FontCache fontCache;
private FontFileCache fontFileCache;
protected CachedFontManager()
{
super();
}
public void initialize(Map map)
{
super.initialize(map);
if (map != null)
{
String prop = (String)map.get(MAX_CACHED_FONTS_KEY);
if (prop != null)
{
try
{
maxEntries = Short.parseShort(prop);
}
catch (Throwable t)
{
}
}
prop = (String)map.get(MAX_GLYPHS_PER_FACE_KEY);
if (prop != null)
{
try
{
maxGlyphsPerFace = Short.parseShort(prop);
}
catch (Throwable t)
{
}
}
}
fontCache = new FontCache(this);
fontFileCache = new FontFileCache(this);
}
public DefineFont createDefineFont(int tagCode, FontDescription font)
{
FontFace fontFace;
boolean useTwips = (tagCode == TagValues.stagDefineFont3);
if (font.source instanceof URL)
{
URL location = (URL)font.source;
fontFace = getEntryFromLocation(location, font.style, useTwips);
if (font.alias == null)
font.alias = fontFace.getFamily();
if (fontFace == null)
FontManager.throwFontNotFound(font.alias, null, font.style, location.toString());
}
else
{
String fontFamily = font.source.toString();
fontFace = getEntryFromSystem(fontFamily, font.style, useTwips);
if (font.alias == null)
font.alias = fontFace.getFamily();
if (fontFace == null)
FontManager.throwFontNotFound(font.alias, fontFamily, font.style, null);
}
FontBuilder builder = new FontBuilder(tagCode, fontFace, font.alias, font.advancedAntiAliasing);
// Add characters for unicode-range
int[][] ranges = getUnicodeRanges(font.unicodeRanges);
if (ranges != null)
{
for (int i = 0; i < ranges.length; i++)
{
int[] range = ranges[i];
if (range != null && range.length == 2)
{
int count = range[1] - range[0] + 1; // Inclusive range
builder.addCharset(range[0], count);
}
}
}
else
{
builder.addAllChars();
}
return (DefineFont)builder.build();
}
public void loadDefineFont(DefineFont tag, Object location)
{
if (tag instanceof DefineFont3)
{
loadDefineFont3((DefineFont3)tag, location);
}
}
protected void loadDefineFont3(DefineFont3 tag, Object location)
{
String family = null;
String locationKey = null;
if (location != null)
{
if (location instanceof URL)
locationKey = ((URL)location).toExternalForm();
else
locationKey = location.toString();
family = (String)getFontFileCache().get(locationKey);
}
if (family == null)
{
family = DefineFont3Face.getFamily(tag);
if (locationKey != null)
getFontFileCache().put(locationKey, family);
}
int style = DefineFont3Face.getStyle(tag);
// Look for whether we've got a FontSet for this family...
FontSet fontSet = (FontSet)getFontCache().get(family);
if (fontSet == null)
{
fontSet = new FontSet(maxFacesPerFont);
getFontCache().put(family, fontSet);
}
// Look to see whether we've got a FontFace for this style....
FontFace face = fontSet.get(style);
if (face == null)
{
face = new DefineFont3Face(tag);
fontSet.put(style, face);
}
else
{
// We already have a FontFace for this style, if it's a
// CachedFontFace, try to update the existing cache with any
// extra glyphs present on this tag...
if (face instanceof CachedFontFace)
{
CachedFontFace cachedFontFace = (CachedFontFace)face;
char[] codepoints = tag.codeTable;
if (codepoints != null)
{
for (char i = 0; i < codepoints.length; i++)
{
char c = codepoints[i];
GlyphEntry ge = cachedFontFace.getGlyphEntry(c);
if (ge == null)
{
ge = DefineFont3Face.createGlyphEntryFromDefineFont(c, i, tag);
cachedFontFace.glyphCache.put(c, ge);
}
}
}
}
}
}
protected FontCache getFontCache()
{
if (fontCache == null)
initialize(null);
return fontCache;
}
protected FontFileCache getFontFileCache()
{
if (fontFileCache == null)
initialize(null);
return fontFileCache;
}
protected abstract String createFontFromLocation(Object location, int style, boolean useTwips);
protected abstract FontSet createSetForSystemFont(String family, int style, boolean useTwips);
/**
* A cache that maps font family names to a <code>FontSet</code> - a set
* of derived styles from the base family font.
*/
static class FontCache extends LRUCache
{
private static final long serialVersionUID = -2402480346505475961L;
FontCache(CachedFontManager manager)
{
super(manager.maxEntries / 2, manager.maxEntries, PURGE_SIZE);
}
/**
* We don't know whether we're looking by location or os family name, so
* we fail fast and don't attempt to fetch.
*
* @param key the font family name
* @return null
*/
protected Object fetch(Object key)
{
return null;
}
}
/**
* A cache mapping a font file location to a family name. If the location
* new, it will load the file to determine the family name and create an
* entry in the main fontCache.
*/
static class FontFileCache extends LRUCache
{
private static final long serialVersionUID = 5379979428987581921L;
FontFileCache(CachedFontManager manager)
{
super(manager.maxEntries / 2, manager.maxEntries, PURGE_SIZE);
}
/**
* We fail fast if we've not seen this location because
* we don't know whether the location will match
* requested style...
*
* @param key the location of the font file
*/
protected Object fetch(Object key)
{
return null;
}
}
}