001: /*
002: * Copyright (c) 2007, intarsys consulting GmbH
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * - Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * - Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * - Neither the name of intarsys nor the names of its contributors may be used
015: * to endorse or promote products derived from this software without specific
016: * prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028: * POSSIBILITY OF SUCH DAMAGE.
029: */
030: package de.intarsys.pdf.font.outlet;
031:
032: import java.util.ArrayList;
033: import java.util.Iterator;
034: import java.util.List;
035: import de.intarsys.font.FontStyle;
036: import de.intarsys.font.afm.AFM;
037: import de.intarsys.font.afm.AFMRegistry;
038: import de.intarsys.font.truetype.TTFont;
039: import de.intarsys.font.truetype.TTRegistry;
040: import de.intarsys.pdf.encoding.Encoding;
041: import de.intarsys.pdf.font.PDFont;
042: import de.intarsys.pdf.font.PDFontTrueType;
043: import de.intarsys.pdf.font.PDFontType1;
044:
045: /**
046: * The standard factory managing and creating fonts.
047: * <p>
048: * This one relies on the building blocks for fonts defined in "de.intarsys.afm"
049: * and "de.intarsys.truetype".
050: * <p>
051: * The factory tries first to resolve the request within the cache of already
052: * loaded fonts. If not found, first Type1 (AFM), then TrueType fonts are looked
053: * up.
054: * <p>
055: * Remember to properly set up the according registries if you want to access
056: * non standard fonts.
057: */
058: public class StandardFontFactory implements IFontFactory {
059: /** The collection of fonts already used within the document */
060: private final List cache;
061:
062: /** flag if new fonts should be embedded */
063: private boolean embedNew = true;
064:
065: protected StandardFontFactory() {
066: super ();
067: this .cache = new ArrayList(10);
068: }
069:
070: public PDFont getBoldFlavor(PDFont font) {
071: PDFont result;
072: FontStyle style = font.getFontStyle().getBoldFlavor();
073: FontQuery template = new FontQuery(font);
074: template.setOverrideFontStyle(style);
075: result = lookupFont(template);
076: if (result == null) {
077: result = loadFont(template);
078: }
079: return (result == null) ? font : result;
080: }
081:
082: public void setEmbedNew(boolean embedNew) {
083: this .embedNew = embedNew;
084: }
085:
086: protected boolean isEmbedNew() {
087: return embedNew;
088: }
089:
090: public PDFont getFont(IFontQuery query) {
091: PDFont result = lookupFont(query);
092: if (result == null) {
093: result = loadFont(query);
094: }
095: return result;
096: }
097:
098: public PDFont getItalicFlavor(PDFont font) {
099: PDFont result = null;
100: FontStyle style = font.getFontStyle().getItalicFlavor();
101: FontQuery template = new FontQuery(font);
102: template.setOverrideFontStyle(style);
103: result = lookupFont(template);
104: if (result == null) {
105: result = loadFont(template);
106: }
107: return (result == null) ? font : result;
108: }
109:
110: public PDFont getRegularFlavor(PDFont font) {
111: PDFont result = null;
112: FontStyle style = FontStyle.REGULAR;
113: FontQuery template = new FontQuery(font);
114: template.setOverrideFontStyle(style);
115: result = lookupFont(template);
116: if (result == null) {
117: result = loadFont(template);
118: }
119: return (result == null) ? font : result;
120: }
121:
122: /**
123: * The collection of already loaded fonts.
124: *
125: * @return The collection of already loaded fonts.
126: */
127: protected List getCache() {
128: return cache;
129: }
130:
131: /**
132: * <code>true</code> when <code>font</code> is considered safe to be
133: * used by others within the document.
134: *
135: * @param font
136: *
137: * @return
138: */
139: protected boolean isReusable(PDFont font) {
140: if (font.isStandardFont()) {
141: return true;
142: }
143: if (font.isSubset()) {
144: return false;
145: }
146:
147: // check if there is some undefined code
148: Encoding encoding = font.getEncoding();
149: for (int i = font.getFirstChar(); i < font.getLastChar(); i++) {
150: if (encoding.getUnicode(i) == -1) {
151: return false;
152: }
153: }
154: return true;
155: }
156:
157: /**
158: * Load a font satisfying the constraints defined in template.
159: *
160: * @param query
161: * The object defining constraints on the result.
162: *
163: * @return a font satisfying the constraints defined in template.
164: */
165: protected PDFont loadFont(IFontQuery query) {
166: PDFont result;
167: result = loadType1Font(query);
168:
169: if (result == null) {
170: result = loadTTFont(query);
171: }
172:
173: if (result != null) {
174: registerFont(result);
175: }
176: return result;
177: }
178:
179: /**
180: * Try to load a TrueType font.
181: *
182: * @param query
183: * The object defining constraints on the result.
184: *
185: * @return a font satisfying the constraints defined in template or null.
186: */
187: protected PDFont loadTTFont(IFontQuery query) {
188: String familyName = query.getFontFamilyName();
189: FontStyle style = query.getFontStyle();
190: PDFontTrueType result = null;
191: TTFont newFont = (TTFont) TTRegistry.get().getFont(familyName,
192: style);
193:
194: if (newFont != null) {
195: result = PDFontTrueType.createNew(newFont);
196: if (!isEmbedNew()) {
197: result.removeFontProgramm();
198: }
199: if (query.getEncoding() != null) {
200: result.setEncoding(query.getEncoding());
201: }
202: }
203:
204: return result;
205: }
206:
207: /**
208: * Try to load a Type1 font.
209: *
210: * @param query
211: * The object defining constraints on the result.
212: *
213: * @return a font satisfying the constraints defined in template or null.
214: */
215: protected PDFont loadType1Font(IFontQuery query) {
216: String familyName = query.getFontFamilyName();
217: FontStyle style = query.getFontStyle();
218: PDFont result = null;
219: AFM afm = (AFM) AFMRegistry.instance().getFont(familyName,
220: style);
221: if (afm != null) {
222: result = PDFontType1.createNew(afm);
223: if (query.getEncoding() != null) {
224: result.setEncoding(query.getEncoding());
225: }
226: }
227: return result;
228: }
229:
230: /**
231: * Lookup a font that is compatible to the template.
232: *
233: * @param query
234: * The template defining properties of the font. A property that
235: * is null is a "wildcard".
236: *
237: * @return A font that satisfies the conditions defined int the template.
238: */
239: protected PDFont lookupFont(IFontQuery query) {
240: for (Iterator it = getCache().iterator(); it.hasNext();) {
241: PDFont font = (PDFont) it.next();
242: if (matches(query, font)) {
243: return font;
244: }
245: }
246: return null;
247: }
248:
249: /**
250: * Answer <code>true</code> if font is "compatible" with query. Compatible
251: * means, that the font returned has at least all of the required features
252: * defined in the query.
253: *
254: * @param font
255: * The font to examine.
256: *
257: * @return Answer <code>true</code> if font is "compatible" with template.
258: */
259: protected boolean matches(IFontQuery query, PDFont font) {
260: if (query.getFontFamilyName() != null) {
261: if (!query.getFontFamilyName().equals(
262: font.getFontFamilyName())) {
263: return false;
264: }
265: }
266: if (query.getFontStyle() != FontStyle.UNDEFINED) {
267: if (font.getFontStyle() != query.getFontStyle()) {
268: return false;
269: }
270: }
271: if (query.getEncoding() != null) {
272: if (font.getEncoding() != query.getEncoding()) {
273: return false;
274: }
275: }
276: return true;
277: }
278:
279: /**
280: * register a font that can be reused in an other context.
281: *
282: * @param font
283: * The PDFont to be registered
284: */
285: protected void registerFont(PDFont font) {
286: getCache().add(font);
287: }
288: }
|