Develop and Download Open Source Software

Browse Subversion Repository

Contents of /dvibrowser-1.2.0/trunk/dvicore/src/main/java/jp/sourceforge/dvibrowser/dvicore/ctx/DefaultDviContext.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 123 - (show annotations) (download) (as text)
Fri Mar 4 13:56:55 2011 UTC (13 years, 1 month ago) by nagaotakeyuki
File MIME type: text/x-java
File size: 15990 byte(s)
Applet support.
1 /*
2 * Copyright (c) 2009, Takeyuki Nagao
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or
6 * without modification, are permitted provided that the
7 * following conditions are met:
8 *
9 * * Redistributions of source code must retain the above
10 * copyright notice, this list of conditions and the
11 * following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the
14 * following disclaimer in the documentation and/or other
15 * materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
18 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
19 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
29 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30 * OF SUCH DAMAGE.
31 */
32
33 package jp.sourceforge.dvibrowser.dvicore.ctx;
34
35 import java.io.File;
36 import java.io.InputStream;
37 import java.net.URL;
38 import java.security.AccessControlException;
39 import java.util.Collection;
40 import java.util.Collections;
41 import java.util.Comparator;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Properties;
45 import java.util.Set;
46 import java.util.TreeMap;
47 import java.util.TreeSet;
48 import java.util.concurrent.ExecutionException;
49 import java.util.concurrent.Future;
50 import java.util.logging.Logger;
51
52 import jp.sourceforge.dvibrowser.dvicore.DviException;
53 import jp.sourceforge.dvibrowser.dvicore.DviFontSpec;
54 import jp.sourceforge.dvibrowser.dvicore.DviPaperSize;
55 import jp.sourceforge.dvibrowser.dvicore.DviResolution;
56 import jp.sourceforge.dvibrowser.dvicore.MetafontMode;
57 import jp.sourceforge.dvibrowser.dvicore.api.CharacterCodeMapper;
58 import jp.sourceforge.dvibrowser.dvicore.api.DevicePainter;
59 import jp.sourceforge.dvibrowser.dvicore.api.DviContext;
60 import jp.sourceforge.dvibrowser.dvicore.api.DviData;
61 import jp.sourceforge.dvibrowser.dvicore.api.DviDocument;
62 import jp.sourceforge.dvibrowser.dvicore.api.DviExecutor;
63 import jp.sourceforge.dvibrowser.dvicore.api.DviExecutorHandler;
64 import jp.sourceforge.dvibrowser.dvicore.api.DviFont;
65 import jp.sourceforge.dvibrowser.dvicore.api.FullMetrics;
66 import jp.sourceforge.dvibrowser.dvicore.api.Glyph;
67 import jp.sourceforge.dvibrowser.dvicore.api.SimpleMetrics;
68 import jp.sourceforge.dvibrowser.dvicore.doc.DirectFileDviDocument;
69 import jp.sourceforge.dvibrowser.dvicore.doc.StreamDviDocument;
70 import jp.sourceforge.dvibrowser.dvicore.doc.URLDviDocument;
71 import jp.sourceforge.dvibrowser.dvicore.font.DviFontResolver;
72 import jp.sourceforge.dvibrowser.dvicore.font.FullMetricsResolver;
73 import jp.sourceforge.dvibrowser.dvicore.font.LogicalFont;
74 import jp.sourceforge.dvibrowser.dvicore.gs.GhostscriptUtils;
75 import jp.sourceforge.dvibrowser.dvicore.render.BasicExecutor;
76 import jp.sourceforge.dvibrowser.dvicore.render.DefaultDevicePainter;
77 import jp.sourceforge.dvibrowser.dvicore.util.DviCache;
78 import jp.sourceforge.dvibrowser.dvicore.util.DviUtils;
79 import jp.sourceforge.dvibrowser.dvicore.util.concurrent.CacheEntry;
80 import jp.sourceforge.dvibrowser.dvicore.util.concurrent.CachedComputer;
81 import jp.sourceforge.dvibrowser.dvicore.util.concurrent.Computation;
82 import jp.sourceforge.dvibrowser.dvicore.util.concurrent.ThreadedComputer;
83 import jp.sourceforge.dvibrowser.dvicore.util.progress.ManagedProgressItem;
84 import jp.sourceforge.dvibrowser.dvicore.util.progress.ProgressRecorder;
85
86
87 public class DefaultDviContext
88 implements DviContext
89 {
90 private static final Logger LOGGER = Logger.getLogger(DefaultDviContext.class.getName());
91
92 private static final String DVICORE_INTERNAL_FILENAME_PREFIX = "dvicore-";
93
94 private final Map<String, Glyph> glyphCache = new DviCache<String, Glyph>(16384);
95 private final CharacterCodeMapper characterCodeMapper
96 = new SimpleJisToUnicodeMapper();
97
98 private boolean recordResources = false;
99 private final Set<URL> resources = new TreeSet<URL>(new Comparator<URL>() {
100 public int compare(URL arg0, URL arg1) {
101 return arg0.toString().compareTo(arg1.toString());
102 }
103 });
104
105 private final ProgressRecorder recorder = new ProgressRecorder(this) {
106 @Override
107 protected boolean removeEldestElement(ManagedProgressItem item)
108 {
109 List<ManagedProgressItem> list = getProgressItems();
110 if (list.size() > 10) {
111 return true;
112 }
113 return false;
114 }
115 };
116
117
118 public DefaultDviContext()
119 throws DviException
120 {
121 this(null);
122 }
123
124 public DefaultDviContext(Properties prop)
125 throws DviException
126 {
127 if (prop == null)
128 prop = getDefaultProperties();
129 this.prop = prop;
130 initializeFontMapper();
131 populatePaperSizes();
132 initializeDirs();
133 }
134
135 protected void initializeDirs()
136 throws DviException
137 {
138 File cacheDir = getCacheDirectory();
139 if (cacheDir != null && !cacheDir.exists()) {
140 if (!cacheDir.mkdirs()) {
141 throw new DviException("Failed to create cache directory: " + cacheDir);
142 }
143 }
144 File tmpDir = getTemporaryDirectory();
145 if (tmpDir != null && !tmpDir.exists()) {
146 if (!tmpDir.mkdirs()) {
147 throw new DviException("Failed to create temporary directory: " + tmpDir);
148 }
149 }
150 }
151
152 protected Properties getDefaultProperties()
153 throws DviException
154 {
155 try {
156 URL url = DefaultDviContext.class.getResource("default-context.properties");
157 Properties prop = new Properties();
158 if (null != url) {
159 prop.load(url.openStream());
160 } else {
161 LOGGER.warning("Failed to load default-context.properties");
162 }
163 return prop;
164 } catch (Exception e) {
165 throw new DviException(e);
166 }
167 }
168
169 private final Properties prop;
170
171 public Properties getProperties()
172 {
173 return prop;
174 }
175
176 public void execute(DviData data, DviExecutorHandler handler)
177 throws DviException
178 {
179 newDviExecutor().execute(data, handler);
180 }
181
182 private static final CachedComputer<String, Collection<DviFont>> dviFontComputer
183 = new CachedComputer<String, Collection<DviFont>>
184 (new ThreadedComputer<String, Collection<DviFont>>(1)) {
185 @Override
186 protected boolean removeEldestEntry(Map.Entry<String, CacheEntry<String, Collection<DviFont>>> entry)
187 {
188 boolean remove = getCache().size() > 64;
189 return remove;
190 }
191 };
192
193 public DviFont findDviFont(LogicalFont logicalFont) throws DviException
194 {
195 Computation<String, Collection<DviFont>> computation
196 = new DviFontResolver(this, logicalFont);
197 try {
198 Collection<DviFont> fonts = dviFontComputer.compute(computation).get();
199 for (DviFont font : fonts) {
200 return font;
201 }
202 return null;
203 } catch (InterruptedException e) {
204 throw new DviException(e);
205 } catch (ExecutionException e) {
206 throw new DviException(e);
207 }
208 }
209
210 public SimpleMetrics findDviSimpleMetrics(DviFontSpec fs) throws DviException
211 {
212 return findDviFullMetrics(fs);
213 }
214
215 private static final CachedComputer<String, Collection<FullMetrics>> fullMetricsComputer
216 = new CachedComputer<String, Collection<FullMetrics>>
217 (new ThreadedComputer<String, Collection<FullMetrics>>(1));
218
219 public FullMetrics findDviFullMetrics(DviFontSpec fs) throws DviException
220 {
221 Computation<String, Collection<FullMetrics>> computation = new FullMetricsResolver(
222 this, fs);
223 try {
224 Collection<FullMetrics> fonts = fullMetricsComputer.compute(computation)
225 .get();
226 if (fonts != null) {
227 for (FullMetrics font : fonts) {
228 return font;
229 }
230 }
231 return null;
232 } catch (InterruptedException e) {
233 throw new DviException(e);
234 } catch (ExecutionException e) {
235 throw new DviException(e);
236 }
237 }
238
239 public CharacterCodeMapper getCharacterCodeMapper(LogicalFont logicalFont) throws DviException
240 {
241 return characterCodeMapper;
242 }
243
244 public DviContext getDviContext() { return this; }
245
246 public Map<String, Glyph> getGlyphCache() throws DviException
247 {
248 return Collections.synchronizedMap(glyphCache);
249 }
250
251 protected void initializeFontMapper()
252 {
253 }
254
255 public DevicePainter newDevicePainter() throws DviException
256 {
257 return new DefaultDevicePainter(this);
258 }
259
260 public DviExecutor newDviExecutor() throws DviException
261 {
262 return new BasicExecutor(this);
263 }
264
265 public DviDocument openDviDocument(File file) throws DviException
266 {
267 return new DirectFileDviDocument(this, file);
268 }
269
270 public DviDocument openDviDocument(InputStream is) throws DviException
271 {
272 return new StreamDviDocument(this, is);
273 }
274
275 // TODO: implement async resource loading
276 public DviDocument openDviDocument(URL url) throws DviException
277 {
278 return new URLDviDocument(this, url);
279 }
280
281 public ProgressRecorder getProgressRecorder()
282 {
283 return recorder;
284 }
285
286 private static final Map<String, DviPaperSize> paperSizes = new TreeMap<String, DviPaperSize>();
287
288 protected void populatePaperSizes()
289 {
290 // ISO 216 sizes
291 // TODO: implement B and C serieses. A4 Japanese, too.
292 // TOOD: outsource the configuration.
293 addPaperSize(new DviPaperSize(841.0, 1189.0, "A0"));
294 addPaperSize(new DviPaperSize(594.0, 841.0, "A1"));
295 addPaperSize(new DviPaperSize(420.0, 594.0, "A2"));
296 addPaperSize(new DviPaperSize(297.0, 420.0, "A3"));
297 addPaperSize(new DviPaperSize(210.0, 297.0, "A4"));
298 addPaperSize(new DviPaperSize(148.0, 210.0, "A5"));
299 addPaperSize(new DviPaperSize(105.0, 148.0, "A6"));
300 addPaperSize(new DviPaperSize(74.0, 105.0, "A7"));
301 addPaperSize(new DviPaperSize(52.0, 74.0, "A8"));
302 addPaperSize(new DviPaperSize(37.0, 52.0, "A9"));
303 addPaperSize(new DviPaperSize(26.0, 37.0, "A10"));
304 }
305
306 protected void addPaperSize(DviPaperSize dviPaperSize)
307 {
308 if (dviPaperSize == null) return;
309 paperSizes.put(dviPaperSize.description().toLowerCase(), dviPaperSize);
310 }
311
312 public DviPaperSize findPaperSizeByName(String name) throws DviException
313 {
314 if (name == null) return null;
315 return paperSizes.get(name.toLowerCase());
316 }
317
318 public DviPaperSize getDefaultPaperSize() throws DviException
319 {
320 return findPaperSizeByName("A4");
321 }
322
323 public DviPaperSize [] listPaperSizes() throws DviException
324 {
325 return paperSizes.values().toArray(new DviPaperSize[0]);
326 }
327
328 private static final DviResolution defaultResolution = new DviResolution(2400, 20);
329 public DviResolution getDefaultResolution() throws DviException
330 {
331 return defaultResolution;
332 }
333
334 private static final CachedComputer<String, Collection<URL>> dviResourceComputer
335 = new CachedComputer<String, Collection<URL>>
336 (new ThreadedComputer<String, Collection<URL>>(1));
337
338 public URL getDviResource(String filename) throws DviException
339 {
340 if (filename.startsWith(DVICORE_INTERNAL_FILENAME_PREFIX)) {
341 // The resource name starting with "dvicore-" are only for internal use.
342 // So there is no local file corresponding to such a filename.
343 // We answer null.
344 return null;
345 }
346
347 Computation<String, Collection<URL>> c
348 = new FileLocationResolver(this, "/dvi/builtin", filename);
349 final Future<Collection<URL>> future = dviResourceComputer.compute(c);
350 try {
351 final Collection<URL> list = future.get();
352 for (URL url : list) {
353 if (recordResources) {
354 LOGGER.info("resolved resource: filename=" + filename + " url=" + url);
355 resources.add(url);
356 } else {
357 LOGGER.finest("resolved resource: filename=" + filename + " url=" + url);
358 }
359 return url;
360 }
361 return null;
362 } catch (InterruptedException e) {
363 LOGGER.warning(e.toString());
364 throw new DviException(e);
365 } catch (ExecutionException e) {
366 LOGGER.warning(e.toString());
367 throw new DviException(e);
368 }
369 }
370
371 public LogicalFont mapLogicalFont(LogicalFont logicalFont)
372 throws DviException
373 {
374 LogicalFont mapped = logicalFont;
375 if (logicalFont != null) {
376 String prefix = getClass().getName();
377 String faceKey = prefix + ".fontMap." + logicalFont.fontSpec().name();
378 LOGGER.info("Face key: " + faceKey);
379 String face = getProperties().getProperty(faceKey);
380 LOGGER.info("Properties: " + getProperties());
381 if (face != null) {
382 mapped = logicalFont.renameTo(face);
383 LOGGER.info("Rename logical font: " + logicalFont + " => " + mapped);
384 }
385 }
386 LOGGER.info("Map logical font: " + logicalFont + " => " + mapped);
387 return mapped;
388 }
389
390 // N.B. System.getProperty() throws an exception when invoked
391 // from inside an applet.
392 private static String getSystemProperty(String key) {
393 try {
394 return System.getProperty(key);
395 } catch (AccessControlException ex) {
396 return null;
397 }
398 }
399
400 private static final String userDir = getSystemProperty("user.dir");
401 private static final String ioTmpDir = getSystemProperty("java.io.tmpdir");
402
403 // TODO: externalize the string "dvibrowser.jar".
404 public File getApplicationHomeDir()
405 throws DviException
406 {
407 if (userDir != null) {
408 File home = new File(userDir);
409 File markFile = new File(home, "dvibrowser.jar");
410 if (markFile.exists()) {
411 // It seems that we are using DviContext from within dvibrowser.
412 return home;
413 }
414 }
415 return null;
416 }
417
418 public File getCacheDirectory() throws DviException
419 {
420 File appHome = getApplicationHomeDir();
421 if (appHome == null) {
422 File tmpDir = getTemporaryDirectory();
423 if (tmpDir != null) {
424 return new File(tmpDir, "cache");
425 }
426 } else {
427 if (userDir != null) {
428 File var = new File(userDir, "var");
429 return new File(var, "cache");
430 }
431 }
432 return null;
433 }
434
435 public File getTemporaryDirectory() throws DviException
436 {
437 File appHome = getApplicationHomeDir();
438 if (appHome == null) {
439 if (ioTmpDir != null) {
440 return new File(ioTmpDir, "dvicontext");
441 }
442 } else {
443 return new File(appHome, "tmp");
444 }
445 return null;
446 }
447
448 private volatile String [] ghostscriptExecutables = null;
449
450 public String getExecutableName(String name) throws DviException
451 {
452 if ("gs".equals(name)) {
453 if (ghostscriptExecutables == null) {
454 // The following code might be called in pararell when we invoke
455 // this method from within multiple threads.
456 // It might be better to use some atomic classes.
457 ghostscriptExecutables = GhostscriptUtils.listGhostscriptExecutables();
458 if (ghostscriptExecutables.length == 0) {
459 LOGGER.warning("You don't seem to have a Ghostscript installed. dvibrowser needs it to render PS, EPS, and PDF.");
460 } else {
461 LOGGER.info("Ghostscript executables found: " + DviUtils.join(" ", ghostscriptExecutables));
462 }
463 }
464 if (ghostscriptExecutables.length > 0) {
465 return ghostscriptExecutables[0];
466 }
467 }
468
469 return name;
470 }
471
472 private final DviToolkit dviToolkit = new DviToolkit(this);
473 public DviToolkit getDviToolkit()
474 {
475 return dviToolkit;
476 }
477
478 private final MetafontMode libraryDefaultMetafontMode = MetafontMode.FALLBACK;
479 public MetafontMode getDefaultMetafontMode() throws DviException {
480 return libraryDefaultMetafontMode;
481 }
482
483 public void setRecordResources(boolean recordResources) {
484 this.recordResources = recordResources;
485 }
486
487 public boolean wantRecordResources() {
488 return recordResources;
489 }
490
491 public Set<URL> getRecordedResources() {
492 return resources;
493 }
494 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26