1 /*
2  * JasperReports - Free Java Reporting Library.
3  * Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
4  * http://www.jaspersoft.com
5  *
6  * Unless you have purchased a commercial license agreement from Jaspersoft,
7  * the following license terms apply:
8  *
9  * This program is part of JasperReports.
10  *
11  * JasperReports is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * JasperReports is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with JasperReports. If not, see <http://www.gnu.org/licenses/>.
23  */

24 package net.sf.jasperreports.engine.fonts;
25
26 import java.awt.Font;
27 import java.awt.FontFormatException;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.lang.ref.ReferenceQueue;
31 import java.lang.ref.WeakReference;
32 import java.nio.file.Files;
33 import java.nio.file.Path;
34 import java.nio.file.StandardCopyOption;
35 import java.util.Map;
36 import java.util.concurrent.ConcurrentHashMap;
37
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40
41 import net.sf.jasperreports.engine.JRException;
42 import net.sf.jasperreports.engine.JasperReportsContext;
43 import net.sf.jasperreports.repo.RepositoryUtil;
44
45 /**
46  * @author Lucian Chirita (lucianc@users.sourceforge.net)
47  */

48 public class AwtFontManager
49 {
50     
51     private static final Log log = LogFactory.getLog(AwtFontManager.class);
52
53     private static final AwtFontManager INSTANCE = new AwtFontManager();
54     
55     public static AwtFontManager instance()
56     {
57         return INSTANCE;
58     }
59     
60     private Map<FontFileReference, Object> fontFileReferences;
61     private ReferenceQueue<Font> fontFilesQueue;
62     
63     public AwtFontManager()
64     {
65         fontFileReferences = new ConcurrentHashMap<>();
66         fontFilesQueue = new ReferenceQueue<>();
67     }
68     
69     public Font getAwtFont(JasperReportsContext jasperReportsContext, String ttfLocation)
70     {
71         purgeFontFiles();
72         
73         InputStream is = null;
74         Path fontFile;
75         try
76         {
77             is = RepositoryUtil.getInstance(jasperReportsContext).getInputStreamFromLocation(ttfLocation);
78             
79             fontFile = Files.createTempFile("jr-font"".ttf");
80             fontFile.toFile().deleteOnExit();
81             
82             if (log.isDebugEnabled())
83             {
84                 log.debug("created font file " + fontFile + for " + ttfLocation);
85             }
86             
87             Files.copy(is, fontFile, StandardCopyOption.REPLACE_EXISTING);
88             
89             Font font = Font.createFont(Font.TRUETYPE_FONT, fontFile.toFile());
90             
91             FontFileReference fontFileReference = new FontFileReference(font, fontFilesQueue, fontFile);
92             fontFileReferences.put(fontFileReference, Boolean.TRUE);
93             
94             return font;
95         }
96         catch (JRException | IOException | FontFormatException e)
97         {
98             throw new InvalidFontException(ttfLocation, e);
99         }
100         finally
101         {
102             try
103             {
104                 if (is != null)
105                 {
106                     is.close();
107                 }
108             }
109             catch (IOException e)
110             {
111             }
112         }
113     }
114     
115     public void purgeFontFiles()
116     {
117         FontFileReference fontFileRef;
118         while ((fontFileRef = (FontFileReference) fontFilesQueue.poll()) != null)
119         {
120             fontFileReferences.remove(fontFileRef);
121             
122             try
123             {
124                 Files.deleteIfExists(fontFileRef.fontFile);
125             }
126             catch (IOException e)
127             {
128                 if (log.isDebugEnabled())
129                 {
130                     log.debug("Failed to delete font file " + fontFileRef.fontFile);
131                 }
132             }
133         }
134     }
135     
136     private static class FontFileReference extends WeakReference<Font>
137     {
138         Path fontFile;
139         
140         FontFileReference(Font font, ReferenceQueue<Font> queue, Path fontFile)
141         {
142             super(font, queue);
143             
144             this.fontFile = fontFile;
145         }
146     }
147     
148 }
149