/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.perseus.builder;
import com.sun.perseus.model.FontFace;
import com.sun.perseus.model.ModelNode;
import com.sun.perseus.model.UpdateAdapter;
import com.sun.perseus.model.DocumentNode;
import com.sun.perseus.platform.ResourceHandler;
import java.io.InputStream;
import java.io.IOException;
import java.io.Reader;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.ParserConfigurationException;
/**
* This helper class encapsulates the creation of a default <tt>FontFace</tt>
* which a renderer can use. <br />
*
* This class tries to load an SVG file containing a font. The resource
* identifier for the default font is: <br />
* <tt>com/sun/perseus/renderer/resources/defaultFont.svg</tt><br />
*
* <b>Note</b>: the <tt>defaultFont.svg</tt> is loaded and its first
* <tt><font></tt> element is loaded. The first <tt><font></tt>
* element must be the first child of the root <tt><svg></tt> element. Any
* other structure for the <tt>defaultFont.svg</tt> file will result in an
* <tt>Error</tt>.
*
* This helper class also encapsulates the creation and loading of a set
* of <tt>FontFaces</tt> for the initial font-family value. The fonts are
* expected to all be in a single initial font file: <br />
* <tt>com/sun/perseus/renderer/resources/initialFont.svg</tt>
*
*
* <b>Note</b>: the <tt>initialFont.svg</tt> is loaded and all the
* children of the root <tt><svg></tt> element are expected to
* be <tt><font></tt> elements. Any
* other structure for the <tt>initialFont.svg</tt> file will result in an
* <tt>Error</tt>.
*
* @see com.sun.perseus.render.RenderGraphics
*
* @version $Id: DefaultFontFace.java,v 1.6 2006/07/17 00:35:43 st125089 Exp $
*/
public final class DefaultFontFace {
/**
* The default font face is cached so that it is loaded only
* once
*/
protected static FontFace defaultFontFace;
/**
* The set of initial font faces is cached so that it is loaded
* only once.
*/
protected static FontFace[] initialFontFaces;
/**
* @return the default font face. This font face is loaded from the
* {@link #ResourceHandler.DEFAULT_FONT_FACE_FILE
* ResourceHandler.DEFAULT_FONT_FACE} resource.
*/
public static FontFace getDefaultFontFace() {
if (defaultFontFace == null) {
loadDefaultFontFace();
}
return defaultFontFace;
}
/**
* @return the initial font faces. The initial font faces are
* loaded from the
* {@link #ResourceHandler.INITIAL_FONT_FACE_FILE
* ResourceHandler.INITIAL_FONT_FACE_FILE} resource.
*/
public static FontFace[] getInitialFontFaces() {
if (initialFontFaces == null) {
loadInitialFontFaces();
}
return initialFontFaces;
}
/**
* Loads the initial font faces. This assumes that the font face file
* has not been loaded already. If the load of the font face fails, the
* application throws an error.
*
* @throws Error if there is an error while loading the file. An error
* is generated.
* @see #getInitialFontFaces
*/
static void loadInitialFontFaces() throws Error {
try {
InputStream is =
ResourceHandler.getInitialFontResource();
if (is == null) {
throw new Exception
(Messages.formatMessage
(Messages.ERROR_CANNOT_LOAD_RESOURCE,
new Object[] {"Initial Font"}));
}
ModelNode svg = loadSVGFontResource(is);
// Now, get the FontFace from the tree.
// vp -> svg -> font[i] -> font-face
// Count the font children
int n = 0;
ModelNode c = svg.getFirstChildNode();
while (c != null) {
n++;
c = c.getNextSiblingNode();
}
initialFontFaces = new FontFace[n];
ModelNode font = svg.getFirstChildNode();
for (int i = 0; i < initialFontFaces.length; i++) {
initialFontFaces[i] = (FontFace) font.getFirstChildNode();
font = font.getNextSiblingNode();
}
} catch (Exception e) {
// Do not tolerate any error as this is critical for the operation
// of the toolkit.
e.printStackTrace();
throw new Error();
}
}
/**
* Loads the default font face. This assumes that the font face file
* has not been loaded already. If the load of the font face fails, the
* application throws an error.
*
* @throws Error if there is an error while loading the default font
* face file.
* @see #getDefaultFontFace
*/
static void loadDefaultFontFace() throws Error {
try {
InputStream is =
ResourceHandler.getDefaultFontResource();
if (is == null) {
throw new Exception
(Messages.formatMessage
(Messages.ERROR_CANNOT_LOAD_RESOURCE,
new Object[] {"Default Font"}));
}
ModelNode svg = loadSVGFontResource(is);
// Now, get the FontFace from the tree.
// svg -> font -> font-face
defaultFontFace = (FontFace)
svg.getFirstChildNode().getFirstChildNode();
} catch (Exception e) {
// Do not tolerate any error as this is critical for the operation
// of the toolkit.
e.printStackTrace();
throw new Error();
}
}
/**
* Helper method: loads an SVG Font resource file
* @param svgResource the SVG Font resource file
* @return The root <tt><svg></tt> element representing the
* resource file.
* @throws Exception if an error happens while loading the resource
*/
protected static ModelNode loadSVGFontResource(final InputStream is)
throws Exception {
// We use JAXP to get a SAX 2 Parser
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(true);
SAXParser parser = null;
try {
parser = factory.newSAXParser();
} catch (ParserConfigurationException e) {
// maybe validation is not supported
factory.setValidating(false);
parser = factory.newSAXParser();
}
// Configure a ModelBuilder to turn an SVG document
// into a ModelNode tree
DocumentNode root = new DocumentNode();
UpdateAdapter ul = new UpdateAdapter();
root.setUpdateListener(ul);
ModelBuilder modelBuilder = new ModelBuilder(null, root);
ul.loadStarting(root, is);
try {
parser.parse(is, modelBuilder);
} finally {
try {
is.close();
} catch (IOException ioe) {
}
int n = modelBuilder.entityStreams.size();
for (int i = 0; i < n; i++) {
Reader r = (Reader) modelBuilder.entityStreams.elementAt(i);
try {
r.close();
} catch (IOException ioe) {
// Do nothing: this means the stream was
// closed by the SAX parser.
}
}
}
if (!ul.loadSuccess()) {
throw new Exception
(Messages.formatMessage
(Messages.ERROR_CANNOT_LOAD_RESOURCE,
new Object[] {"SVG System Font Resource"}));
}
// trace(modelBuilder.getModelRoot(), "");
return modelBuilder.getModelRoot().getFirstChildNode();
}
/**
* Private default constructor to prevent instantiation of this
* utility class
*/
private DefaultFontFace() {
}
}