All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.fontengine.font.mac.FontFactory Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
/**
 * 
 */
package com.adobe.fontengine.font.mac;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.adobe.agl.util.ULocale;
import com.adobe.fontengine.font.Font;
import com.adobe.fontengine.font.FontData;
import com.adobe.fontengine.font.FontImpl;
import com.adobe.fontengine.font.FontLoadingException;
import com.adobe.fontengine.font.InvalidFontException;
import com.adobe.fontengine.font.UnsupportedFontException;
import com.adobe.fontengine.font.mac.FONDResourceHandler.Association;
import com.adobe.fontengine.font.mac.sfntResourceHandler.SfntResource;
import com.adobe.fontengine.fontmanagement.ResourceFont;
import com.adobe.internal.io.ExtendedDataInputStream;
import com.adobe.internal.mac.resource.ResourceParser;

/**
 * Factory for building Mac resource fonts from data or resource fork type resources.
 *
 */
public class FontFactory 
{
	private static final String RESOURCE_FORK_EXTENSION = "/..namedfork/rsrc";
	private static final String DFONT_SUFFIX = ".dfont";

	public static final int UNKNOWN = 0;
	public static final int RESOURCE_FORK_FONT = 1;
	public static final int DATA_FORK_FONT = 2;

	/**
	 * @param url this is the full URL including any resource fork information
	 * @param type is this a data or resource fork
	 * @param fontID the id of the font within the resource
	 * @param fondID the id of the FOND resource which describes this font
	 * @return a FontData loaded from the URL given
	 * @throws InvalidFontException
	 * @throws UnsupportedFontException
	 * @throws FontLoadingException
	 */
	public static FontData load(URL url, int type, int fontID, int fondID) 
	throws InvalidFontException, UnsupportedFontException, FontLoadingException
	{
		FontData rsrcFontData = null;
		ResourceParser parser = new ResourceParser();
		FONDResourceHandler handlerFOND = new FONDResourceHandler();
		versResourceHandler handlervers = new versResourceHandler();
		sfntResourceHandler handlersfnt = new sfntResourceHandler(fontID);
		parser.addHandler(handlerFOND);
		parser.addHandler(handlervers);
		parser.addHandler(handlersfnt);

		try {
			parser.setURL(url);
			parser.parse();
		} catch (IOException e) {
			throw new FontLoadingException(e);
		}

		Map sfntMap = handlersfnt.getResources();
		Set associationSet = handlerFOND.getAssociations();

		for (Association association : associationSet)
		{
			if (fondID == association.getFondID() && (fontID == association.getFontID()))
			{
				SfntResource resource = sfntMap.get(fontID);
				if (resource != null)
				{
					Font font = resource.getFont();
					if (font != null)
					{
						rsrcFontData = new ResourceFontData(
								((FontImpl) font).getFontData(), scriptCodeToCharset(resource.getScriptCode()),
								association.getName(), resource.getName(), association.isBold(), association.isItalic());
						break;
					}
				}
			}
		}

		return rsrcFontData;
	}

	/**
	 * @param url the base URL of the font not including any possible resource fork information
	 * @param type the type of the resource - data or resource fork
	 * @return all available fonts from this resource that are of a type understood
	 * @throws InvalidFontException
	 * @throws UnsupportedFontException
	 * @throws FontLoadingException
	 */
	public static ResourceFont[] load(URL url, int type) 
	throws InvalidFontException, UnsupportedFontException, FontLoadingException
	{
		ResourceParser parser = new ResourceParser();
		FONDResourceHandler handlerFOND = new FONDResourceHandler();
		versResourceHandler handlervers = new versResourceHandler();
		sfntResourceHandler handlersfnt = new sfntResourceHandler();
		parser.addHandler(handlerFOND);
		parser.addHandler(handlervers);
		parser.addHandler(handlersfnt);

		try {
			if (type == RESOURCE_FORK_FONT)
			{
				url = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile() + RESOURCE_FORK_EXTENSION);
			}
			parser.setURL(url);
			parser.parse();
		} catch (IOException e) {
			throw new FontLoadingException(e);
		}

		Map sfntMap = handlersfnt.getResources();
		Set associationSet = handlerFOND.getAssociations();

		List fonts = new ArrayList();

		for (Association association : associationSet)
		{
			int sfntID = association.getFontID();
			SfntResource resource = sfntMap.get(sfntID);
			if (resource != null)
			{
				Font font = resource.getFont();
				if (font != null)
				{
					FontData rsrcFontData = new ResourceFontData(
							((FontImpl) font).getFontData(), scriptCodeToCharset(resource.getScriptCode()),
							association.getName(), resource.getName(), association.isBold(), association.isItalic());
					Font rsrcFont = new ResourceFont(url, type, sfntID, association.getFondID(), rsrcFontData);
					fonts.add(rsrcFont);
				}
			}
		}

