/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2009 Jaspersoft Corporation. All rights reserved.
* http://www.jaspersoft.com
*
* Unless you have purchased a commercial license agreement from Jaspersoft,
* the following license terms apply:
*
* This program is part of JasperReports.
*
* JasperReports is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JasperReports 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with JasperReports. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.jasperreports.engine.util;
import java.awt.Font;
import java.awt.font.TextAttribute;
import java.text.AttributedCharacterIterator.Attribute;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import net.sf.jasperreports.engine.JRFont;
import net.sf.jasperreports.engine.JRRuntimeException;
import net.sf.jasperreports.engine.fonts.FontFace;
import net.sf.jasperreports.engine.fonts.FontFamily;
import net.sf.jasperreports.engine.fonts.FontInfo;
import net.sf.jasperreports.extensions.ExtensionsEnvironment;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author Teodor Danciu (teodord@users.sourceforge.net)
* @version $Id: JRFontUtil.java 3822 2010-05-20 16:59:22Z teodord $
*/
public final class JRFontUtil
{
private static final Log log = LogFactory.getLog(JRFontUtil.class);
/**
*.
*/
private static final InheritableThreadLocal threadMissingFontsCache = new InheritableThreadLocal()
{
@Override
protected Object initialValue() {
return new HashSet();
}
};
/**
*
*/
public static void copyNonNullOwnProperties(JRFont srcFont, JRFont destFont)
{
if(srcFont != null && destFont != null)
{
if (srcFont.getOwnFontName() != null)
{
destFont.setFontName(srcFont.getOwnFontName());
}
if (srcFont.isOwnBold() != null)
{
destFont.setBold(srcFont.isOwnBold());
}
if (srcFont.isOwnItalic() != null)
{
destFont.setItalic(srcFont.isOwnItalic());
}
if (srcFont.isOwnUnderline() != null)
{
destFont.setUnderline(srcFont.isOwnUnderline());
}
if (srcFont.isOwnStrikeThrough() != null)
{
destFont.setStrikeThrough(srcFont.isOwnStrikeThrough());
}
if (srcFont.getOwnFontSize() != null)
{
destFont.setFontSize(srcFont.getOwnFontSize());
}
if (srcFont.getOwnPdfFontName() != null)
{
destFont.setPdfFontName(srcFont.getOwnPdfFontName());
}
if (srcFont.getOwnPdfEncoding() != null)
{
destFont.setPdfEncoding(srcFont.getOwnPdfEncoding());
}
if (srcFont.isOwnPdfEmbedded() != null)
{
destFont.setPdfEmbedded(srcFont.isOwnPdfEmbedded());
}
}
}
/**
* Fills the supplied Map parameter with attributes copied from the JRFont parameter.
* The attributes include the TextAttribute.FONT, which has a java.awt.Font object as value.
* @deprecated Replaced by {@link #getAttributesWithoutAwtFont(Map, JRFont)}.
*/
public static Map getAttributes(Map attributes, JRFont font, Locale locale)
{
//Font awtFont = getAwtFont(font);//FIXMEFONT optimize so that we don't load the AWT font for all exporters.
Font awtFont =
getAwtFontFromBundles(
font.getFontName(),
((font.isBold()?Font.BOLD:Font.PLAIN)|(font.isItalic()?Font.ITALIC:Font.PLAIN)),
font.getFontSize(),
locale,
true
);
if (awtFont != null)
{
attributes.put(TextAttribute.FONT, awtFont);
}
getAttributesWithoutAwtFont(attributes, font);
return attributes;
}
/**
*
*/
public static Map getAttributesWithoutAwtFont(Map attributes, JRFont font)
{
attributes.put(TextAttribute.FAMILY, font.getFontName());
attributes.put(TextAttribute.SIZE, new Float(font.getFontSize()));
if (font.isBold())
{
attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
}
if (font.isItalic())
{
attributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
}
if (font.isUnderline())
{
attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
}
if (font.isStrikeThrough())
{
attributes.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
}
attributes.put(JRTextAttribute.PDF_FONT_NAME, font.getPdfFontName());
attributes.put(JRTextAttribute.PDF_ENCODING, font.getPdfEncoding());
if (font.isPdfEmbedded())
{
attributes.put(JRTextAttribute.IS_PDF_EMBEDDED, Boolean.TRUE);
}
return attributes;
}
/**
* Returns font information containing the font family, font face and font style.
*
* @param name the font family or font face name
* @param locale the locale
* @return a font info object
*/
public static FontInfo getFontInfo(String name, Locale locale)
{
//FIXMEFONT do some cache
List families = ExtensionsEnvironment.getExtensionsRegistry().getExtensions(FontFamily.class);
for (Iterator itf = families.iterator(); itf.hasNext();)
{
FontFamily family = (FontFamily)itf.next();
if (locale == null || family.supportsLocale(locale))
{
if (name.equals(family.getName()))
{
return new FontInfo(family, null, Font.PLAIN);
}
FontFace face = family.getNormalFace();
if (face != null && name.equals(face.getName()))
{
return new FontInfo(family, face, Font.PLAIN);
}
face = family.getBoldFace();
if (face != null && name.equals(face.getName()))
{
return new FontInfo(family, face, Font.BOLD);
}
face = family.getItalicFace();
if (face != null && name.equals(face.getName()))
{
return new FontInfo(family, face, Font.ITALIC);
}
face = family.getBoldItalicFace();
if (face != null && name.equals(face.getName()))
{
return new FontInfo(family, face, Font.BOLD | Font.ITALIC);
}
}
}
//throw new JRRuntimeException("Font family/face named '" + name + "' not found.");
return null;
}
/**
* Returns the font family names available through extensions, in alphabetical order.
*/
public static Collection getFontFamilyNames()
{
TreeSet familyNames = new TreeSet();//FIXMEFONT use collator for order?
//FIXMEFONT do some cache
List families = ExtensionsEnvironment.getExtensionsRegistry().getExtensions(FontFamily.class);
for (Iterator itf = families.iterator(); itf.hasNext();)
{
FontFamily family = (FontFamily)itf.next();
familyNames.add(family.getName());
}
return familyNames;
}
/**
* @deprecated Replaced by {@link #getAwtFontFromBundles(String, int, int, Locale, boolean)}.
*/
public static Font getAwtFontFromBundles(String name, int style, int size, Locale locale)
{
return getAwtFontFromBundles(name, style, size, locale, true);
}
/**
*
*/
public static Font getAwtFontFromBundles(String name, int style, int size, Locale locale, boolean ignoreMissingFont)
{
Font awtFont = null;
FontInfo fontInfo = getFontInfo(name, locale);
if (fontInfo != null)
{
int faceStyle = Font.PLAIN;
FontFamily family = fontInfo.getFontFamily();
FontFace face = fontInfo.getFontFace();
if (face == null)
{
if (((style & Font.BOLD) > 0) && ((style & Font.ITALIC) > 0))
{
face = family.getBoldItalicFace();
faceStyle = Font.BOLD | Font.ITALIC;
}
if (face == null && ((style & Font.BOLD) > 0))
{
face = family.getBoldFace();
faceStyle = Font.BOLD;
}
if (face == null && ((style & Font.ITALIC) > 0))
{
face = family.getItalicFace();
faceStyle = Font.ITALIC;
}
if (face == null)
{
face = family.getNormalFace();
faceStyle = Font.PLAIN;
}
// if (face == null)
// {
// throw new JRRuntimeException("Font family '" + family.getName() + "' does not have the normal font face.");
// }
}
else
{
faceStyle = fontInfo.getStyle();
}
if (face == null)
{
// The font family does not specify any font face, not even a normal one.
// In such case, we take the family name and consider it as JVM available font name.
checkAwtFont(family.getName(), ignoreMissingFont);
awtFont = new Font(family.getName(), style, size);
}
else
{
awtFont = face.getFont();
if (awtFont == null)
{
throw new JRRuntimeException("The '" + face.getName() + "' font face in family '" + family.getName() + "' returns a null font.");
}
awtFont = awtFont.deriveFont((float)size);
awtFont = awtFont.deriveFont(style & ~faceStyle);
}
}
return awtFont;
}
/**
*
*/
public static void resetThreadMissingFontsCache()
{
threadMissingFontsCache.set(new HashSet());
}
/**
*
*/
public static void checkAwtFont(String name, boolean ignoreMissingFont)
{
if (!JRGraphEnvInitializer.isAwtFontAvailable(name))
{
if (ignoreMissingFont)
{
Set missingFontNames = (Set)threadMissingFontsCache.get();
if (!missingFontNames.contains(name))
{
missingFontNames.add(name);
if (log.isWarnEnabled())
{
log.warn("Font '" + name + "' is not available to the JVM. For more details, see http://jasperreports.sourceforge.net/api/net/sf/jasperreports/engine/util/JRFontNotFoundException.html");
}
}
}
else
{
throw new JRFontNotFoundException(name);
}
}
}
/**
* Returns a java.awt.Font instance by converting a JRFont instance.
* Mostly used in combination with third-party visualization packages such as JFreeChart (for chart themes).
* Unless the font parameter is null, this method always returns a non-null AWT font, regardless whether it was
* found in the font extensions or not. This is because we do need a font to draw with and there is no point
* in raising a font missing exception here, as it is not JasperReports who does the drawing.
*/
public static Font getAwtFont(JRFont font, Locale locale)
{
if (font == null)
{
return null;
}
// ignoring missing font as explained in the Javadoc
Font awtFont =
getAwtFontFromBundles(
font.getFontName(),
((font.isBold()?Font.BOLD:Font.PLAIN)|(font.isItalic()?Font.ITALIC:Font.PLAIN)),
font.getFontSize(),
locale,
true
);
if (awtFont == null)
{
awtFont = new Font(getAttributesWithoutAwtFont(new HashMap(), font));
}
else
{
// add underline and strikethrough attributes since these are set at
// style/font level
Map<Attribute, Object> attributes = new HashMap<Attribute, Object>();
if (font.isUnderline())
{
attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
}
if (font.isStrikeThrough())
{
attributes.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
}
if (!attributes.isEmpty())
{
awtFont = awtFont.deriveFont(attributes);
}
}
return awtFont;
}
private JRFontUtil()
{
}
}