/* * 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() { } }