		ResourceFont[] a = new ResourceFont [fonts.size()];
		return fonts.toArray(a);
	}

	public static int getNumBytesNeededToIdentify() 
	{
		// this is the resource file header length
		// we can tell if it's not a resource file in that length
		// but we can't reliably tell if it is
		// combined with the url name though it's a good guess
		return 16;
	}

	public static int isResourceFont(byte[] bytes, URL url) 
	throws IOException 
	{
		InputStream rsrcStream = null;
		int streamType = UNKNOWN;

		try
		{
			rsrcStream = getDataResourceFontStream(url);
			if (rsrcStream != null)
			{
				streamType = DATA_FORK_FONT;
			} else {
				rsrcStream = getResourceStream(url);
				if (rsrcStream != null)
				{
					streamType = RESOURCE_FORK_FONT;
				}
			}
			if (rsrcStream == null)
			{
				return UNKNOWN;
			}

			long dataOffset;
			long mapOffset;
			long dataLength;
			long mapLength;
			try {
				ExtendedDataInputStream dis = new ExtendedDataInputStream(rsrcStream);
				dataOffset = dis.readUnsignedInt();
				mapOffset = dis.readUnsignedInt();
				dataLength = dis.readUnsignedInt();
				mapLength = dis.readUnsignedInt();
			} catch (Exception e) {
				return UNKNOWN;
			}

			if (((mapOffset > dataOffset) && (mapOffset < (dataOffset + dataLength)))
					|| ((dataOffset > mapOffset) && (dataOffset < (mapOffset + mapLength))))
			{
				return UNKNOWN;
			}

			return streamType;

		} finally {
			if (rsrcStream != null)
			{
				rsrcStream.close();
			}
		}
	}

	private static InputStream getResourceStream(URL url) throws IOException 
	{
		URL rsrcURL = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile() + RESOURCE_FORK_EXTENSION);
		InputStream rsrcStream = null;
		try {
			rsrcStream = rsrcURL.openStream();
		} catch (FileNotFoundException e) {
			// ignore this - it means that there is no resource fork
		}
		return rsrcStream;
	}

	private static InputStream getDataResourceFontStream(URL url) 
	throws IOException 
	{
		InputStream rsrcStream = null;

		String file = url.getFile();
		if (file.endsWith(DFONT_SUFFIX))
		{
			rsrcStream = url.openStream();
		}
		return rsrcStream;
	}


	// TODO - this needs to move to the Rideau ScriptUtility class
	// but that means that Rideau will require ULocale and ScriptUtility will need to be made public
	private static final String[] SCRIPTID_TO_ULOCALE =
	{
		"en",							//smRoman	0	Roman	-> English
		"ja",							//smJapanese	1	Japanese	-> Japanese
		"zh-Hant",						//smTradChinese	2	Traditional Chinese
		"ko",							//smKorean	3	Korean	-> Korean
		"ar",							//smArabic	4	Arabic	-> Arabic
		"he",							//smHebrew	5	Hebrew	-> Hebrew
		"el",							//smGreek	6	Greek	-> Greek
		"ru",							//smCyrillic	7	Cyrillic	-> Russian
		"MacSymbol",					//smRSymbol	8	Right-to-left symbols
		"hi",							//smDevanagari	9	Devanagari	-> Hindi
		"pa",							//smGurmukhi	10	Gurmukhi	-> Punjabi
		"gu",							//smGujarati	11	Gujarati	-> Gujarati
		null,							//smOriya	12	Oriya
		null,							//smBengali	13	Bengali
		null,							//smTamil	14	Tamil
		null,							//smTelugu	15	Telugu
		null,							//smKannada	16	Kannada/Kanarese
		null,							//smMalayalam	17	Malayalam
		null,							//smSinhalese	18	Sinhalese
		null,							//smBurmese	19	Burmese
		null,							//smKhmer	20	Khmer
		"th",							//smThai	21	Thai	-> Thai
		null,							//smLaotian	22	Laotian
		null,							//smGeorgian	23	Georgian
		null,							//smArmenian	24	Armenian
		"zh-Hans",						//smSimpChinese	25	Simplified Chinese
		null,							//smTibetan	26	Tibetan
		null,							//smMongolian	27	Mongolian
		null,							//smEthiopic	28	= smGeez  and  smGeez	28	Geez/Ethiopic
		"MacCentralEuropean",			//smEastEurRoman	29	Extended Roman for Slavic and Baltic languages
		null,							//smVietnamese	30	Extended Roman for Vietnamese
		null,							//smExtArabic	31	Extended Arabic for Sindhi
		null,							//smUninterp	32	Uninterpreted symbols
	};

	static final ULocale scriptCodeToCharset(int script)
	{
		script = Math.min(script, SCRIPTID_TO_ULOCALE.length - 1);
		String locale = SCRIPTID_TO_ULOCALE[script];
		if (locale == null)
		{
			locale = SCRIPTID_TO_ULOCALE[0];
		}
		return new ULocale(locale);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy