blob: 7fb37172ab6edb4e67addd12d39a4e7b1e22ecc4 [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 org.apache.batik.bridge;
import java.awt.Font;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.apache.batik.dom.AbstractNode;
import org.apache.batik.gvt.font.AWTFontFamily;
import org.apache.batik.gvt.font.FontFamilyResolver;
import org.apache.batik.gvt.font.GVTFontFace;
import org.apache.batik.gvt.font.GVTFontFamily;
import org.apache.batik.util.ParsedURL;
import org.apache.batik.util.XMLConstants;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.svg.SVGDocument;
/**
* This class represents a <font-face> element or @font-face rule
*
* @author <a href="mailto:bella.robinson@cmis.csiro.au">Bella Robinson</a>
* @version $Id$
*/
public abstract class FontFace extends GVTFontFace
implements ErrorConstants {
/**
* List of ParsedURL's referencing SVGFonts or TrueType fonts,
* or Strings naming locally installed fonts.
*/
List srcs;
/**
* Constructes an SVGFontFace with the specfied font-face attributes.
*/
public FontFace
(List srcs,
String familyName, float unitsPerEm, String fontWeight,
String fontStyle, String fontVariant, String fontStretch,
float slope, String panose1, float ascent, float descent,
float strikethroughPosition, float strikethroughThickness,
float underlinePosition, float underlineThickness,
float overlinePosition, float overlineThickness) {
super(familyName, unitsPerEm, fontWeight,
fontStyle, fontVariant, fontStretch,
slope, panose1, ascent, descent,
strikethroughPosition, strikethroughThickness,
underlinePosition, underlineThickness,
overlinePosition, overlineThickness);
this.srcs = srcs;
}
/**
* Constructes an SVGFontFace with the specfied fontName.
*/
protected FontFace(String familyName) {
super(familyName);
}
public static CSSFontFace createFontFace(String familyName,
FontFace src) {
return new CSSFontFace
(new LinkedList(src.srcs),
familyName, src.unitsPerEm, src.fontWeight,
src.fontStyle, src.fontVariant, src.fontStretch,
src.slope, src.panose1, src.ascent, src.descent,
src.strikethroughPosition, src.strikethroughThickness,
src.underlinePosition, src.underlineThickness,
src.overlinePosition, src.overlineThickness);
}
/**
* Returns the font associated with this rule or element.
*/
public GVTFontFamily getFontFamily(BridgeContext ctx) {
final FontFamilyResolver fontFamilyResolver = ctx.getFontFamilyResolver();
String name = fontFamilyResolver.lookup(familyName);
if (name != null) {
GVTFontFace ff = createFontFace(name, this);
return new AWTFontFamily(ff);
}
Iterator iter = srcs.iterator();
while (iter.hasNext()) {
Object o = iter.next();
if (o instanceof String) {
String str = (String)o;
name = fontFamilyResolver.lookup(str);
if (name != null) {
GVTFontFace ff = createFontFace(str, this);
return new AWTFontFamily(ff);
}
} else if (o instanceof ParsedURL) {
try {
GVTFontFamily ff = getFontFamily(ctx, (ParsedURL)o);
if (ff != null)
return ff;
} catch (SecurityException ex) {
// Security violation notify the user but keep going.
ctx.getUserAgent().displayError(ex);
} catch (BridgeException ex) {
// If Security violation notify
// the user but keep going.
if (ERR_URI_UNSECURE.equals(ex.getCode()))
ctx.getUserAgent().displayError(ex);
} catch (Exception ex) {
// Do nothing couldn't get Referenced URL.
}
}
}
return new AWTFontFamily(this);
}
/**
* Tries to build a GVTFontFamily from a URL reference
*/
protected GVTFontFamily getFontFamily(BridgeContext ctx,
ParsedURL purl) {
String purlStr = purl.toString();
Element e = getBaseElement(ctx);
SVGDocument svgDoc = (SVGDocument)e.getOwnerDocument();
String docURL = svgDoc.getURL();
ParsedURL pDocURL = null;
if (docURL != null)
pDocURL = new ParsedURL(docURL);
// try to load an SVG document
String baseURI = AbstractNode.getBaseURI(e);
purl = new ParsedURL(baseURI, purlStr);
UserAgent userAgent = ctx.getUserAgent();
try {
userAgent.checkLoadExternalResource(purl, pDocURL);
} catch (SecurityException ex) {
// Can't load font - Security violation.
// We should not throw the error that is for certain, just
// move down the font list, but do we display the error or not???
// I'll vote yes just because it is a security exception (other
// exceptions like font not available etc I would skip).
userAgent.displayError(ex);
return null;
}
if (purl.getRef() != null) {
// Reference must be to a SVGFont.
Element ref = ctx.getReferencedElement(e, purlStr);
if (!ref.getNamespaceURI().equals(SVG_NAMESPACE_URI) ||
!ref.getLocalName().equals(SVG_FONT_TAG)) {
return null;
}
SVGDocument doc = (SVGDocument)e.getOwnerDocument();
SVGDocument rdoc = (SVGDocument)ref.getOwnerDocument();
Element fontElt = ref;
if (doc != rdoc) {
fontElt = (Element)doc.importNode(ref, true);
String base = AbstractNode.getBaseURI(ref);
Element g = doc.createElementNS(SVG_NAMESPACE_URI, SVG_G_TAG);
g.appendChild(fontElt);
g.setAttributeNS(XMLConstants.XML_NAMESPACE_URI,
"xml:base", base);
CSSUtilities.computeStyleAndURIs(ref, fontElt, purlStr);
}
// Search for a font-face element
Element fontFaceElt = null;
for (Node n = fontElt.getFirstChild();
n != null;
n = n.getNextSibling()) {
if ((n.getNodeType() == Node.ELEMENT_NODE) &&
n.getNamespaceURI().equals(SVG_NAMESPACE_URI) &&
n.getLocalName().equals(SVG_FONT_FACE_TAG)) {
fontFaceElt = (Element)n;
break;
}
}
// todo : if the above loop fails to find a fontFaceElt, a null is passed to createFontFace()
SVGFontFaceElementBridge fontFaceBridge;
fontFaceBridge = (SVGFontFaceElementBridge)ctx.getBridge
(SVG_NAMESPACE_URI, SVG_FONT_FACE_TAG);
GVTFontFace gff = fontFaceBridge.createFontFace(ctx, fontFaceElt);
return new SVGFontFamily(gff, fontElt, ctx);
}
// Must be a reference to a 'Web Font'.
// Let's see if JDK can parse it.
try {
Font font = Font.createFont(Font.TRUETYPE_FONT,
purl.openStream());
return new AWTFontFamily(this, font);
} catch (Exception ex) {
}
return null;
}
/**
* Default implementation uses the root element of the document
* associated with BridgeContext. This is useful for CSS case.
*/
protected Element getBaseElement(BridgeContext ctx) {
SVGDocument d = (SVGDocument)ctx.getDocument();
return d.getRootElement();
}
}