From bdaace650f445661b79d620c594d28e2fdb94182 Mon Sep 17 00:00:00 2001 From: Takeyuki NAGAO Date: Sun, 25 Mar 2012 23:28:06 +0900 Subject: [PATCH] Initial --- .../dvibrowser/dvi2epub/Dvi2EpubCmd.java | 47 ++ src/jp/sourceforge/dvibrowser/dvi2epub/Test1.java | 44 ++ .../dvibrowser/dvi2epub/cmd/AbstractCommand.java | 53 ++ .../dvibrowser/dvi2epub/cmd/AnnotatedCommand.java | 87 +++ .../dvi2epub/cmd/AnnotatedCommandLine.java | 24 + .../dvi2epub/cmd/AnnotatedCommandLineParser.java | 93 +++ .../dvi2epub/cmd/BooleanValueOption.java | 12 + .../dvibrowser/dvi2epub/cmd/Command.java | 33 + .../dvibrowser/dvi2epub/cmd/CommandException.java | 37 ++ .../dvibrowser/dvi2epub/cmd/CommandLine.java | 5 + .../dvibrowser/dvi2epub/cmd/CommandLineParser.java | 8 + .../dvibrowser/dvi2epub/cmd/CommandUtils.java | 46 ++ .../dvi2epub/cmd/CopyOfOptionAdapter.java | 110 ++++ .../dvi2epub/cmd/DefaultOptionMapper.java | 35 + .../dvibrowser/dvi2epub/cmd/FormatAdapter.java | 110 ++++ .../dvibrowser/dvi2epub/cmd/IntValueOption.java | 12 + .../dvibrowser/dvi2epub/cmd/OptionAdapter.java | 71 ++ .../dvibrowser/dvi2epub/cmd/OptionMapper.java | 5 + .../dvibrowser/dvi2epub/cmd/ParserState.java | 80 +++ .../dvibrowser/dvi2epub/cmd/StringValueOption.java | 28 + .../dvibrowser/dvi2epub/reflect/Dispatcher.java | 76 +++ .../dvibrowser/dvi2epub/reflect/MemberWalker.java | 112 ++++ .../dvi2epub/reflect/MemberWalkerAdapter.java | 61 ++ .../dvi2epub/reflect/MemberWalkerException.java | 52 ++ .../dvi2epub/reflect/MemberWalkerHandler.java | 65 ++ .../dvibrowser/dvicore/DviByteRange.java | 136 ++++ .../sourceforge/dvibrowser/dvicore/DviColor.java | 263 ++++++++ .../dvibrowser/dvicore/DviConstants.java | 57 ++ .../dvibrowser/dvicore/DviException.java | 52 ++ .../dvibrowser/dvicore/DviFontName.java | 122 ++++ .../dvibrowser/dvicore/DviFontSpec.java | 137 ++++ .../dvibrowser/dvicore/DviFontTable.java | 81 +++ .../sourceforge/dvibrowser/dvicore/DviObject.java | 70 ++ .../dvibrowser/dvicore/DviPaperSize.java | 95 +++ .../sourceforge/dvibrowser/dvicore/DviPoint.java | 101 +++ src/jp/sourceforge/dvibrowser/dvicore/DviRect.java | 269 ++++++++ .../dvibrowser/dvicore/DviRectSplitter.java | 88 +++ .../dvibrowser/dvicore/DviRegister.java | 115 ++++ .../dvibrowser/dvicore/DviResolution.java | 87 +++ .../dvibrowser/dvicore/DviSerialized.java | 37 ++ src/jp/sourceforge/dvibrowser/dvicore/DviSize.java | 74 +++ .../dvibrowser/dvicore/DviUniqueId.java | 62 ++ src/jp/sourceforge/dvibrowser/dvicore/DviUnit.java | 148 +++++ .../dvibrowser/dvicore/MetafontMode.java | 73 +++ .../dvibrowser/dvicore/api/BinaryDevice.java | 47 ++ .../dvicore/api/CharacterCodeMapper.java | 41 ++ .../sourceforge/dvibrowser/dvicore/api/Device.java | 55 ++ .../dvibrowser/dvicore/api/DevicePainter.java | 86 +++ .../dvibrowser/dvicore/api/DviCacheable.java | 37 ++ .../dvibrowser/dvicore/api/DviContext.java | 80 +++ .../dvibrowser/dvicore/api/DviContextSupport.java | 37 ++ .../dvibrowser/dvicore/api/DviData.java | 46 ++ .../dvibrowser/dvicore/api/DviDocument.java | 49 ++ .../dvibrowser/dvicore/api/DviExecutor.java | 41 ++ .../dvibrowser/dvicore/api/DviExecutorContext.java | 44 ++ .../dvibrowser/dvicore/api/DviExecutorHandler.java | 79 +++ .../dvibrowser/dvicore/api/DviFont.java | 42 ++ .../dvibrowser/dvicore/api/DviInput.java | 60 ++ .../dvibrowser/dvicore/api/DviPage.java | 44 ++ .../dvibrowser/dvicore/api/FullMetrics.java | 43 ++ .../dvibrowser/dvicore/api/GammaCorrector.java | 39 ++ .../dvibrowser/dvicore/api/Geometer.java | 39 ++ .../dvibrowser/dvicore/api/GeometerContext.java | 42 ++ .../sourceforge/dvibrowser/dvicore/api/Glyph.java | 48 ++ .../sourceforge/dvibrowser/dvicore/api/HasURL.java | 42 ++ .../dvibrowser/dvicore/api/ImageDevice.java | 47 ++ .../dvibrowser/dvicore/api/SimpleMetrics.java | 41 ++ .../dvicore/cli/tools/ConvertToImage.java | 383 +++++++++++ .../sourceforge/dvibrowser/dvicore/cmd/DviBop.java | 105 +++ .../dvibrowser/dvicore/cmd/DviCommand.java | 183 ++++++ .../dvibrowser/dvicore/cmd/DviPostPost.java | 73 +++ .../dvibrowser/dvicore/cmd/DviPostamble.java | 102 +++ .../dvibrowser/dvicore/cmd/DviPreamble.java | 81 +++ .../dvicore/ctx/AbstractDviResourceResolver.java | 94 +++ .../dvibrowser/dvicore/ctx/AsyncComputers.java | 66 ++ .../ctx/BakomaUnicodeCharacterCodeMapper.java | 62 ++ .../dvibrowser/dvicore/ctx/DefaultDviContext.java | 511 +++++++++++++++ .../dvibrowser/dvicore/ctx/DviToolkit.java | 518 +++++++++++++++ .../dvicore/ctx/FileLocationResolver.java | 138 ++++ .../dvibrowser/dvicore/ctx/KpseWhich.java | 297 +++++++++ .../dvicore/ctx/SimpleJisToUnicodeMapper.java | 62 ++ .../ctx/Type1DefaultCharacterCodeMapper.java | 148 +++++ .../dvicore/ctx/UnicodeCharacterCodeMapper.java | 49 ++ .../dvibrowser/dvicore/ctx/cmsy-enc.csv | 1 + .../dvicore/ctx/default-context.properties | 11 + .../sourceforge/dvibrowser/dvicore/ctx/ot1-enc.csv | 1 + .../dvibrowser/dvicore/doc/DefaultDviPage.java | 88 +++ .../dvicore/doc/DirectFileDviDocument.java | 357 +++++++++++ .../dvibrowser/dvicore/doc/StreamDviDocument.java | 263 ++++++++ .../dvibrowser/dvicore/doc/URLDviDocument.java | 142 ++++ .../dvicore/event/TDefaultEventModel.java | 58 ++ .../dvibrowser/dvicore/event/TEvent.java | 18 + .../dvibrowser/dvicore/event/TEventListener.java | 7 + .../dvibrowser/dvicore/event/TEventModel.java | 18 + .../dvicore/event/TEventMulticaster.java | 56 ++ .../dvibrowser/dvicore/event/TEventProcessor.java | 6 + .../dvibrowser/dvicore/event/TEventQueue.java | 16 + .../dvibrowser/dvicore/font/AWTDynamicPkFont.java | 203 ++++++ .../dvicore/font/AWTDynamicPkFontResolver.java | 127 ++++ .../dvicore/font/AbstractDviFontResolver.java | 51 ++ .../dvicore/font/AbstractDynamicPkFont.java | 93 +++ .../dvicore/font/AbstractMetricsResolver.java | 52 ++ .../dvibrowser/dvicore/font/DviFontResolver.java | 199 ++++++ .../dvicore/font/FullMetricsResolver.java | 62 ++ .../dvibrowser/dvicore/font/LogicalFont.java | 104 +++ .../dvibrowser/dvicore/font/LogicalGlyph.java | 69 ++ .../dvicore/font/PackedGlyphRasterizer.java | 149 +++++ .../dvibrowser/dvicore/font/PackedSequence.java | 82 +++ .../dvibrowser/dvicore/font/PkConstants.java | 50 ++ .../dvibrowser/dvicore/font/PkFont.java | 255 ++++++++ .../dvibrowser/dvicore/font/PkFontResolver.java | 63 ++ .../dvibrowser/dvicore/font/PkGlyph.java | 250 ++++++++ .../dvicore/font/RunLengthEncodedGlyph.java | 544 ++++++++++++++++ .../dvicore/font/RunLengthEncodedLine.java | 400 ++++++++++++ .../dvibrowser/dvicore/font/SequencePacker.java | 240 +++++++ .../dvibrowser/dvicore/font/TexFontMetrics.java | 320 +++++++++ .../dvicore/font/TrueTypeFontResolver.java | 95 +++ .../dvibrowser/dvicore/font/Type1FontResolver.java | 84 +++ .../dvibrowser/dvicore/font/VirtualFont.java | 322 ++++++++++ .../dvicore/font/VirtualFontResolver.java | 63 ++ .../dvicore/gs/GhostscriptBBOXParser.java | 104 +++ .../dvicore/gs/GhostscriptCommandBuilder.java | 198 ++++++ .../dvibrowser/dvicore/gs/GhostscriptUtils.java | 241 +++++++ .../dvicore/gui/swing/DefaultDviLayoutManager.java | 209 ++++++ .../dvibrowser/dvicore/gui/swing/DragToScroll.java | 172 +++++ .../dvicore/gui/swing/DviLayoutManager.java | 53 ++ .../dvibrowser/dvicore/gui/swing/TDviDocument.java | 230 +++++++ .../dvibrowser/dvicore/gui/swing/TDviPage.java | 327 ++++++++++ .../dvibrowser/dvicore/gui/swing/TScrollPane.java | 68 ++ .../dvibrowser/dvicore/gui/swing/TexLogViewer.java | 123 ++++ .../dvibrowser/dvicore/gui/swing/ViewSpec.java | 254 ++++++++ .../dvicore/image/pnm/AbstractPnmAsciiFilter.java | 110 ++++ .../dvicore/image/pnm/AbstractPnmSplitter.java | 194 ++++++ .../dvibrowser/dvicore/image/pnm/PbmSplitter.java | 73 +++ .../dvibrowser/dvicore/image/pnm/PgmSplitter.java | 95 +++ .../dvicore/image/pnm/PnmBitAsciiFilter.java | 73 +++ .../dvicore/image/pnm/PnmByteAsciiFilter.java | 72 +++ .../dvibrowser/dvicore/image/pnm/PnmHeader.java | 241 +++++++ .../dvibrowser/dvicore/image/pnm/PnmSplitter.java | 118 ++++ .../dvibrowser/dvicore/image/pnm/PpmSplitter.java | 95 +++ .../dvicore/image/split/AbstractSplitPiece.java | 83 +++ .../image/split/DefaultSplitImageWriter.java | 158 +++++ .../dvibrowser/dvicore/image/split/DviImage.java | 133 ++++ .../dvicore/image/split/FileImagePiece.java | 81 +++ .../dvicore/image/split/ImageFileConfig.java | 74 +++ .../dvicore/image/split/ImageSplitter.java | 45 ++ .../dvibrowser/dvicore/image/split/SplitImage.java | 49 ++ .../dvicore/image/split/SplitImageUtils.java | 69 ++ .../dvicore/image/split/SplitImageWriter.java | 45 ++ .../dvibrowser/dvicore/image/split/SplitPiece.java | 50 ++ .../dvicore/image/split/URLImagePiece.java | 73 +++ .../dvicore/image/split/ZipImagePiece.java | 97 +++ .../dvicore/image/split/ZipSplitImageReader.java | 165 +++++ .../dvicore/image/split/ZipSplitImageWriter.java | 310 +++++++++ .../dvibrowser/dvicore/io/ByteArrayDviData.java | 111 ++++ .../dvibrowser/dvicore/io/DviByteBufferInput.java | 185 ++++++ .../dvicore/io/DviInputStreamReader.java | 196 ++++++ .../dvicore/io/DviRandomAccessFileInput.java | 192 ++++++ .../dvicore/plat/cygwin/CygwinUtils.java | 86 +++ .../dvibrowser/dvicore/render/AbstractDevice.java | 106 +++ .../dvibrowser/dvicore/render/BasicExecutor.java | 713 +++++++++++++++++++++ .../dvibrowser/dvicore/render/BasicGeometer.java | 224 +++++++ .../dvibrowser/dvicore/render/BinaryImage.java | 189 ++++++ .../dvicore/render/BoundingBoxComputer.java | 95 +++ .../dvibrowser/dvicore/render/ByteRGBImage.java | 197 ++++++ .../dvicore/render/ByteRangeComputer.java | 118 ++++ .../dvicore/render/DefaultDevicePainter.java | 399 ++++++++++++ .../dvicore/render/DefaultGammaCorrector.java | 94 +++ .../dvicore/render/DumpBinaryDevice.java | 97 +++ .../dvibrowser/dvicore/render/DumpHandler.java | 156 +++++ .../dvicore/render/DviBoundingBoxPreparator.java | 78 +++ .../dvicore/render/DviExecutorFilter.java | 216 +++++++ .../dvicore/render/DviPagePreparator.java | 96 +++ .../dvicore/render/EmptyBinaryDevice.java | 60 ++ .../dvicore/render/EmptyDevicePainter.java | 58 ++ .../dvicore/render/EmptyDviExecutorHandler.java | 81 +++ .../dvicore/render/GammaCorrectorCache.java | 116 ++++ .../dvibrowser/dvicore/render/IntRGBImage.java | 177 +++++ .../dvicore/render/RunLengthSampler.java | 267 ++++++++ .../dvibrowser/dvicore/render/StopHandler.java | 134 ++++ .../dvicore/render/VirtualFontGeometer.java | 89 +++ .../special/AbstractDviSpecialExecutor.java | 70 ++ .../dvibrowser/dvicore/special/Anchor.java | 102 +++ .../dvibrowser/dvicore/special/AnchorSet.java | 39 ++ .../dvibrowser/dvicore/special/ByteRangeSet.java | 69 ++ .../dvicore/special/EPS2ImagePreparator.java | 189 ++++++ .../dvicore/special/EPS2SplitImagePreparator.java | 168 +++++ .../dvicore/special/EmbeddedPostScript.java | 351 ++++++++++ .../special/EmbeddedPostScriptPreparator.java | 118 ++++ .../dvicore/special/HtmlSpecialParser.java | 161 +++++ .../dvicore/special/PostScriptSpecialParser.java | 231 +++++++ .../dvicore/special/SourceSpecialParser.java | 152 +++++ .../dvibrowser/dvicore/util/Benchmark.java | 140 ++++ .../dvibrowser/dvicore/util/BufferFilter.java | 155 +++++ .../dvibrowser/dvicore/util/Canonicalizer.java | 38 ++ .../dvibrowser/dvicore/util/CommandShell.java | 305 +++++++++ .../dvicore/util/CommandShellHandler.java | 45 ++ .../dvicore/util/DaemonThreadFactory.java | 58 ++ .../dvicore/util/DefaultCommandShellHandler.java | 66 ++ .../dvicore/util/DumpCommandShellHandler.java | 73 +++ .../dvibrowser/dvicore/util/DviCache.java | 72 +++ .../dvibrowser/dvicore/util/DviDesktop.java | 109 ++++ .../dvibrowser/dvicore/util/DviInfoDumper.java | 189 ++++++ .../dvibrowser/dvicore/util/DviUtils.java | 557 ++++++++++++++++ .../dvibrowser/dvicore/util/LineBuffer.java | 94 +++ .../dvicore/util/SimpleCanonicalizer.java | 57 ++ .../dvibrowser/dvicore/util/TeXMessageParser.java | 227 +++++++ .../dvibrowser/dvicore/util/ZipBuilder.java | 181 ++++++ .../dvicore/util/concurrent/AbstractComputer.java | 51 ++ .../dvicore/util/concurrent/BasicComputer.java | 56 ++ .../dvicore/util/concurrent/CacheEntry.java | 83 +++ .../dvicore/util/concurrent/Cacheable.java | 37 ++ .../dvicore/util/concurrent/CachedComputer.java | 143 +++++ .../dvicore/util/concurrent/Computation.java | 39 ++ .../dvicore/util/concurrent/Computer.java | 38 ++ .../util/concurrent/ComputerProgressMonitor.java | 85 +++ .../dvicore/util/concurrent/ThreadedComputer.java | 79 +++ .../dvibrowser/dvicore/util/csv/CsvCellCodec.java | 40 ++ .../dvibrowser/dvicore/util/csv/CsvData.java | 304 +++++++++ .../dvibrowser/dvicore/util/csv/CsvException.java | 52 ++ .../dvibrowser/dvicore/util/csv/CsvLineParser.java | 160 +++++ .../dvibrowser/dvicore/util/csv/CsvParser.java | 89 +++ .../dvicore/util/csv/StringCsvCellCodec.java | 52 ++ .../dvibrowser/dvicore/util/csv/StringCsvData.java | 46 ++ .../util/progress/AbstractProgressModel.java | 103 +++ .../dvicore/util/progress/ManagedProgressItem.java | 147 +++++ .../dvicore/util/progress/ProgressBlock.java | 78 +++ .../dvicore/util/progress/ProgressEvent.java | 61 ++ .../dvicore/util/progress/ProgressItem.java | 44 ++ .../dvicore/util/progress/ProgressListener.java | 43 ++ .../dvicore/util/progress/ProgressLogger.java | 82 +++ .../dvicore/util/progress/ProgressMessage.java | 72 +++ .../dvicore/util/progress/ProgressRecorder.java | 148 +++++ .../dvicore/util/progress/ProgressReporter.java | 127 ++++ 234 files changed, 27580 insertions(+) create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/Dvi2EpubCmd.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/Test1.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/AbstractCommand.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/AnnotatedCommand.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/AnnotatedCommandLine.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/AnnotatedCommandLineParser.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/BooleanValueOption.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/Command.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CommandException.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CommandLine.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CommandLineParser.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CommandUtils.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CopyOfOptionAdapter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/DefaultOptionMapper.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/FormatAdapter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/IntValueOption.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/OptionAdapter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/OptionMapper.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/ParserState.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/cmd/StringValueOption.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/reflect/Dispatcher.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/reflect/MemberWalker.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/reflect/MemberWalkerAdapter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/reflect/MemberWalkerException.java create mode 100644 src/jp/sourceforge/dvibrowser/dvi2epub/reflect/MemberWalkerHandler.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviByteRange.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviColor.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviConstants.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviException.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviFontName.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviFontSpec.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviFontTable.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviObject.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviPaperSize.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviPoint.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviRect.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviRectSplitter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviRegister.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviResolution.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviSerialized.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviSize.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviUniqueId.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/DviUnit.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/MetafontMode.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/BinaryDevice.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/CharacterCodeMapper.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/Device.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/DevicePainter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/DviCacheable.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/DviContext.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/DviContextSupport.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/DviData.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/DviDocument.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/DviExecutor.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/DviExecutorContext.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/DviExecutorHandler.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/DviFont.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/DviInput.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/DviPage.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/FullMetrics.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/GammaCorrector.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/Geometer.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/GeometerContext.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/Glyph.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/HasURL.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/ImageDevice.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/api/SimpleMetrics.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/cli/tools/ConvertToImage.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/cmd/DviBop.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/cmd/DviCommand.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/cmd/DviPostPost.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/cmd/DviPostamble.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/cmd/DviPreamble.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/ctx/AbstractDviResourceResolver.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/ctx/AsyncComputers.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/ctx/BakomaUnicodeCharacterCodeMapper.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/ctx/DefaultDviContext.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/ctx/DviToolkit.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/ctx/FileLocationResolver.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/ctx/KpseWhich.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/ctx/SimpleJisToUnicodeMapper.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/ctx/Type1DefaultCharacterCodeMapper.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/ctx/UnicodeCharacterCodeMapper.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/ctx/cmsy-enc.csv create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/ctx/default-context.properties create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/ctx/ot1-enc.csv create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/doc/DefaultDviPage.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/doc/DirectFileDviDocument.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/doc/StreamDviDocument.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/doc/URLDviDocument.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/event/TDefaultEventModel.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/event/TEvent.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/event/TEventListener.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/event/TEventModel.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/event/TEventMulticaster.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/event/TEventProcessor.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/event/TEventQueue.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/AWTDynamicPkFont.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/AWTDynamicPkFontResolver.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/AbstractDviFontResolver.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/AbstractDynamicPkFont.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/AbstractMetricsResolver.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/DviFontResolver.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/FullMetricsResolver.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/LogicalFont.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/LogicalGlyph.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/PackedGlyphRasterizer.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/PackedSequence.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/PkConstants.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/PkFont.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/PkFontResolver.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/PkGlyph.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/RunLengthEncodedGlyph.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/RunLengthEncodedLine.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/SequencePacker.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/TexFontMetrics.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/TrueTypeFontResolver.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/Type1FontResolver.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/VirtualFont.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/font/VirtualFontResolver.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/gs/GhostscriptBBOXParser.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/gs/GhostscriptCommandBuilder.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/gs/GhostscriptUtils.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/gui/swing/DefaultDviLayoutManager.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/gui/swing/DragToScroll.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/gui/swing/DviLayoutManager.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/gui/swing/TDviDocument.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/gui/swing/TDviPage.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/gui/swing/TScrollPane.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/gui/swing/TexLogViewer.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/gui/swing/ViewSpec.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/pnm/AbstractPnmAsciiFilter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/pnm/AbstractPnmSplitter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PbmSplitter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PgmSplitter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PnmBitAsciiFilter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PnmByteAsciiFilter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PnmHeader.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PnmSplitter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PpmSplitter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/split/AbstractSplitPiece.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/split/DefaultSplitImageWriter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/split/DviImage.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/split/FileImagePiece.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/split/ImageFileConfig.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/split/ImageSplitter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/split/SplitImage.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/split/SplitImageUtils.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/split/SplitImageWriter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/split/SplitPiece.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/split/URLImagePiece.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/split/ZipImagePiece.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/split/ZipSplitImageReader.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/image/split/ZipSplitImageWriter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/io/ByteArrayDviData.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/io/DviByteBufferInput.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/io/DviInputStreamReader.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/io/DviRandomAccessFileInput.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/plat/cygwin/CygwinUtils.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/AbstractDevice.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/BasicExecutor.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/BasicGeometer.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/BinaryImage.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/BoundingBoxComputer.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/ByteRGBImage.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/ByteRangeComputer.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/DefaultDevicePainter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/DefaultGammaCorrector.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/DumpBinaryDevice.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/DumpHandler.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/DviBoundingBoxPreparator.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/DviExecutorFilter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/DviPagePreparator.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/EmptyBinaryDevice.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/EmptyDevicePainter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/EmptyDviExecutorHandler.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/GammaCorrectorCache.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/IntRGBImage.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/RunLengthSampler.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/StopHandler.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/render/VirtualFontGeometer.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/special/AbstractDviSpecialExecutor.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/special/Anchor.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/special/AnchorSet.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/special/ByteRangeSet.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/special/EPS2ImagePreparator.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/special/EPS2SplitImagePreparator.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/special/EmbeddedPostScript.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/special/EmbeddedPostScriptPreparator.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/special/HtmlSpecialParser.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/special/PostScriptSpecialParser.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/special/SourceSpecialParser.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/Benchmark.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/BufferFilter.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/Canonicalizer.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/CommandShell.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/CommandShellHandler.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/DaemonThreadFactory.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/DefaultCommandShellHandler.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/DumpCommandShellHandler.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/DviCache.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/DviDesktop.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/DviInfoDumper.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/DviUtils.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/LineBuffer.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/SimpleCanonicalizer.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/TeXMessageParser.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/ZipBuilder.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/AbstractComputer.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/BasicComputer.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/CacheEntry.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/Cacheable.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/CachedComputer.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/Computation.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/Computer.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/ComputerProgressMonitor.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/ThreadedComputer.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvCellCodec.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvData.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvException.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvLineParser.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvParser.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/csv/StringCsvCellCodec.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/csv/StringCsvData.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/progress/AbstractProgressModel.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/progress/ManagedProgressItem.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressBlock.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressEvent.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressItem.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressListener.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressLogger.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressMessage.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressRecorder.java create mode 100644 src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressReporter.java diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/Dvi2EpubCmd.java b/src/jp/sourceforge/dvibrowser/dvi2epub/Dvi2EpubCmd.java new file mode 100644 index 0000000..ac6b212 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/Dvi2EpubCmd.java @@ -0,0 +1,47 @@ +package jp.sourceforge.dvibrowser.dvi2epub; + +import java.util.Arrays; + +import jp.sourceforge.dvibrowser.dvi2epub.cmd.AnnotatedCommand; +import jp.sourceforge.dvibrowser.dvi2epub.cmd.BooleanValueOption; +import jp.sourceforge.dvibrowser.dvi2epub.cmd.Command; +import jp.sourceforge.dvibrowser.dvi2epub.cmd.CommandException; +import jp.sourceforge.dvibrowser.dvi2epub.cmd.CommandUtils; +import jp.sourceforge.dvibrowser.dvi2epub.cmd.IntValueOption; +import jp.sourceforge.dvibrowser.dvi2epub.cmd.StringValueOption; + +public class Dvi2EpubCmd extends AnnotatedCommand { + + @Override + protected int processCommandLine() throws CommandException { + System.out.println("Arguments: " + Arrays.toString(getArgs())); + return Command.EXIT_SUCCESS; + } + + @BooleanValueOption(description = "test", longName = "debug", shortName = "d") + public void wantDebug(boolean want) + { + System.out.println("test"); + } + + @StringValueOption(description = "test2", longName = "debug2", shortName = "x", value = Command.NULL) + public void setParam1(String s) + { + System.out.println("test2: " + s); + } + + @IntValueOption(description = "test3", longName = "debug3", shortName = "i", value = 3) + public void setParam2(int s) + { + System.out.println("test3: " + s); + } + + @Override + public boolean wantExit() { + return false; + } + + public static void main(String[] args) throws CommandException { + CommandUtils.executeCommand(Dvi2EpubCmd.class, args); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/Test1.java b/src/jp/sourceforge/dvibrowser/dvi2epub/Test1.java new file mode 100644 index 0000000..08d00d6 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/Test1.java @@ -0,0 +1,44 @@ +package jp.sourceforge.dvibrowser.dvi2epub; + +import jp.sourceforge.dvibrowser.dvi2epub.reflect.Dispatcher; +import jp.sourceforge.dvibrowser.dvi2epub.reflect.MemberWalkerException; + +public class Test1 { + public void test(String data) + { + System.out.println("String data: " + data); + } + + public void test(Object o) + { + System.out.println("Object data: " + o); + } + + public static void main(String[] args) throws MemberWalkerException { + Test1 test1 = new Test1(); + Object o = "hoge"; + String s = "foo"; + System.out.println("Class: " + o.getClass()); + test1.test(o); + test1.test(s); + + { + Dispatcher dispatcher = new Dispatcher(test1, "test", o); + if (dispatcher.dispatch()) { + System.out.println("Output = " + dispatcher.getResult()); + } else { + System.out.println("Invocation failure."); + } + } + + { + Dispatcher dispatcher = new Dispatcher(test1, "test", 123); + if (dispatcher.dispatch()) { + System.out.println("Output = " + dispatcher.getResult()); + } else { + System.out.println("Invocation failure."); + } + } + + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/AbstractCommand.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/AbstractCommand.java new file mode 100644 index 0000000..bfc5806 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/AbstractCommand.java @@ -0,0 +1,53 @@ +/* + * Copyright 2012 Take-Yuki NAGAO + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +import java.io.PrintWriter; + +public abstract class AbstractCommand implements Command { + private PrintWriter writer = new PrintWriter(System.out, true); + + public AbstractCommand() { + } + + public abstract int execute(String[] args) throws CommandException; + + public void showUsage() throws CommandException { + showUsage(getWriter()); + } + + public void showUsage(PrintWriter out) throws CommandException { + out.println(getApplicationName() + " " + getCommandLineSyntax()); + out.flush(); + } + + public String getCommandLineSyntax() throws CommandException { + return "[options]"; + } + + public String getApplicationName() throws CommandException { + return getClass().getName(); + } + + public void setWriter(PrintWriter writer) { + this.writer = writer; + } + + public PrintWriter getWriter() { + return writer; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/AnnotatedCommand.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/AnnotatedCommand.java new file mode 100644 index 0000000..df78d0f --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/AnnotatedCommand.java @@ -0,0 +1,87 @@ +/* + * Copyright 2012 Take-Yuki NAGAO + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +import java.io.PrintWriter; + +public abstract class AnnotatedCommand extends AbstractCommand { + private CommandLineParser parser; + private boolean wantHelp; + private String[] args; + + public AnnotatedCommand() { + parser = new AnnotatedCommandLineParser(this); + } + + @BooleanValueOption(shortName = "h", longName = "help", description = "Show help") + public void wantHelp(boolean want) { + this.wantHelp = want; + } + + public boolean wantHelp() { + return wantHelp; + } + + @Override + public int execute(String[] args) throws CommandException { + try { + parser.parse(args); + int ret = doProcessCommandLine(); + return ret; + } finally { + PrintWriter out = getWriter(); + if (out != null) { + out.flush(); + } + } + } + + protected int doProcessCommandLine() + throws CommandException { + if (wantHelp()) { + showUsage(); + return Command.EXIT_SUCCESS; + } else { + return processCommandLine(); + } + } + + protected abstract int processCommandLine() throws CommandException; + + @Override + public void showUsage(PrintWriter pw) throws CommandException { + parser.printHelp(pw); + pw.flush(); + } + + @Override + public String getApplicationName() throws CommandException { + return getClass().getName(); + } + + public String[] getArgs() { + return args; + } + + public void setArgs(String[] args) { + this.args = args; + } + + protected OptionMapper createOptionMapper(ParserState state) { + return new DefaultOptionMapper(state); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/AnnotatedCommandLine.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/AnnotatedCommandLine.java new file mode 100644 index 0000000..2060cba --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/AnnotatedCommandLine.java @@ -0,0 +1,24 @@ +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +public class AnnotatedCommandLine implements CommandLine { + private final String[] args; + private final AnnotatedCommand command; + + public AnnotatedCommandLine(AnnotatedCommand command, String[] args) { + this.command = command; + this.args = args; + } + + @Override + public boolean hasOption(String name) { + return false; + } + + public String[] getArgs() { + return args; + } + + public AnnotatedCommand getCommand() { + return command; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/AnnotatedCommandLineParser.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/AnnotatedCommandLineParser.java new file mode 100644 index 0000000..ef285b9 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/AnnotatedCommandLineParser.java @@ -0,0 +1,93 @@ +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +import java.io.PrintWriter; + +import jp.sourceforge.dvibrowser.dvi2epub.reflect.MemberWalker; +import jp.sourceforge.dvibrowser.dvi2epub.reflect.MemberWalkerException; + +public class AnnotatedCommandLineParser implements CommandLineParser { + private final AnnotatedCommand command; + + public AnnotatedCommandLineParser(AnnotatedCommand cmd) { + this.command = cmd; + } + + @Override + public CommandLine parse(String[] args) throws CommandException { + CommandLine commandLine = new AnnotatedCommandLine(command, args); + ParserState state = new ParserState(args); + while (!state.wantStop()) { + String arg1 = state.shift(); +// System.out.println("arg1=" + arg1); + if (arg1 == null) { + state.wantStop(true); + } else if (arg1.startsWith("--")) { + // Long parameter + parseLongOption(state, arg1); + } else if ("-".equals(arg1)) { + state.wantStop(true); + } else if (arg1.startsWith("-")) { + // Short parameter + parseShortOption(state, arg1); + } else { + // No parameter + state.unshift(arg1); + state.wantStop(true); + } + } + + if (state.hasError()) { + throw new CommandException(state.getThrowable()); + } + + command.setArgs(state.getList().toArray(new String [0])); + + return commandLine; + } + + private void parseShortOption(final ParserState state, final String arg1) throws CommandException { + char c = arg1.charAt(1); + String arguments = null; + if (arg1.length() > 2) { + arguments = arg1.substring(2); + } + doParseOption(state, "" + c, arguments); + } + + private void parseLongOption(final ParserState state, final String arg1) throws CommandException { + String name = arg1.substring(2); + String arguments = null; + int pos = name.indexOf('='); + if (-1 != pos) { + arguments = name.substring(pos + 1); + name = name.substring(0, pos); + } + + doParseOption(state, name, arguments); + } + + private void doParseOption(final ParserState state, final String name, final String parameter) throws CommandException + { + state.setOptionName(name); + state.setOptionParameter(parameter); + OptionMapper mapper = command.createOptionMapper(state); + + MemberWalker walker = new MemberWalker(new OptionAdapter(state, mapper)); + try { + walker.walk(command); + } catch (MemberWalkerException e) { + throw new CommandException(e); + } + } + + public AnnotatedCommand getCommand() { + return command; + } + + @Override + public void printHelp(PrintWriter pw) throws CommandException { + // pw may not be null. + pw.println("Usage: " + command.getApplicationName() + " " + command.getCommandLineSyntax()); + pw.flush(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/BooleanValueOption.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/BooleanValueOption.java new file mode 100644 index 0000000..b5d195c --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/BooleanValueOption.java @@ -0,0 +1,12 @@ +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface BooleanValueOption { + String shortName(); + String longName(); + String description(); + boolean value() default true; +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/Command.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/Command.java new file mode 100644 index 0000000..3bf402a --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/Command.java @@ -0,0 +1,33 @@ +/* + * Copyright 2012 Take-Yuki NAGAO + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +public interface Command { + public static final int EXIT_SUCCESS = 0; + public static final int EXIT_ERROR = 1; + public static final String NULL = "-NULL-"; + + int execute(String[] args) throws CommandException; + + boolean wantExit(); + + void showUsage() throws CommandException; + + String getApplicationName() throws CommandException; + + String getCommandLineSyntax() throws CommandException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CommandException.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CommandException.java new file mode 100644 index 0000000..e8b1036 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CommandException.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012 Take-Yuki NAGAO + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +public class CommandException extends Exception { + private static final long serialVersionUID = 9105846149523606971L; + + public CommandException() { + } + + public CommandException(String arg0) { + super(arg0); + } + + public CommandException(Throwable arg0) { + super(arg0); + } + + public CommandException(String arg0, Throwable arg1) { + super(arg0, arg1); + } + +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CommandLine.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CommandLine.java new file mode 100644 index 0000000..049146b --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CommandLine.java @@ -0,0 +1,5 @@ +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +public interface CommandLine { + boolean hasOption(String name); +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CommandLineParser.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CommandLineParser.java new file mode 100644 index 0000000..ca01862 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CommandLineParser.java @@ -0,0 +1,8 @@ +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +import java.io.PrintWriter; + +public interface CommandLineParser { + CommandLine parse(String [] args) throws CommandException; + void printHelp(PrintWriter pw) throws CommandException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CommandUtils.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CommandUtils.java new file mode 100644 index 0000000..2cfefc5 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CommandUtils.java @@ -0,0 +1,46 @@ +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +public class CommandUtils { + private CommandUtils() {} + + public static int executeCommand(Class cls, String[] args) + throws CommandException { + try { + if (Command.class.isAssignableFrom(cls)) { + Command cmd = (Command) cls.newInstance(); + int ret = cmd.execute(args); + if (cmd.wantExit()) { + System.exit(ret); + } + return ret; + } else { + run(cls.getName(), args); + return Command.EXIT_SUCCESS; + } + } catch (Exception e) { + throw new CommandException(e); + } + } + + public static void run(String classname, String[] args) throws Exception { + Class cls = Class.forName(classname); + cls.getMethod("main", new Class[] { String[].class }) + .invoke(null, new Object[] { args }); + } + + public static boolean parseBoolean(String arg, boolean value) { + if (arg == null) return value; + arg = arg.toLowerCase().trim(); + if (arg.equals("true") || arg.equals("yes")) { + return true; + } + return false; + } + + public static T unescapeNull(T value) + { + if (value instanceof String && Command.NULL.equals(value)) + return null; + return value; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CopyOfOptionAdapter.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CopyOfOptionAdapter.java new file mode 100644 index 0000000..6fecd2f --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/CopyOfOptionAdapter.java @@ -0,0 +1,110 @@ +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import jp.sourceforge.dvibrowser.dvi2epub.reflect.MemberWalkerAdapter; +import jp.sourceforge.dvibrowser.dvi2epub.reflect.MemberWalkerException; + +final class CopyOfOptionAdapter extends MemberWalkerAdapter { + private final String name; + private final String arguments; + private boolean done; + private final ParserState state; + private List> classes; + private String targetMethod; + + CopyOfOptionAdapter(ParserState state, String name, String arguments) { + this.name = name; + this.arguments = arguments; + this.state = state; + targetMethod = "buildArgs"; + classes = new ArrayList>(); + for (Method mm : this.getClass().getDeclaredMethods()) { + if (mm.getName().equals(targetMethod)) { + Class[] clss = mm.getParameterTypes(); + if (clss.length > 0) { + Class cc = clss[0]; + if (cc.isAnnotation()) { + classes.add(cc); + } + } + } + } + } + + public boolean wantMember(Object o, Member member) { + return !done; + } + + public void setDone(boolean value) { + done = value; + } + + public boolean isDone() { + return done; + } + + public void processMethod(Object o, Method method) + throws MemberWalkerException { + Annotation[] annotations = method.getDeclaredAnnotations(); + try { + for (Annotation a : annotations) { + for (Class cls : classes) { + if (a.annotationType().equals(cls)) { + // System.out.println("cls=" + cls); + Method methodS = cls.getDeclaredMethod("shortName", + new Class[] {}); + Method methodL = cls.getDeclaredMethod("longName", + new Class[] {}); + String shortName = (String) methodS.invoke(a); + String longName = (String) methodL.invoke(a); + if (nameHits(name, shortName, longName)) { + // System.out.println("shortName=" + shortName + + // " longName=" + longName); + Method m = this.getClass().getDeclaredMethod( + "buildArgs", new Class[] { cls }); + Object[] args = (Object[]) m.invoke(this, + new Object[] { a }); + method.invoke(o, args); + setDone(true); + } + } + } + } + } catch (Exception ex) { + ex.printStackTrace(); + state.stopWithError(ex); + return; + } + } + + private boolean nameHits(String name, String shortName, String longName) { + if (shortName != null && shortName.equals(name)) { + return true; + } else if (longName != null && longName.equals(name)) { + return true; + } + return false; + } + + protected Object[] buildArgs(IntValueOption p) { + String a = (arguments == null) ? state.shift() : arguments; + int value = (a == null) ? p.value() : Integer.parseInt(a); + return new Object[] { value }; + } + + protected Object[] buildArgs(StringValueOption p) { + String value = CommandUtils.unescapeNull((CommandUtils + .unescapeNull(arguments) == null) ? p.value() : arguments); + return new Object[] { value }; + } + + protected Object[] buildArgs(BooleanValueOption p) { + boolean value = CommandUtils.parseBoolean(arguments, p.value()); + return new Object[] { value }; + } +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/DefaultOptionMapper.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/DefaultOptionMapper.java new file mode 100644 index 0000000..19fda9c --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/DefaultOptionMapper.java @@ -0,0 +1,35 @@ +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +public class DefaultOptionMapper +implements OptionMapper +{ + private final ParserState state; + + public DefaultOptionMapper(ParserState state) { + this.state = state; + } + + public Object[] map(IntValueOption p) { + String param = getState().getOptionParameter(); + String a = (param == null) ? getState().shift() : param; + int value = (a == null) ? p.value() : Integer.parseInt(a); + return new Object[] { value }; + } + + public Object[] map(StringValueOption p) { + String param = getState().getOptionParameter(); + String value = CommandUtils.unescapeNull((CommandUtils + .unescapeNull(param) == null) ? p.value() : param); + return new Object[] { value }; + } + + public Object[] map(BooleanValueOption p) { + String param = getState().getOptionParameter(); + boolean value = CommandUtils.parseBoolean(param, p.value()); + return new Object[] { value }; + } + + public ParserState getState() { + return state; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/FormatAdapter.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/FormatAdapter.java new file mode 100644 index 0000000..ea42794 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/FormatAdapter.java @@ -0,0 +1,110 @@ +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import jp.sourceforge.dvibrowser.dvi2epub.reflect.MemberWalkerAdapter; +import jp.sourceforge.dvibrowser.dvi2epub.reflect.MemberWalkerException; + +final class FormatAdapter extends MemberWalkerAdapter { + private final String name; + private final String arguments; + private boolean done; + private final ParserState state; + private List> classes; + private String targetMethod; + + FormatAdapter(ParserState state, String name, String arguments) { + this.name = name; + this.arguments = arguments; + this.state = state; + targetMethod = "buildArgs"; + classes = new ArrayList>(); + for (Method mm : this.getClass().getDeclaredMethods()) { + if (mm.getName().equals(targetMethod)) { + Class[] clss = mm.getParameterTypes(); + if (clss.length > 0) { + Class cc = clss[0]; + if (cc.isAnnotation()) { + classes.add(cc); + } + } + } + } + } + + public boolean wantMember(Object o, Member member) { + return !done; + } + + public void setDone(boolean value) { + done = value; + } + + public boolean isDone() { + return done; + } + + public void processMethod(Object o, Method method) + throws MemberWalkerException { + Annotation[] annotations = method.getDeclaredAnnotations(); + try { + for (Annotation a : annotations) { + for (Class cls : classes) { + if (a.annotationType().equals(cls)) { + // System.out.println("cls=" + cls); + Method methodS = cls.getDeclaredMethod("shortName", + new Class[] {}); + Method methodL = cls.getDeclaredMethod("longName", + new Class[] {}); + String shortName = (String) methodS.invoke(a); + String longName = (String) methodL.invoke(a); + if (nameHits(name, shortName, longName)) { + // System.out.println("shortName=" + shortName + + // " longName=" + longName); + Method m = this.getClass().getDeclaredMethod( + "buildArgs", new Class[] { cls }); + Object[] args = (Object[]) m.invoke(this, + new Object[] { a }); + method.invoke(o, args); + setDone(true); + } + } + } + } + } catch (Exception ex) { + ex.printStackTrace(); + state.stopWithError(ex); + return; + } + } + + private boolean nameHits(String name, String shortName, String longName) { + if (shortName != null && shortName.equals(name)) { + return true; + } else if (longName != null && longName.equals(name)) { + return true; + } + return false; + } + + protected Object[] buildArgs(IntValueOption p) { + String a = (arguments == null) ? state.shift() : arguments; + int value = (a == null) ? p.value() : Integer.parseInt(a); + return new Object[] { value }; + } + + protected Object[] buildArgs(StringValueOption p) { + String value = CommandUtils.unescapeNull((CommandUtils + .unescapeNull(arguments) == null) ? p.value() : arguments); + return new Object[] { value }; + } + + protected Object[] buildArgs(BooleanValueOption p) { + boolean value = CommandUtils.parseBoolean(arguments, p.value()); + return new Object[] { value }; + } +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/IntValueOption.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/IntValueOption.java new file mode 100644 index 0000000..3e92101 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/IntValueOption.java @@ -0,0 +1,12 @@ +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface IntValueOption { + String shortName(); + String longName(); + String description(); + int value() default 0; +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/OptionAdapter.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/OptionAdapter.java new file mode 100644 index 0000000..97e383e --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/OptionAdapter.java @@ -0,0 +1,71 @@ +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import jp.sourceforge.dvibrowser.dvi2epub.reflect.Dispatcher; +import jp.sourceforge.dvibrowser.dvi2epub.reflect.MemberWalkerAdapter; +import jp.sourceforge.dvibrowser.dvi2epub.reflect.MemberWalkerException; + +final class OptionAdapter extends MemberWalkerAdapter { + private final ParserState state; + private final OptionMapper mapper; + + OptionAdapter(ParserState state, OptionMapper mapper) { + this.state = state; + this.mapper = mapper; + } + + public void processMethod(Object o, Method method) + throws MemberWalkerException { + Annotation[] annotations = method.getDeclaredAnnotations(); + try { + for (Annotation a : annotations) { + String shortName = null, longName = null; + + try { + Method m = a.getClass().getDeclaredMethod("shortName", + new Class[] {}); + shortName = (String) m.invoke(a); + } catch (NoSuchMethodException ex) { + // Ignored. + } + try { + Method m = a.getClass().getDeclaredMethod("longName", + new Class[] {}); + longName = (String) m.invoke(a); + } catch (NoSuchMethodException ex) { + // Ignored. + } + + if (nameHits(state.getOptionName(), shortName, longName)) { + Dispatcher d = new Dispatcher(getMapper(), "map", a); + if (d.dispatch()) { + Object [] args = d.getResult(); +// System.out.println("Dispatch result: " + Arrays.toString(args)); + method.invoke(o, args); + setDone(true); + } + } + } + } catch (Exception ex) { +// ex.printStackTrace(); + state.stopWithError(ex); + return; + } + } + + public OptionMapper getMapper() + { + return mapper; + } + + private boolean nameHits(String name, String shortName, String longName) { + if (shortName != null && shortName.equals(name)) { + return true; + } else if (longName != null && longName.equals(name)) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/OptionMapper.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/OptionMapper.java new file mode 100644 index 0000000..bafa228 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/OptionMapper.java @@ -0,0 +1,5 @@ +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +public interface OptionMapper { + ParserState getState(); +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/ParserState.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/ParserState.java new file mode 100644 index 0000000..cb77993 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/ParserState.java @@ -0,0 +1,80 @@ +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ParserState { + private final String[] args; + private List list = new ArrayList(); + private Throwable throwable; + private boolean stop = false; + private String optionName; + private String optionParameter; + + public ParserState(String [] args) { + this.args = args; + this.list.addAll(Arrays.asList(args)); + } + + public String[] getOriginalArgs() { + return args; + } + + public List getList() { + return list; + } + + public String shift() { + String ret = null; + if (list.size() > 0) { + ret = list.remove(0); + } + return ret; + } + + public void unshift(String value) { + list.add(0, value); + } + + public boolean wantStop() { + return stop; + } + + public void wantStop(boolean stop) { + this.stop = stop; + } + + public void setError(Throwable ex) { + this.throwable = ex; + } + + public void stopWithError(Throwable ex) { + setError(ex); + wantStop(true); + } + + public Throwable getThrowable() { + return this.throwable; + } + + public boolean hasError() { + return getThrowable() != null; + } + + public String getOptionParameter() { + return optionParameter; + } + + public void setOptionParameter(String optionParameter) { + this.optionParameter = optionParameter; + } + + public String getOptionName() { + return optionName; + } + + public void setOptionName(String optionName) { + this.optionName = optionName; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/StringValueOption.java b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/StringValueOption.java new file mode 100644 index 0000000..98eafee --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/cmd/StringValueOption.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012 Take-Yuki NAGAO + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jp.sourceforge.dvibrowser.dvi2epub.cmd; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface StringValueOption { + String shortName(); + String longName(); + String description(); + String value(); +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/reflect/Dispatcher.java b/src/jp/sourceforge/dvibrowser/dvi2epub/reflect/Dispatcher.java new file mode 100644 index 0000000..c2ccb85 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/reflect/Dispatcher.java @@ -0,0 +1,76 @@ +package jp.sourceforge.dvibrowser.dvi2epub.reflect; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + + +public class Dispatcher +extends MemberWalkerAdapter +{ + private final String methodName; + private final Object[] args; + private final Object mapper; + private T result; + private boolean success; + + public Dispatcher(Object mapper, String methodName, Object ... args) throws IllegalArgumentException + { + this.mapper = mapper; + this.methodName = methodName; + this.args = args; + if (args.length < 1) + throw new IllegalArgumentException("Too few arguments to invoke()."); + } + + public void processMethod(Object target, Method method) throws MemberWalkerException { + try { + if (method.getName().equals(getMethodName())) { + Class[] clss = method.getParameterTypes(); + if (clss.length > 0) { + Class cc = clss[0]; + if (cc.isAssignableFrom(args[0].getClass())) { + Object ret = method.invoke(target, getArgs()); + result = (T) ret; + setDone(true); + success = true; + } + } + } + } catch (SecurityException e) { + throw new MemberWalkerException(e); + } catch (IllegalArgumentException e) { + throw new MemberWalkerException(e); + } catch (IllegalAccessException e) { + throw new MemberWalkerException(e); + } catch (InvocationTargetException e) { + throw new MemberWalkerException(e); + } + } + + public boolean dispatch() throws MemberWalkerException + { + MemberWalker walker = new MemberWalker(this); + walker.walk(mapper); + return success; + } + + public String getMethodName() { + return methodName; + } + + public Object[] getArgs() { + return args; + } + + public Object getMapper() { + return mapper; + } + + public T getResult() { + return result; + } + + protected void setResult(T result) { + this.result = result; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/reflect/MemberWalker.java b/src/jp/sourceforge/dvibrowser/dvi2epub/reflect/MemberWalker.java new file mode 100644 index 0000000..c2fa6b2 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/reflect/MemberWalker.java @@ -0,0 +1,112 @@ +/* +The MIT License + +Copyright (c) 2010 Takeyuki Nagao + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ + +package jp.sourceforge.dvibrowser.dvi2epub.reflect; + +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; + +/** + *

+ * Žw’èƒIƒuƒWƒFƒNƒg‚Ì‚·‚ׂẴƒ“ƒoiƒtƒB[ƒ‹ƒh‹y‚уƒ\ƒbƒhj‚ð„‰ñ‚µ‚āC ŒÂX‚̃ƒ“ƒo‚ɑ΂µ‚Ä“Á’è‚̏ˆ—‚ðs‚¤‚½‚߂̃Nƒ‰ƒXD ‹ï‘Ì“I‚ȏˆ—‚Ì“à—e‚Í + * {@link MemberWalkerHandler} ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ÌŽÀ‘•ƒNƒ‰ƒX‚É‹Lq‚µ‚āCƒRƒ“ƒXƒgƒ‰ƒNƒ^ˆø”‚Å‚»‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ðŽw’è‚·‚éD + *

+ *

+ * —˜—p—á‚ð‹“‚°‚éD

+    MyBean bean = new MyBean(); // ƒ†[ƒU’è‹`ƒNƒ‰ƒX
+    bean.setField1("hogehoge");
+    bean.setField2(314);
+    
+    MemberWalker walker = new MemberWalker(new MemberWalkerAdapter() {
+      public void processField(Object o, Field field)
+      {
+        System.out.println("ƒtƒB[ƒ‹ƒh: " + field.getName());
+      }
+    });
+    walker.walk(bean);
+ * 
+ *

+ * + * @author nagaotakeyuki@gmail.com + */ + +public class MemberWalker { + private final MemberWalkerHandler handler; + + /** + *

+ * Žw’肳‚ꂽƒnƒ“ƒhƒ‰‚ðŽ‚Á‚½ƒCƒ“ƒXƒ^ƒ“ƒX‚𐶐¬‚·‚éD + *

+ * + * @param handler + * ƒƒ“ƒo‚ðŒ©‚Â‚¯‚½‚Æ‚«‚ɌĂяo‚³‚ê‚éƒnƒ“ƒhƒ‰ + */ + public MemberWalker(MemberWalkerHandler handler) { + this.handler = handler; + if (handler == null) { + throw new NullPointerException("Handler can't be null."); + } + } + + protected boolean wantMember(Object t, Member member) + throws MemberWalkerException { + return handler.wantMember(t, member); + } + + /** + * Žw’肳‚ꂽƒIƒuƒWƒFƒNƒg‚Ì‚·‚ׂẴƒ“ƒoiƒtƒB[ƒ‹ƒh‚ƃƒ\ƒbƒhj‚ɑ΂µ‚ănƒ“ƒhƒ‰‚ðŒÄ‚яo‚·D public + * ‚Å‚È‚¢ƒƒ“ƒo‚àˆ—‚̑ΏۂƂȂéD + * + * @param t + * ‘ΏۂƂȂéƒIƒuƒWƒFƒNƒg + * @throws MemberWalkerException + */ + public void walk(Object t) throws MemberWalkerException { + if (t == null) + throw new NullPointerException("Cannot walk about null object."); + + if (t.getClass().isPrimitive()) + return; + + // Class#getFields() ‚Å‚Í public ƒtƒB[ƒ‹ƒh‚µ‚©ŽQÆ‚Å‚«‚È‚¢‚Ì‚Å + // ƒNƒ‰ƒX‚ÌŠK‘w‚ð Object ƒNƒ‰ƒX‚Ü‚Å‚½‚Ç‚Á‚ătƒB[ƒ‹ƒh‚̃Gƒ“ƒR[ƒhˆ—‚ðs‚¤D + for (Class cls = t.getClass();; cls = cls.getSuperclass()) { + for (Method method : cls.getDeclaredMethods()) { + if (!wantMember(t, method)) + continue; + method.setAccessible(true); // public ˆÈŠO‚̃ƒ\ƒbƒh‚É‚àƒAƒNƒZƒXo—ˆ‚é‚悤‚É‚·‚éD + handler.processMethod(t, method); + } + for (Field field : cls.getDeclaredFields()) { + if (!wantMember(t, field)) + continue; + field.setAccessible(true); // public ˆÈŠO‚̃tƒB[ƒ‹ƒh‚É‚àƒAƒNƒZƒXo—ˆ‚é‚悤‚É‚·‚éD + handler.processField(t, field); + } + if (cls == Object.class) + break; + } + } +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/reflect/MemberWalkerAdapter.java b/src/jp/sourceforge/dvibrowser/dvi2epub/reflect/MemberWalkerAdapter.java new file mode 100644 index 0000000..a746f24 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/reflect/MemberWalkerAdapter.java @@ -0,0 +1,61 @@ +/* +The MIT License + +Copyright (c) 2010 Takeyuki Nagao + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +package jp.sourceforge.dvibrowser.dvi2epub.reflect; + +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * {@link MemberWalkerHandler} ‚Ì‚½‚߂̃Aƒ_ƒvƒ^ƒNƒ‰ƒXD + * @author nagaotakeyuki@gmail.com + * + */ + +public class MemberWalkerAdapter implements MemberWalkerHandler +{ + private boolean done; + + public boolean wantMember(Object o, Member member) + throws MemberWalkerException + { + int modifiers = member.getModifiers(); + int modifiersToIgnore = Modifier.TRANSIENT; + return ((modifiers & modifiersToIgnore) == 0) && !done; + } + + public void setDone(boolean value) { + done = value; + } + + public boolean isDone() { + return done; + } + + public void processField(Object t, Field field) throws MemberWalkerException {} + + public void processMethod(Object t, Method method) throws MemberWalkerException {} +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/reflect/MemberWalkerException.java b/src/jp/sourceforge/dvibrowser/dvi2epub/reflect/MemberWalkerException.java new file mode 100644 index 0000000..b0364af --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/reflect/MemberWalkerException.java @@ -0,0 +1,52 @@ +/* +The MIT License + +Copyright (c) 2010 Takeyuki Nagao + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +package jp.sourceforge.dvibrowser.dvi2epub.reflect; + +/** + * {@link MemberWalkerHandler} ƒCƒ“ƒ^[ƒtƒFƒCƒX‚Å—áŠO‚ðƒ‰ƒbƒv‚·‚邽‚ß‚Ì—áŠOƒNƒ‰ƒXD + * @author nagaotakeyuki@gmail.com + * + */ +public class MemberWalkerException +extends Exception +{ + private static final long serialVersionUID = 7427816842687879124L; + + public MemberWalkerException() { + super(); + } + + public MemberWalkerException(String message, Throwable cause) { + super(message, cause); + } + + public MemberWalkerException(String message) { + super(message); + } + + public MemberWalkerException(Throwable cause) { + super(cause); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvi2epub/reflect/MemberWalkerHandler.java b/src/jp/sourceforge/dvibrowser/dvi2epub/reflect/MemberWalkerHandler.java new file mode 100644 index 0000000..9e2a953 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvi2epub/reflect/MemberWalkerHandler.java @@ -0,0 +1,65 @@ +/* +The MIT License + +Copyright (c) 2010 Takeyuki Nagao + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +package jp.sourceforge.dvibrowser.dvi2epub.reflect; + +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; + +/** + * {@link MemberWalker} ƒNƒ‰ƒX‚ªŒÂX‚̃ƒ“ƒo‚ɑ΂µ‚čs‚¤ + * ˆ—“à—e‚ð‹Lq‚·‚邽‚߂̃Cƒ“ƒ^[ƒtƒFƒCƒXD + * + * @author nagaotakeyuki@gmail.com + * + */ +public interface MemberWalkerHandler { + /** + * “Á’è‚̃ƒ“ƒo‚ð {@link #processField(Object, Field)} ‹y‚Ñ {@link #processMethod(Object, Method)} + * ‚̌Ăяo‚µ‘ΏۂƂ·‚é‚©‚Ç‚¤‚©‚ðŒˆ’è‚·‚郁ƒ\ƒbƒh + * @param t ‘ΏۃIƒuƒWƒFƒNƒg + * @param member ‘ΏۃIƒuƒWƒFƒNƒg‚̃ƒ“ƒoiƒtƒB[ƒ‹ƒh‚à‚µ‚­‚̓ƒ\ƒbƒhj + * @return member ‚ÅŽw’肳‚ꂽƒƒ“ƒo‚ðŒÄ‚яo‚µ‘ΏۂƂ·‚éê‡‚É trueD + * ‚»‚êˆÈŠO‚Í false + * @throws MemberWalkerException + */ + boolean wantMember(Object t, Member member) throws MemberWalkerException; + + /** + * ƒtƒB[ƒ‹ƒh‚ªŒ©‚‚©‚Á‚½ê‡‚ɌĂяo‚³‚ê‚郁ƒ\ƒbƒhD + * @param t ‘ΏۃIƒuƒWƒFƒNƒg + * @param field Œ©‚‚©‚Á‚½ƒtƒB[ƒ‹ƒh + * @throws MemberWalkerException + */ + void processField(Object t, Field field) throws MemberWalkerException; + + /** + * ƒƒ\ƒbƒh‚ªŒ©‚‚©‚Á‚½ê‡‚ɌĂяo‚³‚ê‚郁ƒ\ƒbƒhD + * @param t ‘ΏۃIƒuƒWƒFƒNƒg + * @param method Œ©‚‚©‚Á‚½ƒƒ\ƒbƒh + * @throws MemberWalkerException + */ + void processMethod(Object t, Method method) throws MemberWalkerException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/DviByteRange.java b/src/jp/sourceforge/dvibrowser/dvicore/DviByteRange.java new file mode 100644 index 0000000..9ad4ef8 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/DviByteRange.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore; + +/** + * An immutable class to represent a range of bytes. + * @author Takeyuki Nagao + * + */ + +public class DviByteRange +{ + public static final DviByteRange EMPTY = new DviByteRange(); + + private final long begin; + private final long end; + + private DviByteRange() + { + begin = 0; + end = -1; + } + + public DviByteRange(long begin, long end) + { + if (begin <= end) { + this.begin = begin; + this.end = end; + } else { + this.begin = end; + this.end = begin; + } + } + + public long begin() + { + return begin; + } + + public long end() + { + return end; + } + + public DviByteRange translate(long by) + { + return new DviByteRange(begin + by, end + by); + } + + public DviByteRange intersect(DviByteRange a) + { + if (a == null) return this; + if (this.isEmpty()) return EMPTY; + if (a.isEmpty()) return EMPTY; + long b = Math.max(this.begin, a.begin); + long e = Math.min(this.end, a.end); + return (b > e) ? EMPTY : new DviByteRange(b, e); + } + + public DviByteRange union(DviByteRange a) + { + if (a == null) return this; + if (this.isEmpty()) return a; + if (a.isEmpty()) return this; + return new DviByteRange( + Math.min(this.begin, a.begin), + Math.max(this.end, a.end) + ); + } + + public boolean isEmpty() + { + return this == EMPTY; + } + + public long length() + { + return end - begin + 1; + } + + public boolean contains(long point) + { + return (begin <= point && point <= end); + } + + public boolean intersects(DviByteRange a) + { + if (a == null) return false; + return !this.intersect(a).isEmpty(); + } + + public String toString() { + return "" + begin + "--" + end; + } + public int hashCode() { + return (int)(begin + 33*end); + } + + public boolean equals(Object obj) { + if (obj instanceof DviByteRange) { + DviByteRange br = (DviByteRange) obj; + return br.begin == begin && br.end == end; + } + return false; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/DviColor.java b/src/jp/sourceforge/dvibrowser/dvicore/DviColor.java new file mode 100644 index 0000000..e156690 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/DviColor.java @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore; + +import java.awt.Color; +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +// immutable. + +public final class DviColor +implements java.io.Serializable +{ + private static final long serialVersionUID = 5615669030601265281L; + + public static final DviColor INVALID = new DviColor(); + + private final int r, g, b; + private final int intRGB; + private final boolean valid; + + public int getRed() { return r;} + public int getGreen() { return g;} + public int getBlue() { return b;} + + public Color toColor() + { + return new Color(r, g, b); + } + + public DviColor() { + r = g = b = intRGB = 0; + valid = false; + } + + public DviColor(int rgb) + { + this( + (rgb >>> 16) & 0xff, + (rgb >>> 8) & 0xff, + rgb & 0xff + ); + } + + public DviColor(int r, int g, int b) + { + if (0 <= r && r < 256 && 0 <= g && g < 256 && 0 <= b && b < 256) { + this.r = r; + this.g = g; + this.b = b; + intRGB = (r << 16) | (g << 8) | b; + valid = true; + } else { + throw new IllegalArgumentException + ("r=" + r + " g=" + g + " b=" + b); + } + } + + public boolean isValid() + { + return valid; + } + + public static DviColor fromIntRGB(int v) + { + final int r, g, b; + + b = v & 0xff; v >>>= 8; + g = v & 0xff; v >>>= 8; + r = v & 0xff; + + return RGB(r, g, b); + } + + public static DviColor RGB(int r, int g, int b) + { + return new DviColor(r, g, b); + } + + public static DviColor RGB(double r, double g, double b) + { + return RGB( + (int)(r * 255 + 0.5), + (int)(g * 255 + 0.5), + (int)(b * 255 + 0.5) + ); + } + + public static DviColor HSV(int h, int s, int v) + { + if (s == 0) { + return RGB(v, v, v); + } + + h = ((h % 360) + 360) % 360; // h = h mod 360 + final double f = h % 60; + + final int p = (int)((v*(255.0 - s) + 255.0/2.0) / 255.0); + final int q = (int)((v*(60.0*255.0 - f * s) + 60.0*255.0 / 2.0) / (60.0 * 255.0)); + final int t = (int)((v*(60.0*255.0 - (60.0 - f) * s) + 60.0*255.0 / 2.0) / (60.0 * 255.0)); + + int r, g, b; + + switch (h / 60) { + case 0: r=v; g=t; b=p; break; + case 1: r=q; g=v; b=p; break; + case 2: r=p; g=v; b=t; break; + case 3: r=p; g=q; b=v; break; + case 4: r=t; g=p; b=v; break; + case 5: r=v; g=p; b=q; break; + default: throw new InternalError(); + } + return RGB(r, g, b); + } + + public static DviColor CMYK(double c, double m, double y, double k) + { + return RGB( + Math.max(0.0, 1.0 - c - k), + Math.max(0.0, 1.0 - m - k), + Math.max(0.0, 1.0 - y - k) + ); + } + + public int toIntRGB() + { + return intRGB; + } + + private static final Pattern rgbPat + = Pattern.compile( + "rgb\\s+([.0-9]+)\\s+([.0-9]+)\\s+([.0-9]+)", + Pattern.CASE_INSENSITIVE + ); + private static final Pattern hsbPat + = Pattern.compile( + "hsb\\s+([.0-9]+)\\s+([.0-9]+)\\s+([.0-9]+)", + Pattern.CASE_INSENSITIVE + ); + private static final Pattern cmykPat + = Pattern.compile( + "cmyk\\s+([.0-9]+)\\s+([.0-9]+)\\s+([.0-9]+)\\s+([.0-9]+)", + Pattern.CASE_INSENSITIVE + ); + private static final Pattern grayPat + = Pattern.compile( + "gray\\s+([.0-9]+)", + Pattern.CASE_INSENSITIVE + ); + + private static final HashMap aliases + = new HashMap(); + + static { + aliases.put( "black", fromIntRGB(0x00000000)); + aliases.put( "blue", fromIntRGB(0x000000ff)); + aliases.put( "green", fromIntRGB(0x0000ff00)); + aliases.put( "cyan", fromIntRGB(0x0000ffff)); + aliases.put( "red", fromIntRGB(0x00ff0000)); + aliases.put("magenta", fromIntRGB(0x00ff00ff)); + aliases.put( "yellow", fromIntRGB(0x00ffff00)); + aliases.put( "white", fromIntRGB(0x00ffffff)); + // TODO: support colors used by dvips. + } + + public static DviColor parseColor(String str) + throws DviException + { + str = str.trim(); + Matcher mat; + + try { + if ((mat = rgbPat.matcher(str)).matches()) { + double r = Double.parseDouble(mat.group(1)); + double g = Double.parseDouble(mat.group(2)); + double b = Double.parseDouble(mat.group(3)); + return RGB(r, g, b); + } else if ((mat = hsbPat.matcher(str)).matches()) { + double h = Double.parseDouble(mat.group(1)); + double s = Double.parseDouble(mat.group(2)); + double b = Double.parseDouble(mat.group(3)); + return HSV( + (int)(h*359 + 0.5), + (int)(s*255 + 0.5), + (int)(b*255 + 0.5) + ); + } else if ((mat = cmykPat.matcher(str)).matches()) { + double c = Double.parseDouble(mat.group(1)); + double m = Double.parseDouble(mat.group(2)); + double y = Double.parseDouble(mat.group(3)); + double k = Double.parseDouble(mat.group(3)); + return CMYK(c, m, y, k); + } else if ((mat = grayPat.matcher(str)).matches()) { + double v = Double.parseDouble(mat.group(1)); + return RGB(v, v, v); + } else { + DviColor c = aliases.get(str.toLowerCase()); + if (c != null) return c; + throw new DviException + ("unrecognized color specification: " + str); + } + } catch(NumberFormatException ex) { + throw new DviException(ex); + } + } + + public int hashCode() + { + return r + 33*(g + 33*b); + } + + public boolean equals(Object obj) + { + if (obj instanceof DviColor) { + DviColor c = (DviColor) obj; + return (r == c.r && g == c.g && b == c.b); + } + return false; + } + + public String toString() + { + return getClass().getName() + "[hex=#" + + toHex(r) + toHex(g) + toHex(b) + "]"; + } + + private static String toHex(int a) + { + return (a < 0x10) ? "0" + Integer.toHexString(a) + : Integer.toHexString(a); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/DviConstants.java b/src/jp/sourceforge/dvibrowser/dvicore/DviConstants.java new file mode 100644 index 0000000..181e93d --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/DviConstants.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore; + +public final class DviConstants +{ + private DviConstants() {} // disable instantiation + + public static final int VF_ID_BYTE = 202; + public static final int VF_SHORT_CHAR = 0; + public static final int VF_LONG_CHAR = 242; + + public static final int TFM_ID_YOKOGUMI = 11; + public static final int TFM_ID_TATEGUMI = 9; + + public static final int DVI_ID_BYTE = 2; + public static final int DVI_ID_BYTE_TATEGUMI = 3; + public static final int DVI_TRAILER = 223; + + public static final double MM_PER_INCH = 25.4; + public static final double POINT_PER_INCH = 72.27; + public static final int DEFAULT_NUM = 25400000; + public static final int DEFAULT_DEN = 7227 * 65536; + public static final int DEFAULT_MAG = 1000; + + public static final int UNDEFINED_FONT_NUMBER = -1; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/DviException.java b/src/jp/sourceforge/dvibrowser/dvicore/DviException.java new file mode 100644 index 0000000..6cb3310 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/DviException.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore; + +public class DviException +extends java.lang.Exception +{ + private static final long serialVersionUID = 2904774705739419493L; + + public DviException() { + super(); + } + public DviException(String msg) { + super(msg); + } + public DviException(String msg, Throwable cause) { + super(msg, cause); + } + public DviException(Throwable cause) { + super(cause); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/DviFontName.java b/src/jp/sourceforge/dvibrowser/dvicore/DviFontName.java new file mode 100644 index 0000000..1038bf0 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/DviFontName.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore; + +import java.io.Serializable; + +import jp.sourceforge.dvibrowser.dvicore.util.Canonicalizer; +import jp.sourceforge.dvibrowser.dvicore.util.SimpleCanonicalizer; + + +// immutable. + +public final class DviFontName +implements Serializable +{ + private static final long serialVersionUID = 5473736840728986859L; + private final int al, nl; + private final String name; + private final int hash; + + private DviFontName(int al, int nl, String name) + { + if (name == null) + throw new NullPointerException + ("name can't be null"); + if (al < 0 || 255 < al) + throw new IllegalArgumentException + ("illegal value of area length: " + al); + if (nl < 0 || 255 < nl) + throw new IllegalArgumentException + ("illegal value of name length: " + nl); + if (name.length() != (al + nl)) + throw new IllegalArgumentException + ("name size mismatch:" + + " name.length()=" + name.length() + + " al=" + al + + " nl=" + nl + ); + + this.al = al; + this.nl = nl; + this.name = name; + this.hash = al + 33*(nl + 33*name.hashCode()); + } + + public int areaLength() { return al; } + public int nameLength() { return nl; } + public String name() { return name; } + + private static final Canonicalizer canonicalizer + = new SimpleCanonicalizer(); + + public static DviFontName getInstance(int al, int nl, String name) + { + return canonicalizer.canonicalize( + new DviFontName(al, nl, name) + ); + } + public static DviFontName getInstance(int nl, String name) + { + return getInstance(0, nl, name); + } + public static DviFontName getInstance(String name) + { + return getInstance(0, name.length(), name); + } + + private volatile String string = null; + public String toString() { + if (string == null) { + string = getClass().getName() + + "[al=" + al + + ",nl=" + nl + + ",name=" + name + + "]"; + } + return string; + } + + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj instanceof DviFontName) { + DviFontName fn = (DviFontName) obj; + return name.equals(fn.name) && al == fn.al && nl == fn.nl; + } + return false; + } + + public int hashCode() { + return hash; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/DviFontSpec.java b/src/jp/sourceforge/dvibrowser/dvicore/DviFontSpec.java new file mode 100644 index 0000000..f08c56a --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/DviFontSpec.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore; + +import jp.sourceforge.dvibrowser.dvicore.util.Canonicalizer; +import jp.sourceforge.dvibrowser.dvicore.util.SimpleCanonicalizer; + +// immutable. + +public final class DviFontSpec +implements java.io.Serializable +{ + private static final long serialVersionUID = 2374998771511821276L; + private final int cs; // check sum. + private final int ss; // Space size. + private final int ds; // Design size. + private final DviFontName fontName; + + private final double dviPerTfmw; + private final int hash; // QUESTION: Should we make this transient? + + private DviFontSpec(int cs, int ss, int ds, DviFontName fontName) { + this.cs = cs; + this.ss = ss; + this.ds = ds; + this.fontName = fontName; + this.hash = ( + cs + 33*(ss + 33*(ds + 33*fontName.hashCode())) + ); + dviPerTfmw = ss / (double) (1 << 20); + } + + private static final Canonicalizer canonicalizer + = new SimpleCanonicalizer(); + public static DviFontSpec getInstance( + int cs, int ss, int ds, DviFontName fontName) + { + return canonicalizer.canonicalize( + new DviFontSpec(cs, ss, ds, fontName) + ); + } + + public static DviFontSpec getInstance( + int cs, int ss, int ds, int al, int nl, byte [] name) + { + return getInstance(cs, ss, ds, + DviFontName.getInstance(al, nl, new String(name)) + ); + } + + public static DviFontSpec getInstance( + int cs, int ss, int ds, int al, int nl, String name) + { + return getInstance(cs, ss, ds, + DviFontName.getInstance(al, nl, name) + ); + } + + public int checkSum() { return cs; } + public int spaceSize() { return ss; } + public int designSize() { return ds; } + public int areaLength() { return fontName.areaLength(); } + public int nameLength() { return fontName.nameLength(); } + public DviFontName fontName() { return fontName; } + public String name() { return fontName.name(); } + + public int tfmToDvi(int tfmw) { + return (int)(dviPerTfmw * tfmw); + } + + private volatile String string = null; + public String toString() { + if (string == null) { + string = "FontSpec" + + "[cs=" + cs + ",ss=" + ss + ",ds=" + ds + + ",fontName=\"" + fontName + "\"]" + ; + } + return string; + } + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj instanceof DviFontSpec) { + DviFontSpec fs = (DviFontSpec) obj; + return (isCompatibleWith(fs) && (cs == fs.cs)); + } + return false; + } + public boolean isCompatibleWith(DviFontSpec fs) { + return ( + (fs != null) + && (ss == fs.ss) && (ds == fs.ds) + && fontName.equals(fs.fontName) + ); + } + + public int hashCode() { + return hash; + } + + public DviFontSpec rename(String newName) + { + return getInstance(cs, ss, ds, + DviFontName.getInstance(newName) + ); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/DviFontTable.java b/src/jp/sourceforge/dvibrowser/dvicore/DviFontTable.java new file mode 100644 index 0000000..60defb2 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/DviFontTable.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore; + +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; + +public class DviFontTable +extends ConcurrentHashMap +{ + private static final long serialVersionUID = -5082474565659155765L; + + public DviFontTable() { + super(); + } + + public DviFontTable transformForVirtualFont(DviFontSpec parent, int vfDesignSize) + { + DviFontTable ft = new DviFontTable(); + + for (int fn : keySet()) { + DviFontSpec fs = get(fn); + ft.put( + fn, + DviFontSpec.getInstance( + fs.checkSum(), + (int)( + parent.spaceSize() * (double) fs.spaceSize() + / (double)(1 << 20) + ), + (int)( + parent.designSize() * (double) fs.designSize() + / (double) vfDesignSize + ), + fs.fontName() + ) + ); + } + + return ft; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + for (int fn : new TreeSet(keySet())) { + DviFontSpec fs = (DviFontSpec) get(fn); + sb.append("fn[" + fn + "]=" + ((fs != null) ? fs.toString() : "null")); + } + return sb.toString(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/DviObject.java b/src/jp/sourceforge/dvibrowser/dvicore/DviObject.java new file mode 100644 index 0000000..8503529 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/DviObject.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore; + +import jp.sourceforge.dvibrowser.dvicore.api.DviContext; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; + + +public class DviObject +implements DviContextSupport, DviSerialized +{ + private final DviContextSupport dcs; + private final String cacheKey; + private final DviUniqueId uniqueId; + + public DviObject(final DviContextSupport dcs) + { + this.dcs = dcs; + if (dcs == null) + throw new IllegalArgumentException + ("DviObject cannot be instantiated with null DviContextSupport."); + uniqueId = DviUniqueId.newInstance(); + cacheKey = uniqueId.toString(); + } + + public DviContext getDviContext() + { + return dcs.getDviContext(); + } + + public String getCacheKey() + { + return cacheKey; + } + + public long getSerialNumber() + { + return uniqueId.getSerialNumber(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/DviPaperSize.java b/src/jp/sourceforge/dvibrowser/dvicore/DviPaperSize.java new file mode 100644 index 0000000..4e4a180 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/DviPaperSize.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore; + +// immutable. + +public class DviPaperSize +implements java.io.Serializable +{ + private static final long serialVersionUID = 4593375448502371177L; + public static final DviPaperSize UNBOUNDED = new DviPaperSize(Double.MAX_VALUE, Double.MAX_VALUE, "unbounded"); + public static final DviPaperSize CROP_TO_WIDTH = new DviPaperSize(Double.MAX_VALUE, Double.MAX_VALUE, "crop-to-width"); + public static final DviPaperSize CROP_TO_HEIGHT = new DviPaperSize(Double.MAX_VALUE, Double.MAX_VALUE, "crop-to-height"); + public static final DviPaperSize CROP_TO_BOTH = new DviPaperSize(Double.MAX_VALUE, Double.MAX_VALUE, "crop-to-both"); + public static final DviPaperSize FALLBACK = new DviPaperSize(210.0, 297.0, "A4(fallback)"); +; + private final double w_mm; + private final double h_mm; + private final String desc; + + public DviPaperSize(double w_mm, double h_mm, String desc) { + this.w_mm = w_mm; + this.h_mm = h_mm; + this.desc = desc; + } + + public double widthInMM() { return w_mm; } + public double heightInMM() { return h_mm; } + + public int widthInDots(DviResolution res) { + return (int) Math.ceil(res.actualDpi() * w_mm / DviConstants.MM_PER_INCH); + } + public int heightInDots(DviResolution res) { + return (int) Math.ceil(res.actualDpi() * h_mm / DviConstants.MM_PER_INCH); + } + + public DviRect toBoundingBox(DviResolution res) + { + return new DviRect + (0, 0, widthInDots(res), heightInDots(res)); + } + + public String description() { return desc; } + + public String toString() { + return "PaperSize" + + "{" + w_mm + "mm x " + h_mm + " mm" + + " desc=" + desc; + } + + public boolean equals(Object obj) { + if (obj instanceof DviPaperSize) { + DviPaperSize a = (DviPaperSize) obj; + return a.w_mm == w_mm + && a.h_mm == h_mm + && desc.equals(a.desc) + ; + } + return false; + } + + public int hashCode() { + return (int)(desc.hashCode() + 33*(w_mm + 33*h_mm)); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/DviPoint.java b/src/jp/sourceforge/dvibrowser/dvicore/DviPoint.java new file mode 100644 index 0000000..f659269 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/DviPoint.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore; + +import java.awt.Point; + +// immutable. + +public final class DviPoint +implements java.io.Serializable +{ + private static final long serialVersionUID = 5621339308791022419L; + + public static final DviPoint ORIGIN = new DviPoint(0,0); + + public final int x; + public final int y; + + public DviPoint(int x, int y) { + this.x = x; + this.y = y; + } + + public DviPoint(DviPoint orig) { + this(orig.x, orig.y); + } + + public DviPoint translate(DviPoint p) { + return new DviPoint(x + p.x, y + p.y); + } + public DviPoint translate(int dx, int dy) { + return new DviPoint(x + dx, y + dy); + } + + public DviPoint shrink(int f) { + if (f <= 0) + throw new IllegalArgumentException + ("shrink factor can't be <= 0."); + + return new DviPoint( + flooredDivision(x, f), + flooredDivision(y, f) + ); + } + + public DviPoint magnify(int f) { + return new DviPoint(x * f, y * f); + } + + private static int flooredDivision(int a, int b) { + return (a < 0) ? (a - b + 1) / b : a / b; + } + + + public int hashCode() { + return x + 33*y; + } + + public boolean equals(Object obj) { + if (obj instanceof DviPoint) { + DviPoint p = (DviPoint) obj; + return p.x == x && p.y == y; + } + return false; + } + + public String toString() { + return "(" + x + "," + y + ")"; + } + +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/DviRect.java b/src/jp/sourceforge/dvibrowser/dvicore/DviRect.java new file mode 100644 index 0000000..660820c --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/DviRect.java @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore; + +import java.awt.Rectangle; + +// immutable. + +public final class DviRect +implements java.io.Serializable +{ + private static final long serialVersionUID = 1112844763203879499L; + public static final DviRect EMPTY = new DviRect(); + private final int x; + private final int y; + private final int width; + private final int height; + + public DviRect() { + this.x = 0; + this.y = 0; + this.width = 0; + this.height = 0; + } + + public DviRect(int x, int y, int width, int height) { + if (width < 0) { + this.x = x + width; + this.width = -width; + } else { + this.x = x; + this.width = width; + } + if (height < 0) { + this.y = y + height; + this.height = -height; + } else { + this.y = y; + this.height = height; + } + } + + public DviRect(DviPoint p, int width, int height) { + this(p.x, p.y, width, height); + } + + public DviRect(DviPoint p, DviSize s) { + this(p.x, p.y, s.width(), s.height()); + } + + public DviRect(int x, int y, DviSize s) { + this(x, y, s.width(), s.height()); + } + + public DviRect(DviRect r) { + this(r.x(), r.y(), r.width(), r.height()); + } + + public boolean isEmpty() { + return width == 0 || height == 0; + } + + public boolean contains(int x, int y) { + return this.x <= x && x < this.x + width && + this.y <= y && y < this.y + height; + } + + public boolean contains(DviPoint p) { + return this.x <= p.x && p.x < this.x + width && + this.y <= p.y && p.y < this.y + height; + } + + public DviSize size() { + return new DviSize(width, height); + } + + public DviRect shrink(int f) { + if (f <= 0) + throw new IllegalArgumentException("shrink factor can't be <= 0."); + + DviRect r = getDviRect( + flooredDivision(x, f), + flooredDivision(y, f), + flooredDivision(right(), f), + flooredDivision(bottom(), f)); + + return r; + } + + public DviRect magnify(int f) { + return new DviRect(x * f, y * f, width * f, height * f); + } + + public static DviRect getDviRect(int sx, int sy, int ex, int ey) { + return new DviRect(sx, sy, ex - sx + 1, ey - sy + 1); + } + + public DviRect translate(DviPoint p) { + return new DviRect(x + p.x, y + p.y, width, height); + } + public DviRect translate(int dx, int dy) { + return new DviRect(x + dx, y + dy, width, height); + } + + public DviRect moveTo(int x, int y) { + return new DviRect(x, y, width, height); + } + + public DviRect crop(int top, int left, int bottom, int right) + { + return new DviRect( + x + left, + y + top, + width - left - right, + height - top - bottom + ); + } + + public DviRect union(DviRect r) { + if (r == null) r = EMPTY; + if (isEmpty()) return r; + if (r.isEmpty()) return this; + int sx = Math.min(x, r.x); + int sy = Math.min(y, r.y); + int ex = Math.max(right(), r.right()); + int ey = Math.max(bottom(), r.bottom()); + return getDviRect(sx, sy, ex, ey); + } + + public static DviRect union(DviRect [] rs) { + DviRect ret = EMPTY; + if (rs != null) { + for (DviRect r : rs) { + ret = ret.union(r); + } + } + return ret; + } + + public DviRect intersect(DviRect r) { + int sx = Math.max(x, r.x); + int sy = Math.max(y, r.y); + int ex = Math.min(right(), r.right()); + int ey = Math.min(bottom(), r.bottom()); + return (sx <= ex && sy <= ey) ? getDviRect(sx, sy, ex, ey) + : new DviRect(); + } + + public boolean intersects(DviRect r) { + int sx = Math.max(x, r.x); + int sy = Math.max(y, r.y); + int ex = Math.min(right(), r.right()); + int ey = Math.min(bottom(), r.bottom()); + return (sx < ex && sy < ey); + } + + public DviRect addPadding(int by) { + if (isEmpty()) return this; + return getDviRect(x - by, y - by, right() + by, bottom() + by); + } + + private static int flooredDivision(final int a, final int b) { + return (a < 0) ? (a - b + 1) / b : a / b; + } + + public int x() { return x; } + public int y() { return y; } + public int width() { return width; } + public int height() { return height; } + public int left() { return x; } + public int top() { return y; } + public int right() { return x + width - 1; } + public int bottom() { return y + height - 1; } + + public DviPoint topLeft() { + return new DviPoint(x, y); + } + public DviPoint topRight() { + return new DviPoint(x+width-1, y); + } + public DviPoint bottomLeft() { + return new DviPoint(x, y+height-1); + } + public DviPoint bottomRight() { + return new DviPoint(x+width-1, y+height-1); + } + + public DviRect resize(int width, int height) + { + return new DviRect(this.x, this.y, width, height); + } + + public int hashCode() { + return (x + 33*(y + 33*(width + 33*height))); + } + + public boolean equals(Object obj) { + if (obj instanceof DviRect) { + DviRect a = (DviRect) obj; + return isEmpty() ? a.isEmpty() : ( + x == a.x && y == a.y && + width == a.width && height == a.height + ); + } return false; + } + + public String toString() { + return getClass().getName() + +"[x=" + x + +",y=" + y + +",width=" + width + +",height=" + height + +"]"; + } + + public Rectangle toRectangle() + { + return new Rectangle(x, y, width - 1, height - 1); + } + + public static DviRect fromRectangle(Rectangle rect) + { + if (rect == null) return null; + return new DviRect(rect.x, rect.y, rect.width + 1, rect.height + 1); + } + + public DviRect magnify(double hScale, double vScale) { + return new DviRect((int) (x * hScale + 0.5), (int) (y * vScale + 0.5), size().magnify(hScale, vScale)); + } + + public DviRect magnify(double scale) { + return magnify(scale, scale); + } + + public DviRect moveTo(DviPoint point) { + if (point == null) throw new IllegalArgumentException("point can't be null"); + return moveTo(point.x, point.y); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/DviRectSplitter.java b/src/jp/sourceforge/dvibrowser/dvicore/DviRectSplitter.java new file mode 100644 index 0000000..307ec62 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/DviRectSplitter.java @@ -0,0 +1,88 @@ +package jp.sourceforge.dvibrowser.dvicore; + +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +public class DviRectSplitter { + private final DviRect rect; + private final DviSize unit; + private final int cols; + private final int rows; + + public DviRectSplitter(DviRect rect, DviSize unit) + { + this.rect = rect; + this.unit = unit; + + if (unit.width == 0) throw new IllegalArgumentException("width must be > 0: " + unit.width); + if (unit.height == 0) throw new IllegalArgumentException("height must be > 0: " + unit.height); + this.cols = (rect.width() + unit.width - 1) / unit.width; + this.rows = (rect.height() + unit.height - 1) / unit.height; + } + + public int getNumColumns() + { + return cols; + } + + public int getNumRows() + { + return rows; + } + + public DviRect getRect() { return rect; } + public DviSize getUnitSize() { return unit; } + + public DviRect getRectAt(int row, int col) + { + if (row < 0 || rows <= row) + throw new IllegalArgumentException("Row index out of range: " + row); + if (col < 0 || cols <= col) + throw new IllegalArgumentException("Column index out of range: " + col); + int x = rect.x() + col * unit.width(); + int y = rect.y() + row * unit.height(); + DviRect r = new DviRect(x, y, unit); + + return r.intersect(rect); + } + + public DviRect [][] getRects() + { + DviRect [] [] rects = new DviRect[rows][cols]; + for (int i=0; i canonicalizer; + static { + canonicalizer = new SimpleCanonicalizer(); + DEFAULT = canonicalizer.canonicalize(new DviUnit()); + } + + private final int num, den, mag; + private final double inchPerDvi, pointPerDvi; + private final int hash; + + private DviUnit() { + this.num = DviConstants.DEFAULT_NUM; + this.den = DviConstants.DEFAULT_DEN; + this.mag = DviConstants.DEFAULT_MAG; + inchPerDvi = (num/254000.0)/den*(mag/1000.0); + pointPerDvi = (num/254000.0)/(den/DviConstants.POINT_PER_INCH)*(mag/1000.0); + hash = hashCodeInternal(); + } + + private DviUnit(int num, int den, int mag) { + this.num = num; + this.den = den; + this.mag = mag; + checkVars(); + inchPerDvi = (num/254000.0)/den*(mag/1000.0); + pointPerDvi = (num/254000.0)/(den/DviConstants.POINT_PER_INCH)*(mag/1000.0); + hash = hashCodeInternal(); + } + + public static DviUnit getInstance(int num, int den, int mag) + { + return canonicalizer.canonicalize( + new DviUnit(num, den, mag) + ); + } + + private int hashCodeInternal() { + return num + 33*(den + 33*mag); + } + + public int numerator() { return num; } + public int denominator() { return den; } + public int magnification() { return mag; } + + public double inchPerDvi() { + return inchPerDvi; + } + public double pointPerDvi() { + return pointPerDvi; + } + public double dotPerDvi(int dpi) { + return inchPerDvi * dpi; + } + public double mmPerDvi(int dpi) { + return inchPerDvi * DviConstants.MM_PER_INCH; + } + + public int mapToPixel(int a, int dpi) { + return (int) mapToPixelDouble(a, dpi); + } + public int mapToPixel(int a, DviResolution res) { + return (int) mapToPixelDouble(a, res); + } + + public double factorDouble(int dpi) { + return dpi * inchPerDvi; + } + public double factorDouble(DviResolution res) { + return res.actualDpi() * inchPerDvi; + } + public double mapToPixelDouble(int a, int dpi) { + return (dpi * inchPerDvi * a + 0.5); + } + public double mapToPixelDouble(int a, DviResolution res) { + return (res.actualDpi() * inchPerDvi * a + 0.5); + } + + private void checkVars() { + if (num <= 0 || den <= 0 || mag <= 0) + throw new IllegalArgumentException + ("Invalid values of num/den*mag"); + } + + private volatile String string = null; + public String toString() { + if (string == null) { + string = getClass().getName() + "[" + num + "/" + den + "*" + mag + "]"; + } + return string; + } + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj instanceof DviUnit) { + DviUnit a = (DviUnit) obj; + return (a.num == num && a.den == den && a.mag == mag); + } + return false; + } + public int hashCode() { + return hash; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/MetafontMode.java b/src/jp/sourceforge/dvibrowser/dvicore/MetafontMode.java new file mode 100644 index 0000000..5dfd17d --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/MetafontMode.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ +package jp.sourceforge.dvibrowser.dvicore; + +// TOOD: implement the default values. +public final class MetafontMode { + public static final MetafontMode FALLBACK_600DPI = new MetafontMode("ljfour", 600); + public static final MetafontMode FALLBACK_400DPI = new MetafontMode("agfatfzz", 400); + public static final MetafontMode FALLBACK = FALLBACK_600DPI; + private final String mode; + private final int bdpi; + + public MetafontMode(String mode, int bdpi) + { + this.mode = mode; + this.bdpi = bdpi; + } + + public String getMode() { + return mode; + } + + public int getBdpi() { + return bdpi; + } + + public int hashCode() + { + return mode.hashCode() + 33 * bdpi; + } + + public boolean equals(Object o) + { + if (!(o instanceof MetafontMode)) { + return false; + } + MetafontMode mm = (MetafontMode) o; + return (mm.mode.equals(mode) && mm.bdpi == mm.bdpi); + } + + public String toString() { + return getClass().getName() + "[mode=" + mode + ",bdpi=" + bdpi + "]"; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/BinaryDevice.java b/src/jp/sourceforge/dvibrowser/dvicore/api/BinaryDevice.java new file mode 100644 index 0000000..061c572 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/BinaryDevice.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import jp.sourceforge.dvibrowser.dvicore.DviException; + +public interface BinaryDevice +extends Device +{ + void begin() throws DviException; + void end() throws DviException; + boolean beginRaster(int w, int h) throws DviException; + void endRaster() throws DviException; + void beginLine() throws DviException; + void endLine(int repeat) throws DviException; + void putBits(int count, boolean paintFlag) throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/CharacterCodeMapper.java b/src/jp/sourceforge/dvibrowser/dvicore/api/CharacterCodeMapper.java new file mode 100644 index 0000000..0f88f6f --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/CharacterCodeMapper.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.font.LogicalFont; + +public interface CharacterCodeMapper { + public String mapCharacterCodeToUnicode + (LogicalFont logicalFont, int code) throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/Device.java b/src/jp/sourceforge/dvibrowser/dvicore/api/Device.java new file mode 100644 index 0000000..13bee43 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/Device.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import jp.sourceforge.dvibrowser.dvicore.DviColor; +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviPoint; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; + +//TODO: add BackgroundColor +public interface Device +{ + DviResolution getResolution() throws DviException; + + DviPoint getReferencePoint() throws DviException; + void setReferencePoint(DviPoint point) throws DviException; + void translate(int dx, int dy) throws DviException; + void translate(DviPoint p) throws DviException; + + void setColor(DviColor color) throws DviException; + DviColor getColor() throws DviException; + + void save() throws DviException; + void restore() throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/DevicePainter.java b/src/jp/sourceforge/dvibrowser/dvicore/api/DevicePainter.java new file mode 100644 index 0000000..8754cc9 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/DevicePainter.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviBop; + +public interface DevicePainter +{ + void setOutput(BinaryDevice out) throws DviException; + + void begin(GeometerContext ctx) throws DviException; + void end() throws DviException; + + void beginPage(DviBop bop) throws DviException; + void endPage() throws DviException; + + void beginFont(DviFontSpec fs) throws DviException; + void endFont() throws DviException; + + void drawChar(int code) throws DviException; + void drawRule(int width, int height) throws DviException; + void drawSpecial(byte [] xxx) throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/DviCacheable.java b/src/jp/sourceforge/dvibrowser/dvicore/api/DviCacheable.java new file mode 100644 index 0000000..8ce32d2 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/DviCacheable.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +public interface DviCacheable { + public String getCacheKey(); +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/DviContext.java b/src/jp/sourceforge/dvibrowser/dvicore/api/DviContext.java new file mode 100644 index 0000000..918dac1 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/DviContext.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import java.io.File; +import java.io.InputStream; +import java.net.URL; +import java.util.Map; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.DviPaperSize; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.MetafontMode; +import jp.sourceforge.dvibrowser.dvicore.ctx.DviToolkit; +import jp.sourceforge.dvibrowser.dvicore.font.LogicalFont; +import jp.sourceforge.dvibrowser.dvicore.util.progress.ProgressRecorder; + + +public interface DviContext +extends DviExecutor, DviContextSupport +{ + DviResolution getDefaultResolution() throws DviException; + MetafontMode getDefaultMetafontMode() throws DviException; + + DviPaperSize getDefaultPaperSize() throws DviException; + DviPaperSize findPaperSizeByName(String name) throws DviException; + DviPaperSize [] listPaperSizes() throws DviException; + + URL getDviResource(String filename) throws DviException; + + File getCacheDirectory() throws DviException; + File getTemporaryDirectory() throws DviException; + String getExecutableName(String name) throws DviException; + + Map getGlyphCache() throws DviException; + CharacterCodeMapper getCharacterCodeMapper(LogicalFont logicalFont) throws DviException; + DviExecutor newDviExecutor() throws DviException; + DevicePainter newDevicePainter() throws DviException; + DviDocument openDviDocument(File file) throws DviException; + DviDocument openDviDocument(URL url) throws DviException; + DviDocument openDviDocument(InputStream is) throws DviException; + DviFont findDviFont(LogicalFont logicalFont) throws DviException; + FullMetrics findDviFullMetrics(DviFontSpec fontSpec) throws DviException; + SimpleMetrics findDviSimpleMetrics(DviFontSpec fontSpec) throws DviException; + LogicalFont mapLogicalFont(LogicalFont logicalFont) throws DviException; + + ProgressRecorder getProgressRecorder(); + DviToolkit getDviToolkit(); +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/DviContextSupport.java b/src/jp/sourceforge/dvibrowser/dvicore/api/DviContextSupport.java new file mode 100644 index 0000000..e94a4f3 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/DviContextSupport.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +public interface DviContextSupport { + public DviContext getDviContext(); +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/DviData.java b/src/jp/sourceforge/dvibrowser/dvicore/api/DviData.java new file mode 100644 index 0000000..35ffbb1 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/DviData.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontTable; +import jp.sourceforge.dvibrowser.dvicore.DviUnit; + +public interface DviData +{ + DviUnit getDviUnit() throws DviException; + DviFontTable getFontTable() throws DviException; + DviInput getInput() throws DviException; + long getDataSize() throws DviException; // optional + DviInput getInput(long start, long end) throws DviException; // optional +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/DviDocument.java b/src/jp/sourceforge/dvibrowser/dvicore/api/DviDocument.java new file mode 100644 index 0000000..c3af35d --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/DviDocument.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostPost; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostamble; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPreamble; + +public interface DviDocument +extends DviData, DviCacheable, DviContextSupport +{ + DviPreamble getPreamble() throws DviException; + DviPostamble getPostamble() throws DviException; + DviPostPost getPostPost() throws DviException; + int getTotalPages() throws DviException; + DviPage [] getPages() throws DviException; + DviPage getPage(int p) throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/DviExecutor.java b/src/jp/sourceforge/dvibrowser/dvicore/api/DviExecutor.java new file mode 100644 index 0000000..fbe65a2 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/DviExecutor.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import jp.sourceforge.dvibrowser.dvicore.DviException; + +public interface DviExecutor +{ + void execute(DviData data, DviExecutorHandler handler) + throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/DviExecutorContext.java b/src/jp/sourceforge/dvibrowser/dvicore/api/DviExecutorContext.java new file mode 100644 index 0000000..5b1c764 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/DviExecutorContext.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import jp.sourceforge.dvibrowser.dvicore.DviByteRange; + +public interface DviExecutorContext +extends DviContextSupport +{ + DviData getData(); + int getCommand(); + DviByteRange getCommandRange(); + void setTerminate(boolean terminate); +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/DviExecutorHandler.java b/src/jp/sourceforge/dvibrowser/dvicore/api/DviExecutorHandler.java new file mode 100644 index 0000000..48d9d27 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/DviExecutorHandler.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviBop; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostPost; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostamble; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPreamble; + + +public interface DviExecutorHandler +{ + void begin(DviExecutorContext ctx) throws DviException; + void end() throws DviException; + + void doSet(int code) throws DviException; + void doSetRule(int w, int h) throws DviException; + void doPut(int code) throws DviException; + void doPutRule(int w, int h) throws DviException; + void doNop() throws DviException; + + void doSelectFont(int fn) throws DviException; + void doDefineFont(int fn, DviFontSpec fs) throws DviException; + + void doPush() throws DviException; + void doPop() throws DviException; + + void doPre(DviPreamble preamble) throws DviException; + void doBop(DviBop bop) throws DviException; + void doEop() throws DviException; + void doPost(DviPostamble postamble) throws DviException; + void doPostPost(DviPostPost postPost) throws DviException; + + void doRight(int by) throws DviException; + void doW(int by) throws DviException; + void doW0() throws DviException; + void doX(int by) throws DviException; + void doX0() throws DviException; + + void doDown(int by) throws DviException; + void doY(int by) throws DviException; + void doY0() throws DviException; + void doZ(int by) throws DviException; + void doZ0() throws DviException; + + void doSpecial(byte [] xxx) throws DviException; +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/DviFont.java b/src/jp/sourceforge/dvibrowser/dvicore/api/DviFont.java new file mode 100644 index 0000000..750a6c5 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/DviFont.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.font.LogicalFont; + +public interface DviFont +{ + Glyph getGlyph(LogicalFont lf, int code) throws DviException; + boolean hasChar(int code) throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/DviInput.java b/src/jp/sourceforge/dvibrowser/dvicore/api/DviInput.java new file mode 100644 index 0000000..da60f63 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/DviInput.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import java.io.IOException; + +public interface DviInput +{ + int readU1() throws IOException; + int readU2() throws IOException; + int readU3() throws IOException; + int readU4() throws IOException; + int readU(int len) throws IOException; + + int readS1() throws IOException; + int readS2() throws IOException; + int readS3() throws IOException; + int readS4() throws IOException; + int readS(int len) throws IOException; + + void readFully(byte [] buf) throws IOException; + + long getOffset(); + +// boolean ready() throws IOException; + + void close() throws IOException; + + void skip(int len) throws IOException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/DviPage.java b/src/jp/sourceforge/dvibrowser/dvicore/api/DviPage.java new file mode 100644 index 0000000..b359117 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/DviPage.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import jp.sourceforge.dvibrowser.dvicore.DviByteRange; +import jp.sourceforge.dvibrowser.dvicore.DviException; + +public interface DviPage +extends DviData, DviCacheable, DviContextSupport +{ + int getPageNumber() throws DviException; + DviDocument getDocument() throws DviException; + DviByteRange range() throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/FullMetrics.java b/src/jp/sourceforge/dvibrowser/dvicore/api/FullMetrics.java new file mode 100644 index 0000000..2b237af --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/FullMetrics.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import jp.sourceforge.dvibrowser.dvicore.DviException; + +public interface FullMetrics +extends SimpleMetrics +{ + int getTfmHeight(int code) throws DviException; + int getTfmDepth(int code) throws DviException; + int getTfmItalic(int code) throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/GammaCorrector.java b/src/jp/sourceforge/dvibrowser/dvicore/api/GammaCorrector.java new file mode 100644 index 0000000..4ca33cc --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/GammaCorrector.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +public interface GammaCorrector +extends DviCacheable +{ + int correctGamma(int c, int maxval); +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/Geometer.java b/src/jp/sourceforge/dvibrowser/dvicore/api/Geometer.java new file mode 100644 index 0000000..0eb706d --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/Geometer.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +public interface Geometer +extends DviExecutorHandler +{ + void setPainter(DevicePainter dp); +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/GeometerContext.java b/src/jp/sourceforge/dvibrowser/dvicore/api/GeometerContext.java new file mode 100644 index 0000000..9794a30 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/GeometerContext.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.DviRegister; + +public interface GeometerContext { + DviRegister getRegister(); + DviFontSpec currentFontSpec(); + DviExecutorContext getExecuterContext(); +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/Glyph.java b/src/jp/sourceforge/dvibrowser/dvicore/api/Glyph.java new file mode 100644 index 0000000..67c2154 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/Glyph.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; + +public interface Glyph +{ + DviRect bounds() throws DviException; + int width() throws DviException; + int height() throws DviException; + int xOffset() throws DviException; + int yOffset() throws DviException; + int xAdvance() throws DviException; + int yAdvance() throws DviException; + void rasterizeTo(BinaryDevice out) throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/HasURL.java b/src/jp/sourceforge/dvibrowser/dvicore/api/HasURL.java new file mode 100644 index 0000000..078576d --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/HasURL.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import java.net.URL; + +import jp.sourceforge.dvibrowser.dvicore.DviException; + + +public interface HasURL { + public URL getURL() throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/ImageDevice.java b/src/jp/sourceforge/dvibrowser/dvicore/api/ImageDevice.java new file mode 100644 index 0000000..0f4bcc4 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/ImageDevice.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; + +public interface ImageDevice +extends Device +{ + DviRect getBounds() throws DviException; + void begin(int maxval) throws DviException; + void end() throws DviException; + boolean beginImage(int w, int h) throws DviException; + void endImage() throws DviException; + void putLine(int [] buf, int off, int len) throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/api/SimpleMetrics.java b/src/jp/sourceforge/dvibrowser/dvicore/api/SimpleMetrics.java new file mode 100644 index 0000000..dbfb76b --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/api/SimpleMetrics.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.api; + +import jp.sourceforge.dvibrowser.dvicore.DviException; + +public interface SimpleMetrics +{ + boolean hasChar(int code) throws DviException; + int getTfmWidth(int code) throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/cli/tools/ConvertToImage.java b/src/jp/sourceforge/dvibrowser/dvicore/cli/tools/ConvertToImage.java new file mode 100644 index 0000000..89ff203 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/cli/tools/ConvertToImage.java @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ +package jp.sourceforge.dvibrowser.dvicore.cli.tools; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FilterOutputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.URL; +import java.util.ArrayList; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.imageio.ImageIO; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviPaperSize; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.api.DviContext; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviDocument; +import jp.sourceforge.dvibrowser.dvicore.api.DviPage; +import jp.sourceforge.dvibrowser.dvicore.ctx.DefaultDviContext; +import jp.sourceforge.dvibrowser.dvicore.gui.swing.ViewSpec; +import jp.sourceforge.dvibrowser.dvicore.image.split.ImageFileConfig; +import jp.sourceforge.dvibrowser.dvicore.util.Benchmark; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; +import jp.sourceforge.dvibrowser.dvicore.util.ZipBuilder; + + +public class ConvertToImage +extends DviObject +{ + private static final String OPT_SHRINK_FACTOR = "--shrink-factor="; + private static final String OPT_DPI = "--dpi="; + private static final String OPT_OUTPUT_FILE = "--output-file="; + private static final String OPT_RESOURCES_FILE = "--resources-file="; + private static final String OPT_PAPER_SIZE = "--paper-size="; + private static final String OPT_USE_BBOX = "--use-bbox="; + private static final String OPT_PADDING = "--padding="; + private static final Logger LOGGER = Logger.getLogger(ConvertToImage.class + .getName()); + + public static class Config + extends DviObject + { + private final ViewSpec viewSpec; + private final ArrayList inputs = new ArrayList(); + private boolean useBoundingBox; + private File outputFile; + private DviPaperSize paperSize; + private ImageFileConfig imageFileConfig; + private int padding; + private File resourcesFile; + + public Config(DviContextSupport dcs) { + super(dcs); + viewSpec = new ViewSpec(dcs); + try { + setPaperSize(getDviContext().getDefaultPaperSize()); + } catch (DviException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + setPaperSize(DviPaperSize.FALLBACK); + } + // TODO: outsource the config. + imageFileConfig = ImageFileConfig.PNG; + padding = 0; + } + + public void setDpi(int dpi) + { + viewSpec.setResolution(new DviResolution(dpi, viewSpec.getResolution().shrinkFactor())); + } + + public void setShrinkFactor(int sf) + { + viewSpec.setResolution(new DviResolution(viewSpec.getResolution().dpi(), sf)); + } + + public ViewSpec getViewSpec() { + return viewSpec; + } + + public void setUseBoundingBox(boolean crop) { + this.useBoundingBox = crop; + } + + public boolean useBoundingBox() { return useBoundingBox; } + + public void setOutputFile(File outputFile) { + if (outputFile != null) { + this.outputFile = outputFile; + } else { + this.outputFile = null; + } + } + + public void addInputFile(File file) + { + if (file != null) { + inputs.add(file); + } else { + LOGGER.warning("Input file is null. Ignored."); + } + } + + public File getOutputFile() { + return outputFile; + } + + public DviPaperSize getPaperSize() { + return paperSize; + } + + + public ArrayList getInputs() { + return inputs; + } + + public void parseArguments(String [] args) throws DviException + { + final DviContext ctx = getDviContext(); + for (int i=0; i"); + pw.println(" options: "); + pw.println(" --dpi=N Set output DPI to N"); + pw.println(" --shrink-factor=N Set shrink factor to N (1--1024)"); + pw.println(" --output-file=F Set output zip file to F"); + pw.println(" --resources-file=F Set resources file to F"); + pw.println(" --padding=N Set padding size to N"); + return sw.toString(); + } + + public void showUsage() + { + System.err.println(getUsage()); + } + + public boolean isValid() { + return getInputs().size() > 0; + } + + public void setPadding(int padding) { + this.padding = padding; + } + + public int getPadding() { + return padding; + } + } + + public ConvertToImage(DviContextSupport dcs) { + super(dcs); + } + + public int convert(Config config) throws Exception { + DviContext ctx = getDviContext(); + ViewSpec vs = config.getViewSpec(); + DviResolution res = vs.getResolution(); + File outputFile = config.getOutputFile(); + OutputStream os = null; + if (outputFile != null) { + if (!outputFile.getName().toLowerCase().endsWith(".zip")) { + outputFile = new File(outputFile.getParentFile(), outputFile.getName() + ".zip"); + } + os = new FileOutputStream(outputFile); + LOGGER.info("Writing outputs to " + outputFile); + } else { + os = new FilterOutputStream(System.out) { + @Override + public void close() + { + // We don't close the stdout. + } + }; + } + ZipBuilder zb = new ZipBuilder(os); + + try { + for (File file : config.getInputs()) { + try { + DviDocument doc = ctx.openDviDocument(file); + LOGGER.info("Processing file: " + file); + for (int i=0; i resources = ctx.getRecordedResources(); + FileOutputStream fos = new FileOutputStream(resourcesFile); + PrintWriter out = new PrintWriter(fos); + for (URL url : resources) { + out.println(url); + } + out.flush(); + out.close(); + fos.close(); + } + + LOGGER.info("Finished: " + benchmark.format()); + // INT_ARGB: Finished: Benchmark result: dvi rendering: 1 samples in 68.182 sec. 0.015 samples/sec. 68182 msec./sample. + // INT_RGB: Finished: Benchmark result: dvi rendering: 1 samples in 62.976 sec. 0.016 samples/sec. 62976 msec./sample. + System.exit(retcode); + } catch (Exception e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + System.exit(1); + } + } + +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/cmd/DviBop.java b/src/jp/sourceforge/dvibrowser/dvicore/cmd/DviBop.java new file mode 100644 index 0000000..2f37076 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/cmd/DviBop.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.cmd; + +/** + * An immutable class to represent the BOP (Begin Of Page) command. + * This class is used internally to parse the DVI data. + * @author Takeyuki NAGAO (nagaotakeyuki@gmail.com) + */ + +public class DviBop +implements java.io.Serializable +{ + private static final long serialVersionUID = 1326126283946043078L; + + private final int count[]; + private final int backPointer; + + public DviBop(int [] count, int backPointer) { + this.count = count.clone(); // a defensive copy + this.backPointer = backPointer; + checkValues(); + } + + public void checkValues() { + if (count.length != 10) + throw new IllegalArgumentException + ("count must be of type int [10]."); + } + + public String countAsString() { + int i, j; + + StringBuilder sb = new StringBuilder(); + sb.append(String.valueOf(count[0])); + for (i=count.length-1; i>0; i--) + if (count[i] != 0) break; + for (j=1; j<=i; j++) + sb.append(":" + count[j]); + + return sb.toString(); + } + + public int [] count() { return count.clone(); } + public int backPointer() { return backPointer; } + + public String toString() { + return getClass().getName() + "[count=" + countAsString() + + ",backPointer=" + backPointer + "]"; + } + + public boolean equals(Object o) { + if (o instanceof DviBop) { + DviBop a = (DviBop) o; + if (!(a.backPointer == backPointer + && a.count.length == count.length + && count.length == 10)) + return false; + + for (int i=0; i<10; i++) + if (a.count[i] != count[i]) + return false; + + return true; + } + return false; + } + + public int hashCode() { + int hash = backPointer; + for (int a : count) + hash = a + 33 * hash; + return hash; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/cmd/DviCommand.java b/src/jp/sourceforge/dvibrowser/dvicore/cmd/DviCommand.java new file mode 100644 index 0000000..1647b82 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/cmd/DviCommand.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.cmd; + +public class DviCommand +{ + private DviCommand() {} // To disable instantiation. + + public static final int DVI_SET1 = 128; + public static final int DVI_SET2 = 129; + public static final int DVI_SET3 = 130; + public static final int DVI_SET4 = 131; + + public static final int DVI_SET_RULE = 132; + + public static final int DVI_PUT1 = 133; + public static final int DVI_PUT2 = 134; + public static final int DVI_PUT3 = 135; + public static final int DVI_PUT4 = 136; + + public static final int DVI_PUT_RULE = 137; + + public static final int DVI_NOP = 138; + public static final int DVI_BOP = 139; + public static final int DVI_EOP = 140; + public static final int DVI_PUSH = 141; + public static final int DVI_POP = 142; + + public static final int DVI_RIGHT1 = 143; + public static final int DVI_RIGHT2 = 144; + public static final int DVI_RIGHT3 = 145; + public static final int DVI_RIGHT4 = 146; + + public static final int DVI_DOWN1 = 157; + public static final int DVI_DOWN2 = 158; + public static final int DVI_DOWN3 = 159; + public static final int DVI_DOWN4 = 160; + + + public static final int DVI_W0 = 147; + public static final int DVI_W1 = 148; + public static final int DVI_W2 = 149; + public static final int DVI_W3 = 150; + public static final int DVI_W4 = 151; + + public static final int DVI_X0 = 152; + public static final int DVI_X1 = 153; + public static final int DVI_X2 = 154; + public static final int DVI_X3 = 155; + public static final int DVI_X4 = 156; + + public static final int DVI_Y0 = 161; + public static final int DVI_Y1 = 162; + public static final int DVI_Y2 = 163; + public static final int DVI_Y3 = 164; + public static final int DVI_Y4 = 165; + + public static final int DVI_Z0 = 166; + public static final int DVI_Z1 = 167; + public static final int DVI_Z2 = 168; + public static final int DVI_Z3 = 169; + public static final int DVI_Z4 = 170; + + public static final int DVI_FONT1 = 235; + public static final int DVI_FONT2 = 236; + public static final int DVI_FONT3 = 237; + public static final int DVI_FONT4 = 238; + + public static final int DVI_XXX1 = 239; + public static final int DVI_XXX2 = 240; + public static final int DVI_XXX3 = 241; + public static final int DVI_XXX4 = 242; + + public static final int DVI_FNT_DEF1 = 243; + public static final int DVI_FNT_DEF2 = 244; + public static final int DVI_FNT_DEF3 = 245; + public static final int DVI_FNT_DEF4 = 246; + + public static final int DVI_POST = 248; + public static final int DVI_POST_POST = 249; + public static final int DVI_PRE = 247; + + public static final int DVI_UNDEF1 = 250; + public static final int DVI_UNDEF2 = 251; + public static final int DVI_UNDEF3 = 252; + public static final int DVI_UNDEF4 = 253; + public static final int DVI_UNDEF5 = 254; + public static final int DVI_UNDEF6 = 255; + public static final int DVI_TDIR = 255; /* For Japanese pTeX */ + + private static final String [] commandNames = { + "SETC_000","SETC_001","SETC_002","SETC_003","SETC_004", + "SETC_005","SETC_006","SETC_007","SETC_008","SETC_009", + "SETC_010","SETC_011","SETC_012","SETC_013","SETC_014", + "SETC_015","SETC_016","SETC_017","SETC_018","SETC_019", + "SETC_020","SETC_021","SETC_022","SETC_023","SETC_024", + "SETC_025","SETC_026","SETC_027","SETC_028","SETC_029", + "SETC_030","SETC_031","SETC_032","SETC_033","SETC_034", + "SETC_035","SETC_036","SETC_037","SETC_038","SETC_039", + "SETC_040","SETC_041","SETC_042","SETC_043","SETC_044", + "SETC_045","SETC_046","SETC_047","SETC_048","SETC_049", + "SETC_050","SETC_051","SETC_052","SETC_053","SETC_054", + "SETC_055","SETC_056","SETC_057","SETC_058","SETC_059", + "SETC_060","SETC_061","SETC_062","SETC_063","SETC_064", + "SETC_065","SETC_066","SETC_067","SETC_068","SETC_069", + "SETC_070","SETC_071","SETC_072","SETC_073","SETC_074", + "SETC_075","SETC_076","SETC_077","SETC_078","SETC_079", + "SETC_080","SETC_081","SETC_082","SETC_083","SETC_084", + "SETC_085","SETC_086","SETC_087","SETC_088","SETC_089", + "SETC_090","SETC_091","SETC_092","SETC_093","SETC_094", + "SETC_095","SETC_096","SETC_097","SETC_098","SETC_099", + "SETC_100","SETC_101","SETC_102","SETC_103","SETC_104", + "SETC_105","SETC_106","SETC_107","SETC_108","SETC_109", + "SETC_110","SETC_111","SETC_112","SETC_113","SETC_114", + "SETC_115","SETC_116","SETC_117","SETC_118","SETC_119", + "SETC_120","SETC_121","SETC_122","SETC_123","SETC_124", + "SETC_125","SETC_126","SETC_127", + "SET1","SET2","SET3","SET4","SET_RULE", + "PUT1","PUT2","PUT3","PUT4","PUT_RULE", + "NOP","BOP","EOP","PUSH","POP", + "RIGHT1","RIGHT2","RIGHT3","RIGHT4", + "W0","W1","W2","W3","W4", + "X0","X1","X2","X3","X4", + "DOWN1","DOWN2","DOWN3","DOWN4", + "Y0","Y1","Y2","Y3","Y4", + "Z0","Z1","Z2","Z3","Z4", + "FONT_00","FONT_01","FONT_02","FONT_03","FONT_04", + "FONT_05","FONT_06","FONT_07","FONT_08","FONT_09", + "FONT_10","FONT_11","FONT_12","FONT_13","FONT_14", + "FONT_15","FONT_16","FONT_17","FONT_18","FONT_19", + "FONT_20","FONT_21","FONT_22","FONT_23","FONT_24", + "FONT_25","FONT_26","FONT_27","FONT_28","FONT_29", + "FONT_30","FONT_31","FONT_32","FONT_33","FONT_34", + "FONT_35","FONT_36","FONT_37","FONT_38","FONT_39", + "FONT_40","FONT_41","FONT_42","FONT_43","FONT_44", + "FONT_45","FONT_46","FONT_47","FONT_48","FONT_49", + "FONT_50","FONT_51","FONT_52","FONT_53","FONT_54", + "FONT_55","FONT_56","FONT_57","FONT_58","FONT_59", + "FONT_60","FONT_61","FONT_62","FONT_63", + "FNT1","FNT2","FNT3","FNT4", + "XXX1","XXX2","XXX3","XXX4", + "FNT_DEF1","FNT_DEF2","FNT_DEF3","FNT_DEF4", + "PRE","POST","POST_POST", + "UNDEF_250","UNDEF_251","UNDEF_252","UNDEF_253","UNDEF_254","UNDEF_255" + }; + + public static String getName(int c) { + if (c < 0 || c > 255) + throw new IllegalArgumentException + ("no dvi command with code " + c + "."); + return commandNames[c]; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/cmd/DviPostPost.java b/src/jp/sourceforge/dvibrowser/dvicore/cmd/DviPostPost.java new file mode 100644 index 0000000..fd6279b --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/cmd/DviPostPost.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.cmd; + +// immutable. + +public class DviPostPost +implements java.io.Serializable +{ + private static final long serialVersionUID = 4094400368736425377L; + private final int postamblePointer; + private final int idByte; + + public DviPostPost(int postamblePointer, int idByte) { + this.idByte = idByte; + this.postamblePointer = postamblePointer; + checkVars(); + } + + public void checkVars() {} + + public int postamblePointer() { return postamblePointer; } + public int idByte() { return idByte; } + + public String toString() { + return getClass().getName() + "[postamblePointer=" + postamblePointer + + ",idByte=" + idByte + "]"; + } + + public boolean equals(Object o) { + if (o instanceof DviPostPost) { + DviPostPost pp = (DviPostPost) o; + return pp.idByte == idByte + && pp.postamblePointer == pp.postamblePointer + ; + } + return false; + } + + public int hashCode() { + return postamblePointer + 33*idByte; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/cmd/DviPostamble.java b/src/jp/sourceforge/dvibrowser/dvicore/cmd/DviPostamble.java new file mode 100644 index 0000000..e98f72b --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/cmd/DviPostamble.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.cmd; + +import jp.sourceforge.dvibrowser.dvicore.DviUnit; + +// immutable. + +public class DviPostamble +implements java.io.Serializable +{ + private static final long serialVersionUID = 2018955950810232285L; + private final int firstBackPointer; + private final DviUnit dviUnit; + private final int maxV, maxH; + private final int maxStackDepth; + private final int totalPages; + + public DviPostamble(int firstBackPointer, DviUnit dviUnit, + int maxV, int maxH, int maxStackDepth, int totalPages) + { + this.firstBackPointer = firstBackPointer; + this.dviUnit = dviUnit; + this.maxV = maxV; + this.maxH = maxH; + this.maxStackDepth = maxStackDepth; + this.totalPages = totalPages; + checkValues(); + } + + public void checkValues() {} + + public int firstBackPointer() { return firstBackPointer; } + public DviUnit dviUnit() { return dviUnit; } + public int maxV() { return maxV; } + public int maxH() { return maxH; } + public int maxStackDepth() { return maxStackDepth; } + public int totalPages() { return totalPages; } + + public String toString() { + return getClass().getName() + "[firstBackPointer=" + firstBackPointer + + ",dviUnit=" + dviUnit + + ",max(H,V)=(" + maxH + "," + maxV + ")" + + ",maxStackDepth=" + maxStackDepth + + ",totalPages=" + totalPages + "]"; + } + + public boolean equals(Object o) { + if (o instanceof DviPostamble) { + DviPostamble p = (DviPostamble) o; + return p.firstBackPointer == firstBackPointer + && p.dviUnit.equals(dviUnit) + && p.maxV == maxV + && p.maxH == maxH + && p.maxStackDepth == maxStackDepth + && p.totalPages == totalPages + ; + } + return false; + } + + public int hashCode() { + return firstBackPointer + + 33*(dviUnit.hashCode() + + 33*(maxV + + 33*(maxH + + 33*(maxStackDepth + + 33*totalPages + )))) + ; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/cmd/DviPreamble.java b/src/jp/sourceforge/dvibrowser/dvicore/cmd/DviPreamble.java new file mode 100644 index 0000000..7458e4b --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/cmd/DviPreamble.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.cmd; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviUnit; + +// immutable. + +public class DviPreamble +implements java.io.Serializable +{ + private static final long serialVersionUID = -455212635042527368L; + private final int idByte; + private final DviUnit dviUnit; + private final byte [] comment; + + public DviPreamble(int idByte, DviUnit dviUnit, byte [] comment) + throws DviException + { + this.idByte = idByte; + this.dviUnit = dviUnit; + this.comment = comment.clone(); + } + + public int idByte() { return idByte; } + public DviUnit dviUnit() { return dviUnit; } + public byte [] comment() { return comment.clone(); } + + public String toString() { + return getClass().getName() + "[idByte=" + idByte + ",dviUnit=" + dviUnit + + ",comment=\"" + new String(comment) + "\"]"; + } + + public boolean equals(Object o) { + if (o instanceof DviPreamble) { + DviPreamble p = (DviPreamble) o; + return p.idByte == idByte + && p.dviUnit.equals(dviUnit) + && new String(p.comment).equals(new String(comment)) + ; + } + return false; + } + + public int hashCode() { + return idByte + 33*(dviUnit.hashCode() + + 33 * new String(comment).hashCode()) + ; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/ctx/AbstractDviResourceResolver.java b/src/jp/sourceforge/dvibrowser/dvicore/ctx/AbstractDviResourceResolver.java new file mode 100644 index 0000000..bee78d4 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/ctx/AbstractDviResourceResolver.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.ctx; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.Computation; + + +public abstract class AbstractDviResourceResolver +extends DviObject +implements Computation> +{ + private final S spec; + public AbstractDviResourceResolver(DviContextSupport dcs, S spec) { + super(dcs); + this.spec = spec; + } + + public Collection call() throws Exception + { + List list = new ArrayList(); + String filename = mapToDviResourceName(getSpec()); + URL url = getDviContext().getDviResource(filename); + if (url != null) { + final T item = createInstanceFromURL(url); + if (item != null) { + list.add(item); + } + } + return list; + } + + @Override + public String getCacheKey() + { + return mapToDviResourceName(getSpec()); + } + + protected T createInstanceFromURL(URL url) throws DviException, + IOException + { + if (url == null) return null; + return createInstanceFromStream(url.openStream()); + } + + protected abstract T createInstanceFromStream(InputStream openStream) throws DviException; + + protected abstract String mapToDviResourceName(S spec); + + public S getSpec() + { + return spec; + } + +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/ctx/AsyncComputers.java b/src/jp/sourceforge/dvibrowser/dvicore/ctx/AsyncComputers.java new file mode 100644 index 0000000..da63ca8 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/ctx/AsyncComputers.java @@ -0,0 +1,66 @@ +package jp.sourceforge.dvibrowser.dvicore.ctx; + +import java.net.URL; +import java.util.Collection; +import java.util.Map; +import java.util.Properties; + +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.api.DviFont; +import jp.sourceforge.dvibrowser.dvicore.api.FullMetrics; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.CacheEntry; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.CachedComputer; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.ThreadedComputer; + +public class AsyncComputers { + private final CachedComputer> dviResourceComputer; + private final CachedComputer> dviFontComputer; + private final CachedComputer> fullMetricsComputer; + private final CachedComputer boundingBoxComputer; + + protected final Properties properties; + + public AsyncComputers(Properties prop) { + this.properties = prop; + this.dviResourceComputer = new CachedComputer>( + new ThreadedComputer>(1)); + this.dviFontComputer = new CachedComputer>( + new ThreadedComputer>(1)) { + @Override + protected boolean removeEldestEntry( + Map.Entry>> entry) { + boolean remove = getCache().size() > 64; + return remove; + } + }; + + fullMetricsComputer = new CachedComputer>( + new ThreadedComputer>(1)); + + boundingBoxComputer = new CachedComputer( + new ThreadedComputer(1)) { + @Override + protected boolean removeEldestEntry( + Map.Entry> entry) { + return getCache().size() > 1024; + } + }; + + } + + public CachedComputer> getDviResourceComputer() { + return dviResourceComputer; + } + + public CachedComputer> getDviFontComputer() { + return dviFontComputer; + } + + public CachedComputer> getFullMetricsComputer() { + return fullMetricsComputer; + } + + public CachedComputer getBoundingBoxComputer() { + return boundingBoxComputer; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/ctx/BakomaUnicodeCharacterCodeMapper.java b/src/jp/sourceforge/dvibrowser/dvicore/ctx/BakomaUnicodeCharacterCodeMapper.java new file mode 100644 index 0000000..efe9b16 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/ctx/BakomaUnicodeCharacterCodeMapper.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.ctx; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.api.CharacterCodeMapper; +import jp.sourceforge.dvibrowser.dvicore.font.LogicalFont; + +public class BakomaUnicodeCharacterCodeMapper implements CharacterCodeMapper { + public String mapCharacterCodeToUnicode(LogicalFont logicalFont, int codePoint) + throws DviException + { + if (0x00 <= codePoint && codePoint <= 0x09) { + codePoint += 161; + } else if (0x0a == codePoint) { + codePoint = 173; + } else if (0x14 == codePoint) { + // http://argent.shinshu-u.ac.jp/~otobe/tex/book/WinXP.html + codePoint = 0x2219; + } else if (0x0b <= codePoint && codePoint <= 0x20) { + codePoint += 174 - 0x0b; + } else if (0x7f == codePoint) { + codePoint = 196; + } + + if (Character.charCount(codePoint) == 1) { + return String.valueOf((char) codePoint); + } else { + return new String(Character.toChars(codePoint)); + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/ctx/DefaultDviContext.java b/src/jp/sourceforge/dvibrowser/dvicore/ctx/DefaultDviContext.java new file mode 100644 index 0000000..2c8c55f --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/ctx/DefaultDviContext.java @@ -0,0 +1,511 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.ctx; + +import java.io.File; +import java.io.InputStream; +import java.net.URL; +import java.security.AccessControlException; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.DviPaperSize; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.MetafontMode; +import jp.sourceforge.dvibrowser.dvicore.api.CharacterCodeMapper; +import jp.sourceforge.dvibrowser.dvicore.api.DevicePainter; +import jp.sourceforge.dvibrowser.dvicore.api.DviContext; +import jp.sourceforge.dvibrowser.dvicore.api.DviData; +import jp.sourceforge.dvibrowser.dvicore.api.DviDocument; +import jp.sourceforge.dvibrowser.dvicore.api.DviExecutor; +import jp.sourceforge.dvibrowser.dvicore.api.DviExecutorHandler; +import jp.sourceforge.dvibrowser.dvicore.api.DviFont; +import jp.sourceforge.dvibrowser.dvicore.api.FullMetrics; +import jp.sourceforge.dvibrowser.dvicore.api.Glyph; +import jp.sourceforge.dvibrowser.dvicore.api.SimpleMetrics; +import jp.sourceforge.dvibrowser.dvicore.doc.DirectFileDviDocument; +import jp.sourceforge.dvibrowser.dvicore.doc.StreamDviDocument; +import jp.sourceforge.dvibrowser.dvicore.doc.URLDviDocument; +import jp.sourceforge.dvibrowser.dvicore.font.DviFontResolver; +import jp.sourceforge.dvibrowser.dvicore.font.FullMetricsResolver; +import jp.sourceforge.dvibrowser.dvicore.font.LogicalFont; +import jp.sourceforge.dvibrowser.dvicore.gs.GhostscriptUtils; +import jp.sourceforge.dvibrowser.dvicore.render.BasicExecutor; +import jp.sourceforge.dvibrowser.dvicore.render.DefaultDevicePainter; +import jp.sourceforge.dvibrowser.dvicore.util.DviCache; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.Computation; +import jp.sourceforge.dvibrowser.dvicore.util.progress.ManagedProgressItem; +import jp.sourceforge.dvibrowser.dvicore.util.progress.ProgressRecorder; + + +public class DefaultDviContext +implements DviContext +{ + private static final Logger LOGGER = Logger.getLogger(DefaultDviContext.class.getName()); + + private static final String DVICORE_INTERNAL_FILENAME_PREFIX = "dvicore-"; + + private final Map glyphCache = new DviCache(16384); + private final CharacterCodeMapper characterCodeMapper + = new SimpleJisToUnicodeMapper(); + + private boolean recordResources = false; + private final Set resources = new TreeSet(new Comparator() { + public int compare(URL arg0, URL arg1) { + return arg0.toString().compareTo(arg1.toString()); + } + }); + + private final ProgressRecorder recorder = new ProgressRecorder(this) { + @Override + protected boolean removeEldestElement(ManagedProgressItem item) + { + List list = getProgressItems(); + if (list.size() > 10) { + return true; + } + return false; + } + }; + + private AsyncComputers asyncComputers; + + + public DefaultDviContext() + throws DviException + { + this(null); + } + + public DefaultDviContext(Properties prop) + throws DviException + { + if (prop == null) + prop = getDefaultProperties(); + this.prop = prop; + initializeComputers(); + initializeFontMapper(); + populatePaperSizes(); + initializeDirs(); + } + + protected void initializeComputers() { + this.setAsyncComputers(new AsyncComputers(prop)); + } + + protected void initializeDirs() + throws DviException + { + File cacheDir = getCacheDirectory(); + if (cacheDir != null && !cacheDir.exists()) { + if (!cacheDir.mkdirs()) { + throw new DviException("Failed to create cache directory: " + cacheDir); + } + } + File tmpDir = getTemporaryDirectory(); + if (tmpDir != null && !tmpDir.exists()) { + if (!tmpDir.mkdirs()) { + throw new DviException("Failed to create temporary directory: " + tmpDir); + } + } + } + + protected Properties getDefaultProperties() + throws DviException + { + try { + URL url = DefaultDviContext.class.getResource("default-context.properties"); + Properties prop = new Properties(); + if (null != url) { + prop.load(url.openStream()); + } else { + LOGGER.warning("Failed to load default-context.properties"); + } + return prop; + } catch (Exception e) { + throw new DviException(e); + } + } + + private final Properties prop; + + public Properties getProperties() + { + return prop; + } + + public void execute(DviData data, DviExecutorHandler handler) + throws DviException + { + newDviExecutor().execute(data, handler); + } + +// TODO: delete +// private static final CachedComputer> dviFontComputer +// = new CachedComputer> +// (new ThreadedComputer>(1)) { +// @Override +// protected boolean removeEldestEntry(Map.Entry>> entry) +// { +// boolean remove = getCache().size() > 64; +// return remove; +// } +// }; + + public DviFont findDviFont(LogicalFont logicalFont) throws DviException + { + Computation> computation + = new DviFontResolver(this, logicalFont); + try { + Collection fonts = getAsyncComputers().getDviFontComputer() + .compute(computation).get(); + for (DviFont font : fonts) { + return font; + } + return null; + } catch (InterruptedException e) { + throw new DviException(e); + } catch (ExecutionException e) { + throw new DviException(e); + } + } + + public SimpleMetrics findDviSimpleMetrics(DviFontSpec fs) throws DviException + { + return findDviFullMetrics(fs); + } + +// private static final CachedComputer> fullMetricsComputer +// = new CachedComputer> +// (new ThreadedComputer>(1)); + + public FullMetrics findDviFullMetrics(DviFontSpec fs) throws DviException + { + Computation> computation = new FullMetricsResolver( + this, fs); + try { + Collection fonts = getAsyncComputers().getFullMetricsComputer() + .compute(computation).get(); + if (fonts != null) { + for (FullMetrics font : fonts) { + return font; + } + } + return null; + } catch (InterruptedException e) { + throw new DviException(e); + } catch (ExecutionException e) { + throw new DviException(e); + } + } + + public CharacterCodeMapper getCharacterCodeMapper(LogicalFont logicalFont) throws DviException + { + return characterCodeMapper; + } + + public DviContext getDviContext() { return this; } + + public Map getGlyphCache() throws DviException + { + return Collections.synchronizedMap(glyphCache); + } + + protected void initializeFontMapper() + { + } + + public DevicePainter newDevicePainter() throws DviException + { + return new DefaultDevicePainter(this); + } + + public DviExecutor newDviExecutor() throws DviException + { + return new BasicExecutor(this); + } + + public DviDocument openDviDocument(File file) throws DviException + { + return new DirectFileDviDocument(this, file); + } + + public DviDocument openDviDocument(InputStream is) throws DviException + { + return new StreamDviDocument(this, is); + } + + // TODO: implement async resource loading + public DviDocument openDviDocument(URL url) throws DviException + { + return new URLDviDocument(this, url); + } + + public ProgressRecorder getProgressRecorder() + { + return recorder; + } + + private static final Map paperSizes = new TreeMap(); + + protected void populatePaperSizes() + { + // ISO 216 sizes + // TODO: implement B and C serieses. A4 Japanese, too. + // TOOD: outsource the configuration. + addPaperSize(new DviPaperSize(841.0, 1189.0, "A0")); + addPaperSize(new DviPaperSize(594.0, 841.0, "A1")); + addPaperSize(new DviPaperSize(420.0, 594.0, "A2")); + addPaperSize(new DviPaperSize(297.0, 420.0, "A3")); + addPaperSize(new DviPaperSize(210.0, 297.0, "A4")); + addPaperSize(new DviPaperSize(148.0, 210.0, "A5")); + addPaperSize(new DviPaperSize(105.0, 148.0, "A6")); + addPaperSize(new DviPaperSize(74.0, 105.0, "A7")); + addPaperSize(new DviPaperSize(52.0, 74.0, "A8")); + addPaperSize(new DviPaperSize(37.0, 52.0, "A9")); + addPaperSize(new DviPaperSize(26.0, 37.0, "A10")); + } + + protected void addPaperSize(DviPaperSize dviPaperSize) + { + if (dviPaperSize == null) return; + paperSizes.put(dviPaperSize.description().toLowerCase(), dviPaperSize); + } + + public DviPaperSize findPaperSizeByName(String name) throws DviException + { + if (name == null) return null; + return paperSizes.get(name.toLowerCase()); + } + + public DviPaperSize getDefaultPaperSize() throws DviException + { + return findPaperSizeByName("A4"); + } + + public DviPaperSize [] listPaperSizes() throws DviException + { + return paperSizes.values().toArray(new DviPaperSize[0]); + } + + private static final DviResolution defaultResolution = new DviResolution(2400, 20); + + public DviResolution getDefaultResolution() throws DviException + { + return defaultResolution; + } + +// TODO: delete +// private static final CachedComputer> dviResourceComputer +// = new CachedComputer> +// (new ThreadedComputer>(1)); + + public URL getDviResource(String filename) throws DviException + { + if (filename.startsWith(DVICORE_INTERNAL_FILENAME_PREFIX)) { + // The resource name starting with "dvicore-" are only for internal use. + // So there is no local file corresponding to such a filename. + // We answer null. + return null; + } + + Computation> c + = new FileLocationResolver(this, "/dvi/builtin", filename); + final Future> future + = getAsyncComputers().getDviResourceComputer().compute(c); + try { + final Collection list = future.get(); + for (URL url : list) { + if (recordResources) { + LOGGER.info("resolved resource: filename=" + filename + " url=" + url); + resources.add(url); + } else { + LOGGER.finest("resolved resource: filename=" + filename + " url=" + url); + } + return url; + } + return null; + } catch (InterruptedException e) { + LOGGER.warning(e.toString()); + throw new DviException(e); + } catch (ExecutionException e) { + LOGGER.warning(e.toString()); + throw new DviException(e); + } + } + + public LogicalFont mapLogicalFont(LogicalFont logicalFont) + throws DviException + { + LogicalFont mapped = logicalFont; + if (logicalFont != null) { + String prefix = getClass().getName(); + String faceKey = prefix + ".fontMap." + logicalFont.fontSpec().name(); + LOGGER.info("Face key: " + faceKey); + String face = getProperties().getProperty(faceKey); + LOGGER.info("Properties: " + getProperties()); + if (face != null) { + mapped = logicalFont.renameTo(face); + LOGGER.info("Rename logical font: " + logicalFont + " => " + mapped); + } + } + LOGGER.info("Map logical font: " + logicalFont + " => " + mapped); + return mapped; + } + + // N.B. System.getProperty() throws an exception when invoked + // from inside an applet. + private static String getSystemProperty(String key) { + try { + return System.getProperty(key); + } catch (AccessControlException ex) { + return null; + } + } + + private static final String userDir = getSystemProperty("user.dir"); + private static final String ioTmpDir = getSystemProperty("java.io.tmpdir"); + + // TODO: externalize the string "dvibrowser.jar". + public File getApplicationHomeDir() + throws DviException + { + if (userDir != null) { + File home = new File(userDir); + File markFile = new File(home, "dvibrowser.jar"); + if (markFile.exists()) { + // It seems that we are using DviContext from within dvibrowser. + return home; + } + } + return null; + } + + public File getCacheDirectory() throws DviException + { + File appHome = getApplicationHomeDir(); + if (appHome == null) { + File tmpDir = getTemporaryDirectory(); + if (tmpDir != null) { + return new File(tmpDir, "cache"); + } + } else { + if (userDir != null) { + File var = new File(userDir, "var"); + return new File(var, "cache"); + } + } + return null; + } + + public File getTemporaryDirectory() throws DviException + { + File appHome = getApplicationHomeDir(); + if (appHome == null) { + if (ioTmpDir != null) { + return new File(ioTmpDir, "dvicontext"); + } + } else { + return new File(appHome, "tmp"); + } + return null; + } + + private volatile String [] ghostscriptExecutables = null; + + public String getExecutableName(String name) throws DviException + { + if ("gs".equals(name)) { + if (ghostscriptExecutables == null) { + // The following code might be called in pararell when we invoke + // this method from within multiple threads. + // It might be better to use some atomic classes. + ghostscriptExecutables = GhostscriptUtils.listGhostscriptExecutables(); + if (ghostscriptExecutables.length == 0) { + LOGGER.warning("You don't seem to have a Ghostscript installed. dvibrowser needs it to render PS, EPS, and PDF."); + } else { + LOGGER.info("Ghostscript executables found: " + DviUtils.join(" ", ghostscriptExecutables)); + } + } + if (ghostscriptExecutables.length > 0) { + return ghostscriptExecutables[0]; + } + } + + return name; + } + + private final DviToolkit dviToolkit = new DviToolkit(this); + public DviToolkit getDviToolkit() + { + return dviToolkit; + } + + private final MetafontMode libraryDefaultMetafontMode = MetafontMode.FALLBACK; + public MetafontMode getDefaultMetafontMode() throws DviException { + return libraryDefaultMetafontMode; + } + + public void setRecordResources(boolean recordResources) { + this.recordResources = recordResources; + } + + public boolean wantRecordResources() { + return recordResources; + } + + public Set getRecordedResources() { + return resources; + } + + protected void setAsyncComputers(AsyncComputers asyncComputers) { + this.asyncComputers = asyncComputers; + } + + public AsyncComputers getAsyncComputers() { + return asyncComputers; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/ctx/DviToolkit.java b/src/jp/sourceforge/dvibrowser/dvicore/ctx/DviToolkit.java new file mode 100644 index 0000000..fcf79bc --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/ctx/DviToolkit.java @@ -0,0 +1,518 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.ctx; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.awt.image.WritableRaster; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviPaperSize; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.api.DevicePainter; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviDocument; +import jp.sourceforge.dvibrowser.dvicore.api.DviPage; +import jp.sourceforge.dvibrowser.dvicore.api.Geometer; +import jp.sourceforge.dvibrowser.dvicore.api.ImageDevice; +import jp.sourceforge.dvibrowser.dvicore.gui.swing.ViewSpec; +import jp.sourceforge.dvibrowser.dvicore.image.split.DviImage; +import jp.sourceforge.dvibrowser.dvicore.image.split.SplitImage; +import jp.sourceforge.dvibrowser.dvicore.image.split.SplitImageUtils; +import jp.sourceforge.dvibrowser.dvicore.render.BasicGeometer; +import jp.sourceforge.dvibrowser.dvicore.render.DviBoundingBoxPreparator; +import jp.sourceforge.dvibrowser.dvicore.render.DviPagePreparator; +import jp.sourceforge.dvibrowser.dvicore.render.IntRGBImage; +import jp.sourceforge.dvibrowser.dvicore.render.RunLengthSampler; +import jp.sourceforge.dvibrowser.dvicore.special.AnchorSet; +import jp.sourceforge.dvibrowser.dvicore.special.EPS2ImagePreparator; +import jp.sourceforge.dvibrowser.dvicore.special.EPS2SplitImagePreparator; +import jp.sourceforge.dvibrowser.dvicore.special.EmbeddedPostScript; +import jp.sourceforge.dvibrowser.dvicore.special.EmbeddedPostScriptPreparator; +import jp.sourceforge.dvibrowser.dvicore.special.HtmlSpecialParser; +import jp.sourceforge.dvibrowser.dvicore.special.SourceSpecialParser; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.CacheEntry; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.CachedComputer; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.Computation; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.ThreadedComputer; + + +// TODO: Make this an interface +public class DviToolkit +extends DviObject +{ + private static final Logger LOGGER = Logger.getLogger(DviToolkit.class.getName()); + + private static final Map anchorSetCache = Collections + .synchronizedMap(new LinkedHashMap() { + private static final long serialVersionUID = 3603340224879882990L; + + protected boolean removeEldestEntry(Map.Entry entry) { + return size() > 1024; + } + }); + + public DviToolkit(DviContextSupport dcs) + { + super(dcs); + } + + public DviRect computeRawBoundingBox(DviPage page, DviResolution res) + throws DviException + { + if (page == null) + return null; + + Computation computation + = new DviBoundingBoxPreparator(this, page, res); + + Future future = computerForBoundingBoxPreparator.compute(computation); + DviRect bbox; + try { + bbox = future.get(); + } catch (InterruptedException e) { + throw new DviException(e); + } catch (ExecutionException e) { + throw new DviException(e); + } + return bbox; + } + + public DviRect computeBoundingBox(DviPage page, DviResolution res) + throws DviException + { + if (page == null) + return null; + + DviRect bbox = computeRawBoundingBox(page, res); + if (bbox == null) return bbox; + return bbox.shrink(res.shrinkFactor()); + } + + public DviRect [] computeRawBoundingBoxes(DviDocument doc, DviResolution res) + throws DviException + { + if (doc == null) + return null; + + List bbox = new ArrayList(); + + for (DviPage page : doc.getPages()) { + bbox.add(computeRawBoundingBox(page, res)); + } + + return bbox.toArray(new DviRect[0]); + } + + public DviRect[] computeBoundingBoxes(DviDocument doc, DviResolution res) throws DviException + { + if (doc == null) + return null; + + DviRect [] raw = computeRawBoundingBoxes(doc, res); + DviRect [] ret = new DviRect[raw.length]; + for (int i=0; i 0) { + DviPage page = doc.getPage(0); + prepareForRendering(page, viewSpec); + computeBoundingBoxes(doc, viewSpec.getResolution()); + } + } + + private AnchorSet buildAnchorSetForDocument(DviDocument doc) + { + AnchorSet as = new AnchorSet(); + { + try { + HtmlSpecialParser hse = new HtmlSpecialParser(this); + hse.execute(doc); + LOGGER.fine("Extracted Html tags from " + doc); + as.addAll(hse.getAnchorSet()); + } catch (DviException e) { + LOGGER.warning(e.toString()); + } + } + { + try { + SourceSpecialParser hse = new SourceSpecialParser(this); + hse.execute(doc); + LOGGER.fine("Extracted Source specials from " + doc); + as.addAll(hse.getAnchorSet()); + } catch (DviException e) { + LOGGER.warning(e.toString()); + } + } + return as; + } + + public AnchorSet getAnchorSet(DviPage page) + throws DviException + { + if (page == null) return null; + DviDocument doc = page.getDocument(); + String key = doc.getCacheKey(); + AnchorSet as = anchorSetCache.get(key); + if (as == null) { + as = buildAnchorSetForDocument(doc); + if (as != null) { + anchorSetCache.put(key, as); + LOGGER.fine("Cached AnchorSet with key " + key); + } + } + + if (as == null) { + return null; + } + + AnchorSet pageAnchorSet = new AnchorSet(); + pageAnchorSet.addAll(as.intersect(page.range())); + return pageAnchorSet; + } + + public DviRect computePageBoundingBox(DviPaperSize paperSize, DviResolution res) + { + DviRect bbox = null; + try { + paperSize = getDviContext().getDefaultPaperSize(); + } catch (DviException e) { + LOGGER.warning(e.toString()); + } + if (paperSize == null) { + LOGGER.warning("The default paper size is undefined. We use A4."); + paperSize = new DviPaperSize(210.0, 297.0, "A4 internal"); + } + + bbox = paperSize.toBoundingBox(res); + + return bbox; + } + + + public void prepareForRendering(DviPage page, ViewSpec viewSpec) + { + Computation computation = new DviPagePreparator(this, page, viewSpec); + try { + computerForPreparator.compute(computation).get(); + } catch (InterruptedException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + } catch (ExecutionException e) { + DviUtils.logStackTrace(LOGGER, Level.SEVERE, e); + } + } + + public boolean canRenderPageImmediately(DviPage page, ViewSpec viewSpec) + { + Computation computation = new DviPagePreparator(this, page, viewSpec); + Future future = computerForPreparator.getCachedResult(computation); + return future != null && future.isDone(); + } + + + + public EmbeddedPostScript getEmbeddedPostScript(DviDocument doc, ViewSpec viewSpec) + throws DviException + { + Computation computation + = new EmbeddedPostScriptPreparator(this, doc, viewSpec); + Future future = computerForEmbeddedPostScriptPreparator.compute(computation); + try { + return future.get(); + } catch (InterruptedException e) { + throw new DviException(e); + } catch (ExecutionException e) { + throw new DviException(e); + } + } + + public String getEmbeddedPostScript(DviPage page, ViewSpec viewSpec) + throws DviException + { + if (page == null) return null; + EmbeddedPostScript eps = getEmbeddedPostScript(page.getDocument(), viewSpec); + return eps.toPostScript(page.getPageNumber(), viewSpec.getEpsResolutionDpi()); + } + + + public DviImage getEmbeddedPostScriptAsImage(DviPage page, ViewSpec viewSpec) + throws DviException + { + Computation computation = new EPS2ImagePreparator(this, + page, viewSpec); + Future future = computerForEPS2Image.compute(computation); + try { + return future.get(); + } catch (InterruptedException e) { + throw new DviException(e); + } catch (ExecutionException e) { + throw new DviException(e); + } + } + + private static final CachedComputer computerForPreparator = new CachedComputer( + new ThreadedComputer(1)) { + @Override + protected boolean removeEldestEntry( + Map.Entry> entry) { + return getCache().size() > 1024; + } + }; + + private static final CachedComputer computerForEmbeddedPostScriptPreparator = new CachedComputer( + new ThreadedComputer(1)) { + @Override + protected boolean removeEldestEntry( + Map.Entry> entry) { + return getCache().size() > 1024; + } + }; + + private static final CachedComputer computerForEPS2Image = new CachedComputer( + new ThreadedComputer(1)) { + @Override + protected boolean removeEldestEntry( + Map.Entry> entry) { + return getCache().size() > 10; + } + }; + + private static final CachedComputer computerForEPS2SplitImage = new CachedComputer( + new ThreadedComputer(1)) { + @Override + protected boolean removeEldestEntry( + Map.Entry> entry) { + return getCache().size() > 10; + } + }; + + private static final CachedComputer computerForBoundingBoxPreparator = new CachedComputer( + new ThreadedComputer(1)) { + @Override + protected boolean removeEldestEntry( + Map.Entry> entry) { + return getCache().size() > 1024; + } + }; + + + public SplitImage getEmbeddedPostScriptAsSplitImage(DviPage page, ViewSpec viewSpec) + throws DviException + { + Computation computation = new EPS2SplitImagePreparator(this, + page, viewSpec); + Future future = computerForEPS2SplitImage.compute(computation); + try { + return future.get(); + } catch (InterruptedException e) { + throw new DviException(e); + } catch (ExecutionException e) { + throw new DviException(e); + } + } + + + // This is slow. + public BufferedImage getScaledImage(int width, int height, BufferedImage image) { + if (image == null) return null; + int origWidth = image.getWidth(); + int origHeight = image.getHeight(); + if (width < 0) { + if (origHeight > 0) { + width = origWidth * height / origHeight; + } else { + width = 0; + } + } else if (height < 0) { + if (origWidth > 0) { + height = origHeight * width / origWidth; + } else { + height = 0; + } + } + BufferedImage out = createCompatibleBufferedImage(width, height); + Graphics2D g = out.createGraphics(); + g.drawImage(image.getScaledInstance(width, height, Image.SCALE_SMOOTH), null, null); + g.dispose(); + return out; + } + + +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/ctx/FileLocationResolver.java b/src/jp/sourceforge/dvibrowser/dvicore/ctx/FileLocationResolver.java new file mode 100644 index 0000000..b64c989 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/ctx/FileLocationResolver.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.ctx; +import java.io.File; +import java.net.URL; +import java.security.AccessControlException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.Computation; +import jp.sourceforge.dvibrowser.dvicore.util.progress.ProgressItem; + + +public class FileLocationResolver +extends DviObject +implements Computation> { + private static final Logger LOGGER = Logger.getLogger(FileLocationResolver.class + .getName()); + private final String systemResourcePath; + private final String filename; + + public FileLocationResolver(DviContextSupport dcs, String systemResourcePath, String filename) + { + super(dcs); + this.filename = filename; + this.systemResourcePath = systemResourcePath; + } + + public Collection call() throws Exception + { + ProgressItem progress = getDviContext().getProgressRecorder().open("preparing " + filename); + List list = new ArrayList(); + try { + try { + if ("true".equals(System.getProperty("dvi.ctx.DefaultDviContext.usePackageShareDir"))) { + File f = new File("share", filename); + if (f.exists() && f.canRead()) { + LOGGER.fine("Using resource from share: " + f); + list.add(f.toURL()); + return list; + } + } + } catch (AccessControlException ex) { + LOGGER.warning(ex.toString()); + } + + LOGGER.finer("running kpsewhich: " + filename); + try { + URL url = null; + KpseWhich kpseWhich = new KpseWhich(this); + url = kpseWhich.findURL(filename, true); + LOGGER.finer("kpsewhich result: " + filename + " => " + url); + if (url != null) + list.add(url); + } catch (RuntimeException ex) { + LOGGER.warning(ex.toString()); + } + + try { + URL u = ClassLoader.getSystemResource(systemResourcePath + "/" + + filename); + LOGGER.fine("system resource by classloader: " + filename + " => " + u); + if (u != null) + list.add(u); + } catch (RuntimeException ex) { + LOGGER.warning(ex.toString()); + } + + try { + URL u = getClass().getResource(systemResourcePath + "/" + + filename); + LOGGER.fine("resource by classloader: " + filename + " => " + u); + if (u != null) + list.add(u); + } catch (RuntimeException ex) { + LOGGER.warning(ex.toString()); + } + + + if (list.size() == 0) { + LOGGER.warning("Failed to resolve file: " + filename); + } + } finally { + progress.close(); + } + + return list; + } + + public String getFilename() + { + return filename; + } + + public String getCacheKey() + { + return filename; + } + + public String getSystemResourcePath() + { + return systemResourcePath; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/ctx/KpseWhich.java b/src/jp/sourceforge/dvibrowser/dvicore/ctx/KpseWhich.java new file mode 100644 index 0000000..f4a4f78 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/ctx/KpseWhich.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.ctx; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.MetafontMode; +import jp.sourceforge.dvibrowser.dvicore.api.DviContext; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.plat.cygwin.CygwinUtils; +import jp.sourceforge.dvibrowser.dvicore.util.CommandShell; +import jp.sourceforge.dvibrowser.dvicore.util.CommandShellHandler; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + + +public class KpseWhich +extends DviObject +{ + public static final int KPSEWHICH_TYPE_UNKNOWN = -1; + public static final int KPSEWHICH_TYPE_DEFAULT = 0; + public static final int KPSEWHICH_TYPE_WINDOWS_SLASH = 1; + public static final int KPSEWHICH_TYPE_CYGWIN = 2; + + private static final Logger LOGGER = Logger.getLogger(KpseWhich.class.getName()); + private static boolean available = false; + private static volatile boolean availabilityChecked = false; + + private static int type = -1; + private boolean useMktexCommand = true; + + public KpseWhich(DviContextSupport dcs) + { + super(dcs); + if (!availabilityChecked) { + checkAvailability(); + } + } + + private static void setAvailability(boolean isAvailable) + { + available = isAvailable; + availabilityChecked = true; + } + + // TODO: outsource the test filename. + private synchronized void checkAvailability() { + boolean success = true; + try { + String filename = "cmr10.mf"; + String result = findURLInternal(filename, true); + if (result == null) { + LOGGER.warning("Unable to locate by kpsewhich: " + filename); + success = false; + } else { + LOGGER.info("kpsewhich answers: filename=" + filename + " result=" + result); + File f = new File(result); + if (!f.exists()) { + if (DviUtils.isWindows()) { + LOGGER.info("Trying cygpath to map " + result + " to system path."); + { + File f2 = replaceSlashInWindows(result); + if (f2 != null) { + if (f2.exists()) { + LOGGER.info("The mapped path seems to work: " + f2.getAbsolutePath()); + LOGGER.info("kpsewhich seems to encode path with /."); + type = KPSEWHICH_TYPE_WINDOWS_SLASH; + } + } + } + + if (type < 0) { + File f2 = fromPosixPathCygwin(result); + if (f2.exists()) { + LOGGER.info("The mapped path seems to work: " + f2.getAbsolutePath()); + LOGGER.info("kpsewhich seems to use the cygwin style path."); + type = KPSEWHICH_TYPE_CYGWIN; + } + } + + if (type >= 0) { + LOGGER.warning("kpsewhich type resolved: " + type); + success = true; + } else { + LOGGER.warning("Unrecognized output by kpsewhich: " + result); + success = false; + } + } else { + LOGGER.warning("Unable to find file: " + result); + success = false; + } + } else { + LOGGER.info("Using default kpsewhich."); + type = KPSEWHICH_TYPE_DEFAULT; + success = true; + } + } + } catch (MalformedURLException ex) { + success = false; + } catch (DviException ex) { + success = false; + } catch (RuntimeException ex) { + success = false; + } + setAvailability(success); + if (!success) { + LOGGER.info("kpsewhich is not available"); + } + } + + private static final Pattern patSlashInWindows = Pattern.compile("^[A-Za-z]:.*$"); + private File replaceSlashInWindows(String path) { + Matcher mat = patSlashInWindows.matcher(path); + if (mat.matches()) { + return new File(path.replaceAll("/", "\\")); + } + return null; + } + + private File fromPosixPathCygwin(String posixPath) { + try { + String windowsPath = CygwinUtils.posixPathToJavaPath(posixPath); + return new File(windowsPath); + } catch (InterruptedException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + return null; + } catch (IOException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + return null; + } catch (DviException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + return null; + } + } + + public URL findURL(String name) throws MalformedURLException, DviException + { + return findURL(name, false); + } + + private String findURLInternal(String name, boolean mustExist) throws MalformedURLException, DviException + { + String result = null; + try { + DviContext ctx = getDviContext(); + MetafontMode mfmode = getMetafontMode(); + Vector cmdLine = new Vector(); + cmdLine.add(ctx.getExecutableName("kpsewhich")); + if (mustExist) { + cmdLine.add("-must-exist"); + } + + if (useMktexThroughKpsewhich()) { + cmdLine.add("-mktex=pk"); + cmdLine.add("-mktex=tex"); + cmdLine.add("-mktex=mf"); + cmdLine.add("-mktex=tfm"); + } + if (mfmode != null) { + cmdLine.add("-dpi=" + mfmode.getBdpi()); + cmdLine.add("-mode=" + mfmode.getMode()); + } + cmdLine.add(name); + + final ArrayList stderrData = new ArrayList(); + final ArrayList stdoutData = new ArrayList(); + CommandShell cs = new CommandShell(); + cs.setCommandLine(cmdLine); + cs.setHandler(new CommandShellHandler() { + public void handleStderr(InputStream in) throws IOException { + DviUtils.addLinesFromStream(stderrData, in, LOGGER, Level.FINE, System.err); + } + public void handleStdout(InputStream in) throws IOException { + DviUtils.addLinesFromStream(stdoutData, in); + } + public void handleStdin(OutputStream out) throws IOException { + out.close(); + } + }); + int ret = cs.execute(); + if (ret != 0) { + LOGGER.fine("kpsewhich command failed with retcode=" + ret + " cmdline=" + + DviUtils.join(" ", cmdLine) + " stderr=" + DviUtils.join("\n", stderrData)); + } else { + if (stdoutData.size() > 0) { + result = stdoutData.get(0); + } + } + } catch (Exception e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + } + + LOGGER.fine("kpsewhich result: name=" + name + " result=" + result); + + return result; + } + + + protected MetafontMode getMetafontMode() + throws DviException + { + MetafontMode mfmode = getDviContext().getDefaultMetafontMode(); + if (mfmode == null) { + mfmode = MetafontMode.FALLBACK; + } + return mfmode; + } + + public URL findURL(String name, boolean mustExist) throws MalformedURLException, DviException + { + if (!available) return null; + String path = findURLInternal(name, mustExist); + + if (path == null) return null; + + // The result kpsewhich returns is a POSIX absolute path to the resource in cygwin environment. + // Such a path does not work with the File class. So we have to convert it by + // running the command: cygpath -w + + File file = null; + switch (type) { + case KPSEWHICH_TYPE_DEFAULT: + file = new File(path); + break; + case KPSEWHICH_TYPE_CYGWIN: + file = fromPosixPathCygwin(path); + break; + case KPSEWHICH_TYPE_WINDOWS_SLASH: + file = replaceSlashInWindows(path); + break; + default: + throw new InternalError("unknown kpsewhich type: " + type); + } + + if (mustExist) { + if (!file.exists()) { + file = null; + } + } + + if (file != null) { + return file.toURL(); + } + + return null; + } + + public void setUseMktexThroughKpsewhich(boolean useMktexCommand) { + this.useMktexCommand = useMktexCommand; + } + + public boolean useMktexThroughKpsewhich() { + return useMktexCommand; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/ctx/SimpleJisToUnicodeMapper.java b/src/jp/sourceforge/dvibrowser/dvicore/ctx/SimpleJisToUnicodeMapper.java new file mode 100644 index 0000000..6c7c181 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/ctx/SimpleJisToUnicodeMapper.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.ctx; + +import java.io.UnsupportedEncodingException; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.api.CharacterCodeMapper; +import jp.sourceforge.dvibrowser.dvicore.font.LogicalFont; + + +public class SimpleJisToUnicodeMapper implements CharacterCodeMapper { + public String mapCharacterCodeToUnicode(LogicalFont logicalFont, int jis) + throws DviException + { + if (jis < 0x2120) { + return String.valueOf((char) jis); + } + + try { + String unicode = new String(new byte[] { + (byte)(((jis >> 8) & 0xff) + 0x80), + (byte)((jis & 0xff) + 0x80) + } + , "EUC-JP" + ); + return unicode; + } catch (UnsupportedEncodingException e) { + throw new DviException(e); + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/ctx/Type1DefaultCharacterCodeMapper.java b/src/jp/sourceforge/dvibrowser/dvicore/ctx/Type1DefaultCharacterCodeMapper.java new file mode 100644 index 0000000..828a163 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/ctx/Type1DefaultCharacterCodeMapper.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.ctx; + +import java.io.IOException; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.api.CharacterCodeMapper; +import jp.sourceforge.dvibrowser.dvicore.font.LogicalFont; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; +import jp.sourceforge.dvibrowser.dvicore.util.csv.CsvCellCodec; +import jp.sourceforge.dvibrowser.dvicore.util.csv.CsvData; +import jp.sourceforge.dvibrowser.dvicore.util.csv.CsvException; + + +public class Type1DefaultCharacterCodeMapper implements CharacterCodeMapper { + private static final Logger LOGGER = Logger.getLogger(Type1DefaultCharacterCodeMapper.class.getName()); + + public static final String ENC_OT1 = "ot1-enc"; + public static final String ENC_CMSY = "cmsy-enc"; + public static final String ENC_CMMI = "cmmi-enc"; + public static final String ENC_CMEX = "cmex-enc"; + public static final String ENC_CMTT = "cmtt-enc"; + public static final String ENC_T2 = "t2-enc"; + public static final String ENC_CORK = "cork-enc"; + public static final String ENC_TS1 = "ts1-enc"; + public static final String ENC_YFRAK = "yfrak-enc"; + + private int [] table = null; + + private final String encName; + + public Type1DefaultCharacterCodeMapper(String encName) + { + this.encName = encName; + } + + public String mapCharacterCodeToUnicode(LogicalFont logicalFont, int codePoint) + throws DviException + { + try { + codePoint = mapCodePoint(codePoint); + } catch (IOException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + throw new DviException(e); + } catch (CsvException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + throw new DviException(e); + } + if (Character.charCount(codePoint) == 1) { + return String.valueOf((char) codePoint); + } else { + return new String(Character.toChars(codePoint)); + } + } + + protected int mapCodePoint(int codePoint) throws IOException, CsvException, DviException { + initTable(); + if (codePoint < table.length) { + return table[codePoint]; + } + return codePoint; + } + + private synchronized void initTable() throws IOException, CsvException, DviException + { + if (table == null) { + doInitTable(); + } + } + + private void doInitTable() throws IOException, CsvException, DviException { + CsvData data = new CsvData(new CsvCellCodec() { + public String decodeKey(String s) { + return s; + } + + public String encodeKey(String key) { + return key; + } + + public Integer decodeValue(String key, String s) { + return Integer.decode(s); + } + + public String encodeValue(String key, Integer value) { + return String.format("0x%x", value.intValue()); + } + }); + URL url = getEncodingCsvFile(getTexEncodingName()); + data.readFromStream(url.openStream()); + table = new int [128]; + for (int i=0; i%06x\n", texchar, pfbchar)); + } else { + throw new DviException + ("texchar value out of range: " + texchar); + } + } + } + + protected URL getEncodingCsvFile(String texEncodingName) { + String filename = texEncodingName + ".csv"; + URL url = getClass().getResource(filename); + return url; + } + + public String getTexEncodingName() { + return encName; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/ctx/UnicodeCharacterCodeMapper.java b/src/jp/sourceforge/dvibrowser/dvicore/ctx/UnicodeCharacterCodeMapper.java new file mode 100644 index 0000000..3559bf6 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/ctx/UnicodeCharacterCodeMapper.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.ctx; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.api.CharacterCodeMapper; +import jp.sourceforge.dvibrowser.dvicore.font.LogicalFont; + +public class UnicodeCharacterCodeMapper implements CharacterCodeMapper { + public String mapCharacterCodeToUnicode(LogicalFont logicalFont, int codePoint) + throws DviException + { + if (Character.charCount(codePoint) == 1) { + return String.valueOf((char) codePoint); + } else { + return new String(Character.toChars(codePoint)); + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/ctx/cmsy-enc.csv b/src/jp/sourceforge/dvibrowser/dvicore/ctx/cmsy-enc.csv new file mode 100644 index 0000000..1794c60 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/ctx/cmsy-enc.csv @@ -0,0 +1 @@ +texchar,pfbchar 0x00,0x2212 0x01,0x00b7 0x02,0x00d7 0x03,0x2217 0x04,0x00f7 0x05,0x0000 0x06,0x00b1 0x07,0x0000 0x08,0x2295 0x09,0x0000 0x0a,0x2297 0x0b,0x0000 0x0c,0x0000 0x0d,0x0000 0x0e,0x0000 0x0f,0x2022 0x10,0x0000 0x11,0x2261 0x12,0x2286 0x13,0x2287 0x14,0x2264 0x15,0x2265 0x16,0x0000 0x17,0x0000 0x18,0x223c 0x19,0x2248 0x1a,0x2282 0x1b,0x2283 0x1c,0x0000 0x1d,0x0000 0x1e,0x0000 0x1f,0x0000 0x20,0x2190 0x21,0x2192 0x22,0x2191 0x23,0x2193 0x24,0x2194 0x25,0x0000 0x26,0x0000 0x27,0x0000 0x28,0x21d0 0x29,0x21d2 0x2a,0x21d1 0x2b,0x21d3 0x2c,0x21d4 0x2d,0x0000 0x2e,0x0000 0x2f,0x221d 0x30,0x0000 0x31,0x221e 0x32,0x2208 0x33,0x0000 0x34,0x0000 0x35,0x0000 0x36,0x0000 0x37,0x0000 0x38,0x2200 0x39,0x2203 0x3a,0x00ac 0x3b,0x2205 0x3c,0x0000 0x3d,0x0000 0x3e,0x0000 0x3f,0x22a5 0x40,0x2135 0x41,0x0041 0x42,0x0042 0x43,0x0043 0x44,0x0044 0x45,0x0045 0x46,0x0046 0x47,0x0047 0x48,0x0048 0x49,0x0049 0x4a,0x004a 0x4b,0x004b 0x4c,0x004c 0x4d,0x004d 0x4e,0x004e 0x4f,0x004f 0x50,0x0050 0x51,0x0051 0x52,0x0052 0x53,0x0053 0x54,0x0054 0x55,0x0055 0x56,0x0056 0x57,0x0057 0x58,0x0058 0x59,0x0059 0x5a,0x005a 0x5b,0x222a 0x5c,0x2229 0x5d,0x0000 0x5e,0x2227 0x5f,0x2228 0x60,0x0000 0x61,0x0000 0x62,0x0000 0x63,0x0000 0x64,0x0000 0x65,0x0000 0x66,0x007b 0x67,0x007d 0x68,0x0000 0x69,0x0000 0x6a,0x007c 0x6b,0x0000 0x6c,0x0000 0x6d,0x0000 0x6e,0x005c 0x6f,0x0000 0x70,0x221a 0x71,0x0000 0x72,0x0000 0x73,0x222b 0x74,0x0000 0x75,0x0000 0x76,0x0000 0x77,0x0000 0x78,0x00a7 0x79,0x2020 0x7a,0x2021 0x7b,0x00b6 0x7c,0x2663 0x7d,0x2666 0x7e,0x2665 0x7f,0x2660 \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/ctx/default-context.properties b/src/jp/sourceforge/dvibrowser/dvicore/ctx/default-context.properties new file mode 100644 index 0000000..a8d82bb --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/ctx/default-context.properties @@ -0,0 +1,11 @@ +jp.sourceforge.dvibrowser.dvicore.ctx.DefaultDviContext.fontMap.rml = dvicore-awt-dynamic-pk-font-serif +jp.sourceforge.dvibrowser.dvicore.ctx.DefaultDviContext.fontMap.ryumin-l = dvicore-awt-dynamic-pk-font-serif +jp.sourceforge.dvibrowser.dvicore.ctx.DefaultDviContext.fontMap.rmlv = dvicore-awt-dynamic-pk-font-serif +jp.sourceforge.dvibrowser.dvicore.ctx.DefaultDviContext.fontMap.jis = dvicore-awt-dynamic-pk-font-serif +jp.sourceforge.dvibrowser.dvicore.ctx.DefaultDviContext.fontMap.jisv = dvicore-awt-dynamic-pk-font-serif +jp.sourceforge.dvibrowser.dvicore.ctx.DefaultDviContext.fontMap.gtbbb-m = dvicore-awt-dynamic-pk-font-sans-serif +jp.sourceforge.dvibrowser.dvicore.ctx.DefaultDviContext.fontMap.gbm = dvicore-awt-dynamic-pk-font-sans-serif +jp.sourceforge.dvibrowser.dvicore.ctx.DefaultDviContext.fontMap.gbmv = dvicore-awt-dynamic-pk-font-sans-serif +jp.sourceforge.dvibrowser.dvicore.ctx.DefaultDviContext.fontMap.jisg = dvicore-awt-dynamic-pk-font-sans-serif +jp.sourceforge.dvibrowser.dvicore.ctx.DefaultDviContext.fontMap.jisgv = dvicore-awt-dynamic-pk-font-sans-serif +jp.sourceforge.dvibrowser.dvicore.special.EPS2ImagePreparator.preservePS = true diff --git a/src/jp/sourceforge/dvibrowser/dvicore/ctx/ot1-enc.csv b/src/jp/sourceforge/dvibrowser/dvicore/ctx/ot1-enc.csv new file mode 100644 index 0000000..aef8f6e --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/ctx/ot1-enc.csv @@ -0,0 +1 @@ +texchar,pfbchar 0x00,0x0393 0x01,0x0394 0x02,0x0398 0x03,0x039b 0x04,0x039e 0x05,0x03a0 0x06,0x03a3 0x07,0x03a5 0x08,0x03a6 0x09,0x03a8 0x0a,0x03a9 0x0b,0xfb00 0x0c,0xfb01 0x0d,0xfb02 0x0e,0xfb03 0x0f,0xfb04 0x10,0x200d 0x11,0x0237 0x12,0x0060 0x13,0x00b4 0x14,0x02c7 0x15,0x02d8 0x16,0x00af 0x17,0x02da 0x18,0x00b8 0x19,0x00df 0x1a,0x00e6 0x1b,0x0153 0x1c,0x00f8 0x1d,0x00c6 0x1e,0x0152 0x1f,0x00d8 0x20,0x0020 0x21,0x0021 0x22,0x201d 0x23,0x0023 0x24,0x0024 0x25,0x0025 0x26,0x0026 0x27,0x2019 0x28,0x0028 0x29,0x0029 0x2a,0x002a 0x2b,0x002b 0x2c,0x002c 0x2d,0x002d 0x2e,0x002e 0x2f,0x002f 0x30,0x0030 0x31,0x0031 0x32,0x0032 0x33,0x0033 0x34,0x0034 0x35,0x0035 0x36,0x0036 0x37,0x0037 0x38,0x0038 0x39,0x0039 0x3a,0x003a 0x3b,0x003b 0x3c,0x00a1 0x3d,0x003d 0x3e,0x00bf 0x3f,0x003f 0x40,0x0040 0x41,0x0041 0x42,0x0042 0x43,0x0043 0x44,0x0044 0x45,0x0045 0x46,0x0046 0x47,0x0047 0x48,0x0048 0x49,0x0049 0x4a,0x004a 0x4b,0x004b 0x4c,0x004c 0x4d,0x004d 0x4e,0x004e 0x4f,0x004f 0x50,0x0050 0x51,0x0051 0x52,0x0052 0x53,0x0053 0x54,0x0054 0x55,0x0055 0x56,0x0056 0x57,0x0057 0x58,0x0058 0x59,0x0059 0x5a,0x005a 0x5b,0x005b 0x5c,0x201c 0x5d,0x005d 0x5e,0x02c6 0x5f,0x02d9 0x60,0x2018 0x61,0x0061 0x62,0x0062 0x63,0x0063 0x64,0x0064 0x65,0x0065 0x66,0x0066 0x67,0x0067 0x68,0x0068 0x69,0x0069 0x6a,0x006a 0x6b,0x006b 0x6c,0x006c 0x6d,0x006d 0x6e,0x006e 0x6f,0x006f 0x70,0x0070 0x71,0x0071 0x72,0x0072 0x73,0x0073 0x74,0x0074 0x75,0x0075 0x76,0x0076 0x77,0x0077 0x78,0x0078 0x79,0x0079 0x7a,0x007a 0x7b,0x2013 0x7c,0x2014 0x7d,0x02dd 0x7e,0x02dc 0x7f,0x00a8 \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/doc/DefaultDviPage.java b/src/jp/sourceforge/dvibrowser/dvicore/doc/DefaultDviPage.java new file mode 100644 index 0000000..f7d9723 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/doc/DefaultDviPage.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.doc; + +import jp.sourceforge.dvibrowser.dvicore.DviByteRange; +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontTable; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviUnit; +import jp.sourceforge.dvibrowser.dvicore.api.DviDocument; +import jp.sourceforge.dvibrowser.dvicore.api.DviInput; +import jp.sourceforge.dvibrowser.dvicore.api.DviPage; + +public final class DefaultDviPage +extends DviObject +implements DviPage//, java.io.Serializable +{ + private final DviDocument doc; + private final long bop; + private final long eop; + private final int pageNum; + + DefaultDviPage(DviDocument doc, int pageNum, long bop, long eop) + { + super(doc); + this.doc = doc; + this.pageNum = pageNum; + this.bop = bop; + this.eop = eop; + } + + public DviDocument getDocument() { return doc; } + public DviUnit getDviUnit() throws DviException { return doc.getDviUnit(); } + public DviFontTable getFontTable() throws DviException { return doc.getFontTable(); } + public DviByteRange range() { return new DviByteRange(bop, eop); } + public int getPageNumber() { return pageNum; } + + public DviInput getInput() + throws DviException + { + return doc.getInput(bop, eop); + } + + public String toString() + { + return getClass().getName() + "[pageNum=" + pageNum + ",bop=" + bop + ",eop=" + eop + "]"; + } + + public long getDataSize() throws DviException + { + return (eop - bop + 1); + } + + public DviInput getInput(long start, long end) throws DviException + { + return doc.getInput(bop + start, bop + end); + } +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/doc/DirectFileDviDocument.java b/src/jp/sourceforge/dvibrowser/dvicore/doc/DirectFileDviDocument.java new file mode 100644 index 0000000..b0c1258 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/doc/DirectFileDviDocument.java @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.doc; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; + +import jp.sourceforge.dvibrowser.dvicore.DviConstants; +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.DviFontTable; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviUnit; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviDocument; +import jp.sourceforge.dvibrowser.dvicore.api.DviInput; +import jp.sourceforge.dvibrowser.dvicore.api.DviPage; +import jp.sourceforge.dvibrowser.dvicore.api.HasURL; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviCommand; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostPost; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostamble; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPreamble; +import jp.sourceforge.dvibrowser.dvicore.io.ByteArrayDviData; +import jp.sourceforge.dvibrowser.dvicore.io.DviRandomAccessFileInput; +import jp.sourceforge.dvibrowser.dvicore.render.EmptyDviExecutorHandler; + + +// TODO: Optimize this class. It's really slow for a large file. +public class DirectFileDviDocument +extends DviObject +implements DviDocument, HasURL +{ + public static final long MAX_BUFFER_LENGTH = 10000000; + /* Buffer size for the data after postamble. 10MB */ + + private final File file; + + private DviPreamble preamble = null; + private DviPostamble postamble = null; + private DviPostPost postPost = null; + + final DviFontTable fontTable = new DviFontTable(); + + private ArrayList pages = new ArrayList(); + + public DirectFileDviDocument(DviContextSupport dcs, File file) + throws DviException + { + super(dcs); + this.file = file; + try { + RandomAccessFile in = new RandomAccessFile(file, "r"); + parseRandomAccessFile(in); + in.close(); + } catch (IOException ex) { + throw new DviException(ex); + } + } + + private void parseRandomAccessFile(RandomAccessFile in) + throws IOException, DviException + { + // Parse the preamble. + { + int idByte, num, den, mag, k; + byte [] comment; + + if (DviCommand.DVI_PRE != in.readUnsignedByte()) + throw new DviException + ("Format error in dvi file: file doesn't start with pre."); + + idByte = in.readUnsignedByte(); + num = in.readInt(); + den = in.readInt(); + mag = in.readInt(); + + k = in.readUnsignedByte(); + comment = new byte[k]; + in.readFully(comment); + + preamble = new DviPreamble( + idByte, DviUnit.getInstance(num, den, mag), comment); + } + + // Determine the location of the postamble. + final long postPostPointer; + { + long pos = in.length() - 1; + int postamblePointer; + int idByte; + + long paddingSize = 0; + + while (true) { + if (pos < 0) + throw new DviException( + "Dvi file ended while looking for the postamble."); + in.seek(pos); + if (DviConstants.DVI_TRAILER != in.readUnsignedByte()) break; + paddingSize++; + pos--; + } + pos -= 5; + if (pos < 0) + throw new DviException( + "Dvi file ended while looking for the postamble."); + + postPostPointer = pos; + + /* pos -> +0 DVI_POST_POST (U1) + * +1 post_offset (U4) + * +5 id_byte (U1) + * +6 padding paddingSize copies of ((byte)223). + */ + in.seek(pos); + + if (DviCommand.DVI_POST_POST != in.readUnsignedByte()) + throw new DviException( + "Format error in dvi file: unable to find post_post."); + + postamblePointer = in.readInt(); + if (postamblePointer < 0 || + (long) postamblePointer > in.length() - 33) + throw new DviException( + "Format error in dvi file: file size too short."); + + /* TODO: check id_byte */ + idByte = in.readUnsignedByte(); + + postPost = new DviPostPost(postamblePointer, idByte); + } + + in.seek(postPost.postamblePointer()); + + /* pos -> + 0 DVI_POST (U1) + * + 1 bp (S4) + * + 5 num (S4) + * + 9 den (S4) + * +13 mag (S4) + * +17 maxV (S4) + * +21 maxH (S4) + * +25 max_stack_depth (U2) + * +27 total_pages (U2) + * size = 29 bytes. + */ + + if (DviCommand.DVI_POST != in.readUnsignedByte()) + throw new DviException( + "Format error in dvi file: unable to find post."); + + { + int bp; + int num, den, mag; + int maxV, maxH, maxStackDepth, totalPages; + + bp = in.readInt(); + num = in.readInt(); + den = in.readInt(); + mag = in.readInt(); + maxV = in.readInt(); + maxH = in.readInt(); + maxStackDepth = in.readUnsignedShort(); + totalPages = in.readUnsignedShort(); + + postamble = new DviPostamble( + bp, DviUnit.getInstance(num, den, mag), + maxV, maxH, maxStackDepth, totalPages); + } + + // parse font definitions stored right after the postamble. + + { + long buflen = postPostPointer - in.getFilePointer(); + if (0 < buflen) { + if (buflen > MAX_BUFFER_LENGTH) + throw new DviException + ("Too long data after postamble."); + + final byte [] buf = new byte [(int) buflen]; + in.readFully(buf); + + getDviContext().execute( + new ByteArrayDviData(buf), + new EmptyDviExecutorHandler() { + public void doDefineFont(int fn, DviFontSpec fs) { + fontTable.put(fn, fs); + } + } + ); + } + } + + // TODO: handle embedded data. + + { + long bop = postamble.firstBackPointer(); + long eop = postPost.postamblePointer() - 1; + int pageNum = postamble.totalPages(); + + while (bop != -1 && pageNum > 0) { + in.seek(bop); + + if (DviCommand.DVI_BOP != in.readUnsignedByte()) + throw new DviException( + "Format error in dvi file: broken bop link."); + + pageNum--; + // REMARK: pageNum==0 corresponds to the first page. + pages.add(0, new DefaultDviPage(DirectFileDviDocument.this, pageNum, bop, eop)); + + eop = bop - 1; + in.seek(bop + 1 + 4 * 10); + bop = in.readInt(); + } + + if (pageNum != 0) + throw new DviException( + "Format error in dvi file: wrong number of pages."); + } + } + + public int getTotalPages() throws DviException { + return postamble.totalPages(); + } + + public DviUnit getDviUnit() { + return postamble.dviUnit(); + } + public DviPreamble getPreamble() { + return preamble; + } + public DviPostamble getPostamble() { + return postamble; + } + public DviPostPost getPostPost() { + return postPost; + } + public DviFontTable getFontTable() { + return fontTable; + } + + public DviInput getInput() + throws DviException + { + try { + RandomAccessFile raf = new RandomAccessFile(getFile(), "r"); + DviRandomAccessFileInput in = new DviRandomAccessFileInput(raf); + return in; + } catch (FileNotFoundException e) { + throw new DviException(e); + } + } + + public DviInput getInput(long start, long end) throws DviException + { + try { + RandomAccessFile raf = new RandomAccessFile(getFile(), "r"); + raf.seek(start); + DviRandomAccessFileInput in = new DviRandomAccessFileInput(raf); + in.setOffset(start); + in.setEnd(end); + return in; + } catch (FileNotFoundException e) { + throw new DviException(e); + } catch (IOException e) { + throw new DviException(e); + } + } + +// private DviInput getInputNIO(long start, long end) +// throws DviException +// { +// try { +// FileInputStream fis = new FileInputStream(file); +// FileChannel fc = fis.getChannel(); +// MappedByteBuffer bb = fc.map( +// FileChannel.MapMode.READ_ONLY, +// start, end - start + 1 +// ); +// DviByteBufferInput in = new DviByteBufferInput(bb); +// in.setOffset(start); +// return in; +// } catch (Throwable ex) { +// Logger.trace(ex); +// return getInput(start, end); +// } +// } + + public DviPage getPage(int p) + throws DviException + { + if (p < 0 || getTotalPages() <= p) + throw new IllegalArgumentException + ("page number out of bounds."); + + return pages.get(p); + } + + public DviPage [] getPages() + { + return pages.toArray(new DviPage [0]); + } + + public long getDataSize() throws DviException + { + return getFile().length(); + } + + public File getFile() + { + return file; + } + + public URL getURL() throws DviException + { + try { + return file.toURL(); + } catch (MalformedURLException e) { + throw new DviException(e); + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/doc/StreamDviDocument.java b/src/jp/sourceforge/dvibrowser/dvicore/doc/StreamDviDocument.java new file mode 100644 index 0000000..1c13b82 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/doc/StreamDviDocument.java @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.doc; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.DviFontTable; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviUnit; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviData; +import jp.sourceforge.dvibrowser.dvicore.api.DviDocument; +import jp.sourceforge.dvibrowser.dvicore.api.DviExecutorContext; +import jp.sourceforge.dvibrowser.dvicore.api.DviInput; +import jp.sourceforge.dvibrowser.dvicore.api.DviPage; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviBop; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostPost; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostamble; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPreamble; +import jp.sourceforge.dvibrowser.dvicore.io.DviInputStreamReader; +import jp.sourceforge.dvibrowser.dvicore.render.EmptyDviExecutorHandler; + + +// TODO: support document cache +public class StreamDviDocument +extends DviObject +implements DviDocument //, java.io.Serializable +{ + public static final long MAX_BUFFER_LENGTH = 10000000; /* 10MB */ + + private DviPreamble preamble = null; + private DviPostamble postamble = null; + private DviPostPost postPost = null; + + private byte [] buf = null; + + final DviFontTable fontTable = new DviFontTable(); + + private ArrayList pages = new ArrayList(); + + public StreamDviDocument(DviContextSupport dcs, InputStream in) + throws DviException + { + super(dcs); + try { + parseInputStream(in); + } catch (IOException ex) { + throw new DviException(ex); + } + } + + private void parseInputStream(InputStream is) + throws IOException, DviException + { + final MyInputStream mis = new MyInputStream(is); + final DviInputStreamReader in = new DviInputStreamReader(mis); + + getDviContext().execute( + new DviData() { + public DviInput getInput() { return in; } + public DviFontTable getFontTable() { throw new UnsupportedOperationException(); } + public DviUnit getDviUnit() { throw new UnsupportedOperationException(); } + public long getDataSize() throws DviException + { + throw new UnsupportedOperationException(); + } + public DviInput getInput(long start, long end) throws DviException + { + throw new UnsupportedOperationException(); + } + }, + new EmptyDviExecutorHandler() { + private int pageNum=0; + private DviExecutorContext ctx; + public void begin(DviExecutorContext ctx) { + this.ctx = ctx; + } + public void end() { + this.ctx = null; + } + public void doPre(DviPreamble pre) { + preamble = pre; + } + public void doPost(DviPostamble post) { + postamble = post; + } + public void doPostPost(DviPostPost pp) { + postPost = pp; + ctx.setTerminate(true); + } + private long bop; + public void doBop(DviBop bop) { + this.bop = ctx.getCommandRange().begin(); + } + public void doEop() { + long eop = ctx.getCommandRange().begin(); + DviDocument doc = StreamDviDocument.this; + if (doc.getDviContext() instanceof URLDviDocument) { + doc = (URLDviDocument) doc.getDviContext(); + } + DviPage page = createPage(pageNum, bop, eop); + pages.add(page); + pageNum++; + } + public void doDefineFont(int fn, DviFontSpec fs) { + fontTable.put(fn, fs); + } + } + ); + if (preamble == null) + throw new DviException + ("no preamble found in the stream."); + + if (postamble == null) + throw new DviException + ("no postamble found in the stream."); + + if (postPost == null) + throw new DviException + ("no postPost found in the stream."); + + buf = mis.baos.toByteArray(); + } + + protected DviPage createPage(int pageNum, long bop, long eop) + { + return new DefaultDviPage(this, pageNum, bop, eop); + } + + private static class MyInputStream + extends FilterInputStream + { + public MyInputStream(InputStream is) { super(is); } + private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + public int read() + throws IOException + { + int c = super.read(); + baos.write(c); + return c; + } + + public int read(byte [] b, int off, int len) + throws IOException + { + int r = super.read(b, off, len); + if (r > 0) { + baos.write(b, off, r); + } + return r; + } + public void reset() + throws IOException + { + throw new UnsupportedOperationException(); + } + public long skip(long n) + throws IOException + { + throw new UnsupportedOperationException(); + } + public boolean markSupported() + { + return false; + } + } + + public int getTotalPages() throws DviException { + return postamble.totalPages(); + } + + public DviUnit getDviUnit() { + return postamble.dviUnit(); + } + public DviPreamble getPreamble() { + return preamble; + } + public DviPostamble getPostamble() { + return postamble; + } + public DviPostPost getPostPost() { + return postPost; + } + public DviFontTable getFontTable() { + return fontTable; + } + + public DviInput getInput() + throws DviException + { + ByteArrayInputStream bais = new ByteArrayInputStream(buf); + return new DviInputStreamReader(bais); + } + + public long getDataSize() + { + return buf.length; + } + + public DviInput getInput(long start, long end) + throws DviException + { + DviInputStreamReader in = new DviInputStreamReader( + new ByteArrayInputStream( + this.buf, (int) start, (int)(end - start) + 1 + ) + ); + in.setOffset(start); + return in; + } + + public DviPage getPage(int p) + throws DviException + { + if (p < 0 || getTotalPages() <= p) + throw new IllegalArgumentException + ("page number out of bounds."); + + return pages.get(p); + } + + public DviPage [] getPages() + { + return pages.toArray(new DviPage [pages.size()]); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/doc/URLDviDocument.java b/src/jp/sourceforge/dvibrowser/dvicore/doc/URLDviDocument.java new file mode 100644 index 0000000..aac4149 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/doc/URLDviDocument.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.doc; +import java.io.IOException; +import java.net.URL; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontTable; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviUnit; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviDocument; +import jp.sourceforge.dvibrowser.dvicore.api.DviInput; +import jp.sourceforge.dvibrowser.dvicore.api.DviPage; +import jp.sourceforge.dvibrowser.dvicore.api.HasURL; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostPost; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostamble; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPreamble; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + + +// TODO: make URLDviDocument a subclass of StreamDviDocument +public class URLDviDocument extends DviObject implements DviDocument, HasURL { +// private static final Logger LOGGER = Logger.getLogger(URLDviDocument.class +// .getName()); + + private final URL url; + private final DviDocument streamDoc; + + public URLDviDocument(DviContextSupport dcs, URL url) + throws DviException + { + super(dcs); + this.url = url; + try { + this.streamDoc = new StreamDviDocument(this, url.openStream()) { + @Override + protected DviPage createPage(int pageNum, long bop, long eop) { + return new DefaultDviPage(URLDviDocument.this, pageNum, bop, eop); + } + }; + } catch (IOException e) { + throw new DviException(e); + } + } + + public DviPage getPage(int p) throws DviException + { + return streamDoc.getPage(p); + } + + public DviPage[] getPages() throws DviException + { + return streamDoc.getPages(); + } + + public DviPostPost getPostPost() throws DviException + { + return streamDoc.getPostPost(); + } + + public DviPostamble getPostamble() throws DviException + { + return streamDoc.getPostamble(); + } + + public DviPreamble getPreamble() throws DviException + { + return streamDoc.getPreamble(); + } + + public int getTotalPages() throws DviException + { + return streamDoc.getTotalPages(); + } + + public long getDataSize() throws DviException + { + return streamDoc.getDataSize(); + } + + public DviUnit getDviUnit() throws DviException + { + return streamDoc.getDviUnit(); + } + + public DviFontTable getFontTable() throws DviException + { + return streamDoc.getFontTable(); + } + + public DviInput getInput() throws DviException + { + return streamDoc.getInput(); + } + + public DviInput getInput(long start, long end) throws DviException + { + return streamDoc.getInput(start, end); + } + + public String getCacheKey() + { + return getClass().getName() + "--" + DviUtils.md5Hex(url.toExternalForm()) + + streamDoc.getCacheKey(); + } + + public URL getURL() throws DviException + { + return url; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/event/TDefaultEventModel.java b/src/jp/sourceforge/dvibrowser/dvicore/event/TDefaultEventModel.java new file mode 100644 index 0000000..e31870f --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/event/TDefaultEventModel.java @@ -0,0 +1,58 @@ +package jp.sourceforge.dvibrowser.dvicore.event; + +public class TDefaultEventModel +implements TEventModel +{ + private volatile TEventListener listeners = null; + + public void addListener(TEventListener l) + { + listeners = TEventMulticaster.add(listeners, l); + } + + public void addUniqueListener(TEventListener l) + { + removeListener(l); + addListener(l); + } + + public String dumpListeners() + { + if (listeners instanceof TEventMulticaster) { + return ((TEventMulticaster) listeners).toString(); + } else if (listeners == null) { + return "null"; + } else { + return listeners.toString(); + } + } + + public void removeListener(TEventListener l) + { + listeners = TEventMulticaster.remove(listeners, l); + } + + public void removeListeners() + { + listeners = null; + } + + public TEventListener getListeners() + { + return listeners; + } + + public void inheritListeners(TEventProcessor ep) + { + if (ep == null) return; + TEventModel em = ep.getEventModel(); + if (em == null) return; + addListener(em.getListeners()); + } + + public void processEvent(TEvent e) + { + if (listeners != null) + listeners.handleEvent(e); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/event/TEvent.java b/src/jp/sourceforge/dvibrowser/dvicore/event/TEvent.java new file mode 100644 index 0000000..5135f12 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/event/TEvent.java @@ -0,0 +1,18 @@ +package jp.sourceforge.dvibrowser.dvicore.event; + +// TODO: use java.awt.Event +public class TEvent +extends java.util.EventObject +{ + private static final long serialVersionUID = 6716360144019948710L; + + public TEvent(Object source) + { + super(source); + } + + public String toString() + { + return super.toString(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/event/TEventListener.java b/src/jp/sourceforge/dvibrowser/dvicore/event/TEventListener.java new file mode 100644 index 0000000..c0f7416 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/event/TEventListener.java @@ -0,0 +1,7 @@ +package jp.sourceforge.dvibrowser.dvicore.event; + +public interface TEventListener +//extends java.util.EventListener +{ + public void handleEvent(TEvent e); +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/event/TEventModel.java b/src/jp/sourceforge/dvibrowser/dvicore/event/TEventModel.java new file mode 100644 index 0000000..387fdd1 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/event/TEventModel.java @@ -0,0 +1,18 @@ +package jp.sourceforge.dvibrowser.dvicore.event; + +public interface TEventModel +{ + public void addListener(TEventListener l); + public void addUniqueListener(TEventListener l); + + public void removeListener(TEventListener l); + public void removeListeners(); + + public String dumpListeners(); + + public TEventListener getListeners(); + + public void inheritListeners(TEventProcessor ep); + + public void processEvent(TEvent e); +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/event/TEventMulticaster.java b/src/jp/sourceforge/dvibrowser/dvicore/event/TEventMulticaster.java new file mode 100644 index 0000000..1b98a78 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/event/TEventMulticaster.java @@ -0,0 +1,56 @@ +package jp.sourceforge.dvibrowser.dvicore.event; + +public class TEventMulticaster +implements TEventListener +{ + protected final TEventListener a, b; + + protected TEventMulticaster(TEventListener a, TEventListener b) + { + this.a = a; + this.b = b; + } + + public static TEventListener add(TEventListener a, TEventListener b) + { + if (a == null) return b; + if (b == null) return a; + return new TEventMulticaster(a, b); + } + + public static TEventListener remove(TEventListener a, TEventListener b) + { + if (a == null || a == b) { + return null; + } else if (a instanceof TEventMulticaster) { + return ((TEventMulticaster) a).remove(b); + } else { + return a; + } + } + + public void handleEvent(TEvent e) + { + a.handleEvent(e); + b.handleEvent(e); + } + + public String toString() + { + if (a == null) return b.toString(); + if (b == null) return a.toString(); + return "(" + a.toString() + "," + b.toString() + ")"; + } + + protected TEventListener remove(TEventListener o) + { + if (o == a) return b; + if (o == b) return a; + TEventListener a2 = remove(a, o); + TEventListener b2 = remove(b, o); + if (a2 == a && b2 == b) { + return this; + } + return add(a2, b2); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/event/TEventProcessor.java b/src/jp/sourceforge/dvibrowser/dvicore/event/TEventProcessor.java new file mode 100644 index 0000000..d85c045 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/event/TEventProcessor.java @@ -0,0 +1,6 @@ +package jp.sourceforge.dvibrowser.dvicore.event; + +public interface TEventProcessor +{ + public TEventModel getEventModel(); +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/event/TEventQueue.java b/src/jp/sourceforge/dvibrowser/dvicore/event/TEventQueue.java new file mode 100644 index 0000000..dc506e1 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/event/TEventQueue.java @@ -0,0 +1,16 @@ +package jp.sourceforge.dvibrowser.dvicore.event; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +public class TEventQueue +extends LinkedBlockingQueue +{ + private static final long serialVersionUID = -2631304249462595119L; + + public TEvent poll(long timeout) + throws InterruptedException + { + return poll(timeout, TimeUnit.MILLISECONDS); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/AWTDynamicPkFont.java b/src/jp/sourceforge/dvibrowser/dvicore/font/AWTDynamicPkFont.java new file mode 100644 index 0000000..1127ae1 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/AWTDynamicPkFont.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.awt.image.Raster; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.DviUnit; +import jp.sourceforge.dvibrowser.dvicore.api.CharacterCodeMapper; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + + +public class AWTDynamicPkFont +extends AbstractDynamicPkFont +{ + private static final Logger LOGGER = Logger.getLogger(AWTDynamicPkFont.class.getName()); + + private static final long serialVersionUID = 6218737476095318238L; + private final Font font; + private CharacterCodeMapper mapper; + private boolean renderBoundigBoxes = false; + + public AWTDynamicPkFont(DviContextSupport dcs, Font font) + throws DviException + { + this(dcs, font, null); + } + public AWTDynamicPkFont(DviContextSupport dcs, Font font, CharacterCodeMapper mapper) + throws DviException + { + super(dcs); + if (font == null) + throw new NullPointerException + ("font is null"); + this.font = font; + this.setCharacterCodeMapper(mapper); + } + + public boolean hasChar(int code) { return font.canDisplay(code); } + + protected String mapToUnicode(LogicalFont lf, int code) throws DviException + { + if (getCharacterCodeMapper() != null) { + return getCharacterCodeMapper().mapCharacterCodeToUnicode(lf, code); + } else { + return getDviContext().getCharacterCodeMapper(lf) + .mapCharacterCodeToUnicode(lf, code); + } + } + + protected PkGlyph generatePkGlyph(LogicalFont lf, int code) + throws DviException + { + String unicode = mapToUnicode(lf, code); + + LOGGER.finest("str=(" + unicode + ") code=0x" + Integer.toHexString(code) + + " hex=" + DviUtils.hexDump(unicode)); + + Graphics2D g; + BufferedImage img; + + // We instantiate an image to get Graphics2D. + img = new BufferedImage( + 1, 1, + BufferedImage.TYPE_BYTE_GRAY + ); + + DviUnit dviUnit = lf.dviUnit(); + DviFontSpec fs = lf.fontSpec(); + DviResolution res = lf.resolution(); + float fontSize = (float) dviUnit.mapToPixelDouble(fs.spaceSize(), res.dpi()); + Font derivedFont = font.deriveFont(fontSize); + +// System.out.println(Integer.toHexString(code) + "(" + unicode + "): " + derivedFont); + + g = img.createGraphics(); + FontMetrics fm = g.getFontMetrics(derivedFont); + int descent = fm.getMaxDescent(); + int ascent = fm.getMaxAscent(); + int leading = fm.getLeading(); + int maxAdvance = fm.getMaxAdvance(); + int maxAscent = fm.getMaxAscent(); + int maxDescent = fm.getMaxDescent(); + + Rectangle2D charBounds = fm.getMaxCharBounds(g); + Rectangle2D bounds = fm.getStringBounds(unicode, g); + Rectangle2D boundsByChars = fm.getStringBounds(unicode.toCharArray(), 0, 1, g); + int x = (int) Math.floor(bounds.getMinX()); + int y = (int) Math.floor(bounds.getMinY()); + int width = (int) (bounds.getWidth() + 0.5); + int height = (int) (bounds.getHeight() + 0.5); + //height = maxAscent + maxDescent; + height = (int)(charBounds.getHeight() + 0.5); + + int padding = 600; + + // padding = Math.max(maxAscent, maxDescent); + padding = (int) (charBounds.getHeight() + 0.5); + + y = - maxAscent; + + x += -padding - maxAdvance; + y += -padding; + width += padding * 2 + maxAdvance * 2; + height += padding * 2; + + int bw = width + 1; + int bh = height + 1; + +// System.out.println("codePoint=" + String.format("x0%06x", code)); +// System.out.println("bounds=" + bounds); +// System.out.println("charBounds=" + charBounds); +// System.out.println("padding=" + padding); +// System.out.println("boundsByChars=" + boundsByChars); +// System.out.println("maxAdvance=" + maxAdvance); +// System.out.println("ascent=" + ascent + " max=" + fm.getMaxAscent()); +// System.out.println("descent=" + descent + " max=" + fm.getMaxDescent()); +// System.out.println("leading=" + leading); +// System.out.println("width=" + width); +// System.out.println("height=" + height); +// System.out.println("(x, y)=(" + x + "," + y + ")"); + g.dispose(); + g = null; + + img = new BufferedImage( + bw, bh, + BufferedImage.TYPE_BYTE_GRAY + ); + g = img.createGraphics(); + g.setFont(derivedFont); + g.drawString(unicode, -x, -y); + if (renderBoundigBoxes()) { + g.drawRect(0, 0, width - 1, height - 1); + g.drawRect(0, 0, width - 1 , -y - 1); + g.drawRect(0, 0, -x - 1, height -1); + } + g.dispose(); + + Raster raster = img.getRaster(); + DataBufferByte data = (DataBufferByte) raster.getDataBuffer(); + RunLengthEncodedGlyph rlg = RunLengthEncodedGlyph.readByteGray( + data.getData(), + bw, bh, + -x, -y + ); + PkGlyph glyph = rlg.toPkGlyph(); +// System.out.println(code); +// BinaryDevice out = new dvi.render.DumpBinaryDevice(System.out); +// glyph.rasterizeTo(out); + return glyph; + } + public void setRenderBoundigBoxes(boolean renderBoundigBoxes) { + this.renderBoundigBoxes = renderBoundigBoxes; + } + public boolean renderBoundigBoxes() { + return renderBoundigBoxes; + } + public CharacterCodeMapper getCharacterCodeMapper() { + return mapper; + } + public void setCharacterCodeMapper(CharacterCodeMapper mapper) { + this.mapper = mapper; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/AWTDynamicPkFontResolver.java b/src/jp/sourceforge/dvibrowser/dvicore/font/AWTDynamicPkFontResolver.java new file mode 100644 index 0000000..0bc7c25 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/AWTDynamicPkFontResolver.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; +import java.awt.Font; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.DviUnit; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviFont; + + +public class AWTDynamicPkFontResolver +extends AbstractDviFontResolver +{ + private static final Logger LOGGER = Logger + .getLogger(AWTDynamicPkFontResolver.class.getName()); + + public AWTDynamicPkFontResolver(DviContextSupport dcs, LogicalFont logicalFont) { + super(dcs, logicalFont); + } + + @Override + public Collection call() throws Exception + { + Font rawFont = mapToRawAWTFont(getLogicalFont()); + List list = new ArrayList(); + if (rawFont != null) { + DviFont font = new AWTDynamicPkFont(getDviContext(), rawFont); + list.add(font); + } + return list; + } + + protected Font mapToRawAWTFont(LogicalFont logicalFont) + { + DviFontSpec fs = logicalFont.fontSpec(); + DviResolution res = logicalFont.resolution(); + DviUnit dviUnit = logicalFont.dviUnit(); + String face = mapToRawAWTFontFace(logicalFont); + if (face != null) { + LOGGER.fine("Using AWT font face " + face + " to render " + logicalFont); + final int fontSize = (int) dviUnit.mapToPixelDouble(fs.spaceSize(), res.dpi()); + if ("dvicore-awt-dynamic-pk-font-serif".equals(face)) { + LOGGER.fine("Using serif for" + logicalFont); + return new Font("serif", Font.PLAIN, fontSize); + } else if ("dvicore-awt-dynamic-pk-font-sans-serif".equals(face)) { + LOGGER.fine("Using sans-serif for" + logicalFont); + return new Font("sans-serif", Font.PLAIN, fontSize); + } else { + LOGGER.fine("No AWT font face to render " + logicalFont); + return new Font(face, Font.PLAIN, fontSize); + } + } else { + LOGGER.fine("No AWT font face to render " + logicalFont); + } + return null; + } + + + protected String mapToRawAWTFontFace(LogicalFont logicalFont) + { + return logicalFont.fontSpec().name(); + } + + @Override + public String getCacheKey() + { + LogicalFont spec = getLogicalFont(); + return spec.fontSpec().fontName() + + "-" + spec.fontSpec().checkSum() + + "-" + spec.fontSpec().spaceSize() + + "-" + spec.fontSpec().designSize() + + "-" + spec.resolution().dpi() + + "-" + spec.dviUnit() + ; + } + + @Override + protected DviFont createInstanceFromStream(InputStream openStream) + throws DviException + { + throw new UnsupportedOperationException(); + } + + @Override + protected String mapToDviResourceName(LogicalFont logicalFont) + { + throw new UnsupportedOperationException(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/AbstractDviFontResolver.java b/src/jp/sourceforge/dvibrowser/dvicore/font/AbstractDviFontResolver.java new file mode 100644 index 0000000..016d0d2 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/AbstractDviFontResolver.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; + +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviFont; +import jp.sourceforge.dvibrowser.dvicore.ctx.AbstractDviResourceResolver; + +public abstract class AbstractDviFontResolver +extends AbstractDviResourceResolver +{ + public AbstractDviFontResolver(DviContextSupport dcs, LogicalFont logicalFont) { + super(dcs, logicalFont); + } + + public LogicalFont getLogicalFont() + { + return getSpec(); + } + +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/AbstractDynamicPkFont.java b/src/jp/sourceforge/dvibrowser/dvicore/font/AbstractDynamicPkFont.java new file mode 100644 index 0000000..6c09cd8 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/AbstractDynamicPkFont.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Map; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviFont; +import jp.sourceforge.dvibrowser.dvicore.api.Glyph; + + +public abstract class AbstractDynamicPkFont +extends DviObject +implements DviFont +{ + private static final long serialVersionUID = -7653383398207050528L; + + public AbstractDynamicPkFont(DviContextSupport dcs) + throws DviException + { + super(dcs); + } + + // TODO: make the GlyphCache hierarchical so that we can discard + // glyphs of the same font simultaneously. + public Glyph getGlyph(LogicalFont lf, int code) + throws DviException + { + String key = lf.fontSpec().toString() + + "--" + lf.dviUnit().toString() + "--" + lf.resolution().dpi() + + "--" + code; + + Map cache = getDviContext().getGlyphCache(); + Glyph glyph = cache.get(key); + if (glyph != null) return glyph; + + //System.out.println("generating glyph: lf=" + lf + " code=" + code); + glyph = generatePkGlyph(lf, code); + cache.put(key, glyph); + + return glyph; + } + + protected abstract PkGlyph generatePkGlyph(LogicalFont lf, int code) + throws DviException; + + private void writeObject(ObjectOutputStream s) + throws IOException + { + s.defaultWriteObject(); + } + + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/AbstractMetricsResolver.java b/src/jp/sourceforge/dvibrowser/dvicore/font/AbstractMetricsResolver.java new file mode 100644 index 0000000..f4a5e47 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/AbstractMetricsResolver.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.ctx.AbstractDviResourceResolver; + +public abstract class AbstractMetricsResolver +extends AbstractDviResourceResolver +{ +// private static final Logger LOGGER = Logger +// .getLogger(AbstractMetricsResolver.class.getName()); +// + public AbstractMetricsResolver(DviContextSupport dcs, DviFontSpec fontSpec) { + super(dcs, fontSpec); + } + + public DviFontSpec getFontSpec() + { + return getSpec(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/DviFontResolver.java b/src/jp/sourceforge/dvibrowser/dvicore/font/DviFontResolver.java new file mode 100644 index 0000000..f157504 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/DviFontResolver.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Future; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.api.CharacterCodeMapper; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviFont; +import jp.sourceforge.dvibrowser.dvicore.ctx.BakomaUnicodeCharacterCodeMapper; +import jp.sourceforge.dvibrowser.dvicore.ctx.Type1DefaultCharacterCodeMapper; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.CacheEntry; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.CachedComputer; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.ThreadedComputer; +import jp.sourceforge.dvibrowser.dvicore.util.progress.ProgressItem; + + +public class DviFontResolver +extends AbstractDviFontResolver +{ + private static final Logger LOGGER = Logger + .getLogger(DviFontResolver.class.getName()); + + // TODO: set maximum number of fonts to cache. + // TODO: outsource the size configurations. + private static final CachedComputer> dviFontComputer + = new CachedComputer> + (new ThreadedComputer>(3)) { + @Override + protected boolean removeEldestEntry(Map.Entry>> entry) + { + boolean remove = getCache().size() > 64; + return remove; + } + }; + + private boolean trueTypeEnabled = false; + + private boolean type1Enabled = false; + + private boolean openTypeEnabled = false; + + private boolean pkEnabled = true; + + private static final CharacterCodeMapper defaultTrueTypeMapper = new BakomaUnicodeCharacterCodeMapper(); + private static final CharacterCodeMapper defaultType1Mapper + = new Type1DefaultCharacterCodeMapper(Type1DefaultCharacterCodeMapper.ENC_OT1); + + public DviFontResolver(DviContextSupport dcs, LogicalFont logicalFont) { + super(dcs, logicalFont); + } + + @Override + public Collection call() throws Exception + { + ProgressItem progress = getDviContext().getProgressRecorder().open( + "resolving " + getLogicalFont().fontSpec().name()); + try { + LOGGER.fine("Resolving DVI font " + getLogicalFont()); + LogicalFont mappedLogicalFont = getDviContext().mapLogicalFont( + getLogicalFont()); + LOGGER.fine("Mapped logical font is " + mappedLogicalFont); + List list = new ArrayList(); + { + // Note: We have to use the original logical font to find a virtual font. + { + Future> future = dviFontComputer + .compute(new VirtualFontResolver(this, getLogicalFont())); + list.addAll(future.get()); + } + + if (list.size() == 0 && openTypeEnabled()) { + TrueTypeFontResolver resolver = new TrueTypeFontResolver(this, mappedLogicalFont); + resolver.setFileExtension(".otf"); + Future> future = dviFontComputer.compute(resolver); + Collection fonts = future.get(); + list.addAll(fonts); + } + if (list.size() == 0 && type1Enabled) { + Future> future = dviFontComputer + .compute(new Type1FontResolver(this, mappedLogicalFont)); + Collection fonts = future.get(); + for (DviFont font : fonts) { + if (font instanceof AWTDynamicPkFont) { + ((AWTDynamicPkFont) font).setCharacterCodeMapper + (defaultType1Mapper); + } + list.add(font); + } + } + if (list.size() == 0 && trueTypeEnabled) { + Future> future = dviFontComputer + .compute(new TrueTypeFontResolver(this, mappedLogicalFont)); + Collection fonts = future.get(); + for (DviFont font : fonts) { + if (font instanceof AWTDynamicPkFont) { + ((AWTDynamicPkFont) font).setCharacterCodeMapper + (defaultTrueTypeMapper); + } + list.add(font); + } + } + + if (list.size() == 0 && pkEnabled() ) { + Future> future = dviFontComputer + .compute(new PkFontResolver(this, mappedLogicalFont)); + list.addAll(future.get()); + } + + if (list.size() == 0) { + Future> future = dviFontComputer + .compute(new AWTDynamicPkFontResolver(this, mappedLogicalFont)); + list.addAll(future.get()); + } + } + return list; + } finally { + progress.close(); + } + } + + @Override + public String getCacheKey() + { + LogicalFont spec = getLogicalFont(); + return spec.fontSpec().fontName() + + "-" + spec.fontSpec().checkSum() + + "-" + spec.fontSpec().spaceSize() + + "-" + spec.fontSpec().designSize() + + "-" + spec.resolution().dpi() + + "-" + spec.dviUnit() + ; + } + + @Override + protected DviFont createInstanceFromStream(InputStream openStream) + throws DviException + { + throw new UnsupportedOperationException(); + } + + @Override + protected String mapToDviResourceName(LogicalFont logicalFont) + { + throw new UnsupportedOperationException(); + } + + public void setOpenTypeEnabled(boolean openTypeEnabled) { + this.openTypeEnabled = openTypeEnabled; + } + + public boolean openTypeEnabled() { + return openTypeEnabled; + } + + public void setPkEnabled(boolean pkEnabled) { + this.pkEnabled = pkEnabled; + } + + public boolean pkEnabled() { + return pkEnabled; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/FullMetricsResolver.java b/src/jp/sourceforge/dvibrowser/dvicore/font/FullMetricsResolver.java new file mode 100644 index 0000000..21674ae --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/FullMetricsResolver.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; +import java.io.InputStream; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.FullMetrics; + + +public class FullMetricsResolver extends AbstractMetricsResolver { +// private static final Logger LOGGER = Logger +// .getLogger(FullMetricsResolver.class.getName()); + + public FullMetricsResolver(DviContextSupport dcs, DviFontSpec fontSpec) { + super(dcs, fontSpec); + } + + @Override + protected FullMetrics createInstanceFromStream(InputStream openStream) + throws DviException + { + return new TexFontMetrics(this, openStream); + } + + @Override + protected String mapToDviResourceName(DviFontSpec spec) + { + return TexFontMetrics.getTfmFilename(spec); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/LogicalFont.java b/src/jp/sourceforge/dvibrowser/dvicore/font/LogicalFont.java new file mode 100644 index 0000000..d32548a --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/LogicalFont.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; + +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.DviUnit; +import jp.sourceforge.dvibrowser.dvicore.util.Canonicalizer; +import jp.sourceforge.dvibrowser.dvicore.util.SimpleCanonicalizer; + +// immutable + +public final class LogicalFont +implements java.io.Serializable +{ + private static final long serialVersionUID = -8543173850765210687L; + private final DviFontSpec fs; + private final DviUnit dviUnit; + private final DviResolution res; + + private LogicalFont(DviFontSpec fs, DviUnit dviUnit, DviResolution res) { + this.fs = fs; + this.dviUnit = dviUnit; + this.res = res; + if (fs == null) throw new IllegalArgumentException("font spec cannot be null"); + if (dviUnit == null) throw new IllegalArgumentException("DVI unit cannot be null"); + if (res == null) throw new IllegalArgumentException("resolution cannot be null"); + } + + private static final Canonicalizer canonicalizer + = new SimpleCanonicalizer(); + + public static LogicalFont getInstance( + DviFontSpec fs, DviUnit dviUnit, DviResolution res) + { + return canonicalizer.canonicalize( + new LogicalFont(fs, dviUnit, res) + ); + } + + public DviFontSpec fontSpec() { return fs; } + public DviUnit dviUnit() { return dviUnit; } + public DviResolution resolution() { return res; } + + private String string = null; + public String toString() { + if (string == null) { + string = getClass().getName() + + "[" + fs + "," + dviUnit + "," + res + "]" + ; + } + return string; + } + + public LogicalFont renameTo(String newName) + { + return getInstance(fs.rename(newName), dviUnit, res); + } + + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj instanceof LogicalFont) { + LogicalFont lf = (LogicalFont) obj; + return fs.equals(lf.fs) && + dviUnit.equals(lf.dviUnit) && + res.equals(lf.res); + } + return false; + } + + public int hashCode() { + return fs.hashCode() + 33*(dviUnit.hashCode() + 33*res.hashCode()); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/LogicalGlyph.java b/src/jp/sourceforge/dvibrowser/dvicore/font/LogicalGlyph.java new file mode 100644 index 0000000..8e7538e --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/LogicalGlyph.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; + +// immutable + +public class LogicalGlyph +implements java.io.Serializable +{ + private static final long serialVersionUID = -4973535722455103574L; + private final LogicalFont lf; + private final int code; + public LogicalGlyph(LogicalFont lf, int code) + { + this.lf = lf; + this.code = code; + } + + public LogicalFont logicalFont() { return lf; } + public int code() { return code; } + + public boolean equals(Object obj) { + if (obj instanceof LogicalGlyph) { + LogicalGlyph a = (LogicalGlyph) obj; + return a.lf.equals(lf) && a.code == code; + } + return false; + } + + public int hashCode() { + return code + 33*lf.hashCode(); + } + + public String toString() { + return getClass().getName() + + "[lf=" + lf + + " code=" + code; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/PackedGlyphRasterizer.java b/src/jp/sourceforge/dvibrowser/dvicore/font/PackedGlyphRasterizer.java new file mode 100644 index 0000000..9a00e64 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/PackedGlyphRasterizer.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.api.BinaryDevice; + +// not thread-safe. + +public final class PackedGlyphRasterizer +{ + private PkGlyph glyph; + private byte [] buf; + private int dynF, dynG, dynH; + private boolean highNyb; + private int offset; + + public void begin(PkGlyph glyph) + { + this.glyph = glyph; + buf = glyph.raster(); + dynF = glyph.dynF(); + dynG = ((13-dynF) << 4) + dynF + 1; + dynH = ((dynF+1)<<4) - dynF - 1; // 15 * (dynF + 1) + offset = 0; + highNyb = true; + } + + public void end() + { + glyph = null; + buf = null; + } + + private int getNybble() + throws DviException + { + if (highNyb) { + highNyb = false; + return ((buf[offset] >> 4) & 15); + } else { + highNyb = true; + return (buf[offset++] & 15); + } + } + + private int repeat = 0; + + private int getPackedNumInternal(boolean recursed) + throws DviException + { + int i = getNybble(); + if (i == 0) { + int j; + do { + j = getNybble(); + i++; + } while (j == 0); + while (i-- > 0) { + j = (j << 4) | getNybble(); + } + return j - 16 + dynG; + } else { + if (i <= dynF) { + return i; + } else if (i < 14) { // dynF < i < 14 + return (i << 4) + getNybble() - dynH; + } else { + if (recursed) + throw new IllegalStateException + ("too many levels of recursion"); + if (i == 14) { + repeat = getPackedNumInternal(true); + } else // i == 15 + repeat = 1; + return getPackedNumInternal(true); + } + } + } + + public int getPackedNum() + throws DviException + { + return getPackedNumInternal(false); + } + + public void rasterizeTo(final BinaryDevice out) + throws DviException + { + boolean paintFlag = glyph.turnOn(); + int w = glyph.width(); + int h = glyph.height(); + if (w <= 0 || h <= 0) + return; + if (out.beginRaster(w, h)) { + out.beginLine(); + while (h > 0) { + int count = getPackedNum(); + while (count > 0) { + if (count < w) { + out.putBits(count, paintFlag); + w -= count; + break; + } else { + out.putBits(w, paintFlag); + out.endLine(repeat); + count -= w; + h -= repeat + 1; + w = glyph.width(); + repeat = 0; + out.beginLine(); + } + } + paintFlag = !paintFlag; + } + } + out.endRaster(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/PackedSequence.java b/src/jp/sourceforge/dvibrowser/dvicore/font/PackedSequence.java new file mode 100644 index 0000000..d1f3456 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/PackedSequence.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; + +// immutable. + +public final class PackedSequence +implements java.io.Serializable, Cloneable +{ + private static final long serialVersionUID = -2179435976613430392L; + private byte [] data; + private final int dynF; + private final int nybLength; + + public PackedSequence(byte [] data, int dynF, int nybLength) { + this.data = data; + this.dynF = dynF; + this.nybLength = nybLength; + } + + public byte [] data() { return data.clone(); } + public int dynF() { return dynF; } + public int nybLength() { return nybLength; } + + public Object clone() + { + try { + PackedSequence ps = (PackedSequence) super.clone(); + ps.data = data.clone(); + return ps; + } catch (CloneNotSupportedException ex) { + throw new InternalError(); + } + } + + public String toString() + { + String s = getClass().getName() + + "[dynF=" + dynF + + " nybLength=" + nybLength + + " data=" + ; + boolean needComma = false; + for (byte a : data) { + if (needComma) s += ","; + s += String.valueOf(a); + needComma = true; + } + + return s + "]"; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/PkConstants.java b/src/jp/sourceforge/dvibrowser/dvicore/font/PkConstants.java new file mode 100644 index 0000000..a254fb2 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/PkConstants.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; + +public final class PkConstants { + private PkConstants() {} // disable instantiation + + public static final int PK_ID_BYTE = 89; + + public static final int PK_DYNF_RASTER_BY_BITS = 14; + + public static final int PK_XXX1 = 240; + public static final int PK_XXX2 = 241; + public static final int PK_XXX3 = 242; + public static final int PK_XXX4 = 243; + public static final int PK_YYY = 244; + public static final int PK_POST = 245; + public static final int PK_NOP = 246; + public static final int PK_PRE = 247; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/PkFont.java b/src/jp/sourceforge/dvibrowser/dvicore/font/PkFont.java new file mode 100644 index 0000000..093495c --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/PkFont.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.DviUnit; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviFont; +import jp.sourceforge.dvibrowser.dvicore.api.Glyph; +import jp.sourceforge.dvibrowser.dvicore.api.SimpleMetrics; +import jp.sourceforge.dvibrowser.dvicore.io.DviInputStreamReader; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + + +public class PkFont +extends DviObject +implements DviFont, SimpleMetrics +{ + private static final long serialVersionUID = 1531160169076910099L; + + private final File file; + + private int idByte; + private byte[] comment; + + private int designSize; + private int checkSum; + private int hppp; + private int vppp; + private long bodyOffset; + private int numChars; + + private HashMap glyphs + = new HashMap(); + + public PkFont(DviContextSupport dcs, File file) + throws DviException + { + super(dcs); + this.file = file; + try { + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + parseInputStream(fis); + } finally { + DviUtils.silentClose(fis); + } + } catch (DviException ex) { + throw ex; + } catch (IOException ex) { + throw new DviException(ex); + } + } + + public PkFont(DviContextSupport dcs, InputStream is) + throws DviException + { + super(dcs); + try { + parseInputStream(is); + } catch (DviException ex) { + throw ex; + } catch (IOException ex) { + throw new DviException(ex); + } + this.file = null; + } + + public boolean hasChar(int code) + { + return glyphs.containsKey(code); + } + + public Glyph getGlyph(LogicalFont lf, int code) + { + return glyphs.get(code); + } + + public int getWidth(int code) + { + PkGlyph g = (PkGlyph) glyphs.get(code); + if (g == null) return 0; + return g.width(); + } + + public int getHeight(int code) + { + PkGlyph g = (PkGlyph) glyphs.get(code); + if (g == null) return 0; + return g.height(); + } + + public int getTfmWidth(int code) + { + PkGlyph g = (PkGlyph) glyphs.get(code); + if (g == null) return 0; + return g.getTfmWidth(); + } + + public int getIdByte() { + return idByte; + } + + public byte[] getComment() { + return comment.clone(); + } + + public int getDesignSize() { + return designSize; + } + + public int getCheckSum() { + return checkSum; + } + + // TODO: rename this method + public int getHppp() { + return hppp; + } + + // TODO: rename this method + public int getVppp() { + return vppp; + } + + public long getBodyOffset() { + return bodyOffset; + } + + public int getNumChars() { + return numChars; + } + + public void parseInputStream(InputStream is) + throws IOException, DviException + { + DviInputStreamReader in = new DviInputStreamReader( + new BufferedInputStream(is, 8192) + ); + + if (in.readU1() != PkConstants.PK_PRE) + throw new DviException + ("PK file doesn't start with PRE."); + + idByte = in.readU1(); + if (idByte != PkConstants.PK_ID_BYTE) + throw new DviException + ("Unrecognized PK file: wrong idByte: " + idByte); + int commentLen = in.readU1(); + comment = new byte[commentLen]; + in.readFully(comment); + designSize = in.readS4(); + checkSum = in.readS4(); + hppp = in.readS4(); + vppp = in.readS4(); + bodyOffset = in.getOffset(); + + numChars = 0; + + boolean stop = false; + while (!stop) { + byte [] buf; + int c = in.readU1(); + switch (c) { + case PkConstants.PK_XXX4: + case PkConstants.PK_XXX3: + case PkConstants.PK_XXX2: + case PkConstants.PK_XXX1: { + int len; + len = in.readU(c - PkConstants.PK_XXX1 + 1); + buf = new byte[len]; + in.readFully(buf); + // System.out.println("xxx: \"" + new String(buf) + "\""); + break; + } + case PkConstants.PK_YYY: { +// int yyy = in.readS4(); + in.readS4(); + // System.out.println("yyy: " + yyy); + break; + } + case PkConstants.PK_NOP: + break; + case PkConstants.PK_POST: + stop = true; + break; + case PkConstants.PK_PRE: + throw new DviException + ("broken PK file: PRE found in the body of PK file: " + + file.getPath()); + default: + { +// long pos = in.getOffset() - 1; + PkGlyph g = (PkGlyph) PkGlyph.readFromInput(c, in); + glyphs.put(g.code(), g); + } + } + } + } + + public static String getDviResourceName(LogicalFont lf) + { + DviFontSpec fs = lf.fontSpec(); + DviResolution res = lf.resolution(); + DviUnit dviUnit = lf.dviUnit(); + int useDpi = (int) ( + (double) res.dpi() * fs.spaceSize() * dviUnit.magnification() + / fs.designSize() / 1000 + ); + if (useDpi <= 0) return null; + String pk = fs.name() + "." + useDpi + "pk"; + return pk; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/PkFontResolver.java b/src/jp/sourceforge/dvibrowser/dvicore/font/PkFontResolver.java new file mode 100644 index 0000000..c6b8c23 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/PkFontResolver.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; +import java.io.InputStream; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviFont; + + +public class PkFontResolver +extends AbstractDviFontResolver +{ +// private static final Logger LOGGER = Logger.getLogger(DviFontResolver.class +// .getName()); + public PkFontResolver(DviContextSupport dcs, LogicalFont logicalFont) + { + super(dcs, logicalFont); + } + + @Override + protected DviFont createInstanceFromStream(InputStream openStream) throws DviException + { + return new PkFont(this, openStream); + } + + @Override + protected String mapToDviResourceName(LogicalFont logicalFont) + { + return PkFont.getDviResourceName(logicalFont); + } + +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/PkGlyph.java b/src/jp/sourceforge/dvibrowser/dvicore/font/PkGlyph.java new file mode 100644 index 0000000..f312474 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/PkGlyph.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; + +import java.io.IOException; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.api.BinaryDevice; +import jp.sourceforge.dvibrowser.dvicore.api.DviInput; +import jp.sourceforge.dvibrowser.dvicore.api.Glyph; + + +// immutable. + +public class PkGlyph +implements Glyph +{ + private static final long serialVersionUID = 3825743583018783073L; + + public static final PkGlyph EMPTY + = new PkGlyph( + 0, 0, + null, + 0, false, + 0, 0 + ); + + private int flagByte; + private int dynF; + private boolean turnOn; + private int packetLength; + private int code; + private int tfmw; + private byte [] raster = null; + + private int xAdvance; + private int yAdvance; + private int width; + private int height; + private int xOffset; + private int yOffset; + private DviRect bbox; + + // This constructor is used internally. + private PkGlyph() {} + + public PkGlyph( + int width, int height, + byte [] raster, + int dynF, boolean turnOn, + int xOffset, int yOffset) + { + this.width = width; + this.height = height; + this.raster = raster; + this.dynF = dynF; + this.turnOn = turnOn; + this.xOffset = xOffset; + this.yOffset = yOffset; + + bbox = new DviRect(-xOffset, -yOffset, width, height); + + flagByte = 7; + packetLength = 0; + code = 0; + tfmw = 0; // TODO: write tfmw. + xAdvance = yAdvance = 0; + } + + public static Glyph readFromInput(DviInput in) + throws DviException, IOException + { + return readFromInput(in.readU1(), in); + } + + public static Glyph readFromInput(int firstByte, DviInput in) + throws DviException, IOException + { + PkGlyph g = new PkGlyph(); + + // firstByte = + // 7 6 5 4 3 2 1 0 + // +---+---+---+---+------+---+---+---+ + // MSB | dynF |turnOn| flagByte | LSB. + // +---+---+---+---+------+---+---+---+ + + g.flagByte = firstByte & 7; + g.turnOn = (0 != (firstByte & 8)); + g.dynF = (firstByte >> 4) & 15; + + int rasterSize; + if (g.flagByte == 7) { + g.packetLength = in.readS4(); + g.code = in.readS4(); + g.tfmw = in.readS4(); + g.xAdvance = in.readS4(); + g.yAdvance = in.readS4(); + g.width = in.readS4(); + g.height = in.readS4(); + g.xOffset = in.readS4(); + g.yOffset = in.readS4(); + + g.packetLength += 9; + rasterSize = g.packetLength - 37; + } else if (g.flagByte > 3) { + g.packetLength = (g.flagByte - 4) * 65536 + + in.readU2(); + g.code = in.readU1(); + g.tfmw = in.readS3(); + g.xAdvance = in.readU2() * 65536; + g.yAdvance = 0; + g.width = in.readU2(); + g.height = in.readU2(); + g.xOffset = in.readS2(); + g.yOffset = in.readS2(); + + g.packetLength += 4; + rasterSize = g.packetLength - 17; + } else { + g.packetLength = g.flagByte * 256 + + in.readU1(); + g.code = in.readU1(); + g.tfmw = in.readS3(); + g.xAdvance = in.readU1() * 65536; + g.yAdvance = 0; + g.width = in.readU1(); + g.height = in.readU1(); + g.xOffset = in.readS1(); + g.yOffset = in.readS1(); + + g.packetLength += 3; + rasterSize = g.packetLength - 11; + } + + if (rasterSize > 0) { + g.raster = new byte[rasterSize]; + in.readFully(g.raster); + } else if (rasterSize == 0) { + // TODO: handle the case where rasterSize == 0 && turnOn==true. + // This can happen. It's not an error. + } else { + throw new DviException + ("Negative rasterSize: " + rasterSize); + } + + g.bbox = new DviRect(-g.xOffset, -g.yOffset, g.width, g.height); + + return g; + } + + public boolean rasterByBits() { return (dynF == PkConstants.PK_DYNF_RASTER_BY_BITS); } + public int flagByte() { return flagByte; } + public int dynF() { return dynF; } + public boolean turnOn() { return turnOn; } + public int packetLength() { return packetLength; } + + public byte [] raster() { return raster; } + + public int code() { return code; } + + public int getTfmWidth() { return tfmw; } + + public int xAdvance() { return xAdvance; } + public int yAdvance() { return yAdvance; } + public int width() { return width; } + public int height() { return height; } + public int xOffset() { return xOffset; } + public int yOffset() { return yOffset; } + public DviRect bounds() { return bbox; } + + public void rasterizeTo(BinaryDevice out) + throws DviException + { + out.save(); + try { + out.translate(-xOffset, -yOffset); + if (rasterByBits()) { + // TODO: test this code. + RunLengthEncodedGlyph rlg = RunLengthEncodedGlyph.readRasterByBits( + raster, + width, height, + 0, 0 // Offsets are not used when drawing a raster by bits. + ); + rlg.rasterizeTo(out); + } else { + PackedGlyphRasterizer sub = new PackedGlyphRasterizer(); + sub.begin(this); + sub.rasterizeTo(out); + sub.end(); + } + } finally { + out.restore(); + } + } + + public String toString() + { + return getClass().getName() + + "[packetLength=" + packetLength + + ",flagByte=" + flagByte + + ",dynF=" + dynF + + ",code=" + code + + ",tfmw=" + tfmw + + ",xAdvance=" + xAdvance + + ",yAdvance=" + yAdvance + + ",width=" + width + + ",height=" + height + + ",xOffset=" + xOffset + + ",yOffset=" + yOffset + + ( + (raster != null) ? + (",rasterSize=" + raster.length) : + ",raster=null" + ) + + "]" + ; + + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/RunLengthEncodedGlyph.java b/src/jp/sourceforge/dvibrowser/dvicore/font/RunLengthEncodedGlyph.java new file mode 100644 index 0000000..1e4a57e --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/RunLengthEncodedGlyph.java @@ -0,0 +1,544 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviPoint; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.api.BinaryDevice; +import jp.sourceforge.dvibrowser.dvicore.render.AbstractDevice; + + +// mutable. + +public final class RunLengthEncodedGlyph +{ + private static final int DEFAULT_ARRAY_SIZE = 256; + + private int width; + private int height; + private int xOffset; + private int yOffset; + private ArrayList lines; + + public RunLengthEncodedGlyph() + { + this(0, 0, 0, 0); + } + + private RunLengthEncodedGlyph(int width, int height, int xOffset, int yOffset) + { + this.width = width; + this.height = height; + this.xOffset = xOffset; + this.yOffset = yOffset; + this.lines = new ArrayList(DEFAULT_ARRAY_SIZE); + } + + public static RunLengthEncodedGlyph readByteBinary( + byte [] buf, int width, int height, + int xOffset, int yOffset) + { + RunLengthEncodedGlyph rlg = new RunLengthEncodedGlyph(width, height, xOffset, yOffset); + + RunLengthEncodedLine prev = null; + int pitch = ((width + 7) >>> 3) << 3; + int bitOffset = 0; + for (int i=0; i 0) + line.append(count, (0 != last)); + + if (line.equals(prev)) { + rlg.lines.add(prev); + } else { + rlg.lines.add(line); + prev = line; + } + } + rlg.compact(); + + return rlg; + } + + + public DviRect getBounds() + { + return new DviRect(-xOffset, -yOffset, width, height); + } + public int width() { return width; } + public int height() { return height; } + public int xOffset() { return xOffset; } + public int yOffset() { return yOffset; } + + public boolean isEmpty() + { + return (width <= 0 || height <= 0 || lines.size() == 0); + } + + public void rasterizeTo(BinaryDevice out) + throws DviException + { + out.save(); + try { + out.translate(-xOffset, -yOffset); + if (out.beginRaster(width, height)) { + // TODO: use repeat. + for (int i=0; i 0) { + if (line.headOn()) { + lskip = 0; + } else { + lskip = Math.min(lskip, line.head()); + } + } + } + + prev = null; + for (int i=0; i 0) { + if (line.tailOn()) { + rskip = 0; + } else { + rskip = Math.min(rskip, line.tail()); + } + } + prev = line; + } + + prev = null; + for (int i=0; i 0) { + RunLengthEncodedLine line = lines.get(0); + if (!line.allOff()) + break; + lines.remove(0); + height--; + yOffset--; + tskip++; + } + + while (height > 0) { + RunLengthEncodedLine line = lines.get(height-1); + if (!line.allOff()) + break; + lines.remove(height-1); + height--; + bskip++; + } + + for (int i=0; i counts = new ArrayList(DEFAULT_ARRAY_SIZE); + + int count=0; + int repeat=0; + RunLengthEncodedLine line = lines.get(0); + boolean turnOn = line.headOn(); + int i = 0; + while (line != null) { + ArrayList data = line.getData(); + final int ds = data.size(); + for (int j=0; j 0) { + count += data.get(j) + r * width; + // repeat is unchanged. + } else { + count = data.get(j); + repeat = r; + } + } else { + count += c; + } + if (needFlush) { + if (repeat > 0) { + counts.add(-repeat); + repeat = 0; + } + counts.add(count); + count = 0; + } + } + } + + PackedSequence ps = new SequencePacker(counts).pack(); + + return new PkGlyph( + width, height, + ps.data(), ps.dynF(), + turnOn, + xOffset, yOffset + ); + } + + public DviRect bounds() + throws DviException + { + if (isEmpty()) + return DviRect.EMPTY; + else + return new DviRect(-xOffset, -yOffset, width, height); + } + + public void unite(RunLengthEncodedGlyph rlg) + { + DviRect u = rlg.getBounds().union(getBounds()); + + ArrayList newLines + = new ArrayList(DEFAULT_ARRAY_SIZE); + RunLengthEncodedLine last = null; + int ey = u.bottom(); + for (int y = u.top(); y<=ey; y++) { + RunLengthEncodedLine a = new RunLengthEncodedLine(); + RunLengthEncodedLine b = new RunLengthEncodedLine(); + int ia = y + yOffset; + int ib = y + rlg.yOffset; + + if (0 <= ia && ia < height) { + int w = u.width(); + int lpad = -xOffset-u.left(); + if (lpad > 0) { + a.append(lpad, false); + w -= lpad; + } + a.append(lines.get(ia)); + w -= width; + a.append(w, false); + } else { + a.append(u.width(), false); + } + + if (0 <= ib && ib < rlg.height) { + int w = u.width(); + int lpad = -rlg.xOffset-u.left(); + if (lpad > 0) { + b.append(lpad, false); + w -= lpad; + } + b.append(rlg.lines.get(ib)); + w -= rlg.width; + b.append(w, false); + } else { + b.append(u.width(), false); + } + + a = RunLengthEncodedLine.union(a, b); + + if (a.equals(last)) { + newLines.add(last); + } else { + newLines.add(a); + last = a; + } + } + + this.width = u.width(); + this.height = u.height(); + this.xOffset = -u.x(); + this.yOffset = -u.y(); + this.lines = newLines; + compact(); + } + + + public BinaryDevice getBinaryDevice(DviResolution res) + throws DviException + { + return new BinaryDeviceImpl(res); + } + +// private static String dumpCounts(ArrayList counts, boolean flag) +// { +// String str = ""; +// +// for (int k=0; k data + = new ArrayList(); + + // TODO: Make the return value unmodifiable. + public ArrayList getData() { return data; } + public boolean headOn() { return headOn; } + public boolean tailOn() { return tailOn; } + public int width() { return width; } + public boolean allOn() { + return headOn && data.size() == 1; + } + public boolean allOff() { + return !headOn && data.size() == 1; + } + public int head() { + return isEmpty() ? 0 : data.get(0); + } + public int tail() { + return isEmpty() ? 0 : data.get(data.size()-1); + } + /////////////// + + public void rasterizeTo(BinaryDevice out) + throws DviException + { + boolean flag = headOn; + final int ds = data.size(); + for (int i=0; i 0) { + int c = data.get(0).intValue(); + if (c > count) { + data.set(0, c - count); + width -= count; + hash -= headOn ? count : -count; + break; + } else { + data.remove(0); + hash -= headOn ? c : -c; + headOn = !headOn; + count -= c; + width -= c; + if (width <= 0) { + clear(); + break; + } + } + } + } + + public void cropTail(int count) + { + if (width == 0) return; + while (count > 0) { + int last = data.size() - 1; + int c = data.get(last); + if (c > count) { + data.set(last, c - count); + hash -= tailOn ? count : -count; + width -= count; + break; + } else { + data.remove(last); + hash -= tailOn ? c : -c; + tailOn = !tailOn; + count -= c; + width -= c; + if (width <= 0) { + clear(); + break; + } + } + } + } + + /////////////// + + public void prepend(RunLengthEncodedLine rll) + { + if (rll.isEmpty()) return; + if (rll == this) + rll = (RunLengthEncodedLine) clone(); + boolean flag = rll.tailOn; + for (int i=rll.data.size()-1; i>=0; i--) { + prepend(rll.data.get(i), flag); + flag = !flag; + } + } + + public void append(RunLengthEncodedLine rll) + { + if (rll.isEmpty()) return; + if (rll == this) + rll = (RunLengthEncodedLine) clone(); + boolean flag = rll.headOn; + final int ds = rll.data.size(); + for (int i=0; i=bitOffset; i--) { + boolean flag = (0 != (buf[i >>> 3] & (1 << (7 - (i & 7))))); + prepend(1, revert ? !flag : flag); + } + } + + public void append(byte [] buf, + int bitOffset, int bitLen, boolean revert) + { + if (bitOffset < 0) + throw new IllegalArgumentException + ("bit offset can't be negative"); + if (bitLen <= 0) return; + // TODO: Optimize this code using a look-up table. + for (int i=0; i>> 3] & (1 << (7 - (p & 7))))); + append(1, revert ? !flag : flag); + } + } + + /////////////// + + public static RunLengthEncodedLine union(RunLengthEncodedLine a, RunLengthEncodedLine b) + { + if (a == null || b == null) + throw new NullPointerException(); + if (a.isEmpty()) return (RunLengthEncodedLine) b.clone(); + if (b.isEmpty()) return (RunLengthEncodedLine) a.clone(); + + RunLengthEncodedLine rll = new RunLengthEncodedLine(); + boolean a_flag = a.headOn; + boolean b_flag = b.headOn; + int a_ptr = 0; + int b_ptr = 0; + int a_size = a.data.size(); + int b_size = b.data.size(); + int a_count = a.data.get(0); + int b_count = b.data.get(0); + while (a_count != Integer.MAX_VALUE || + b_count != Integer.MAX_VALUE) + { + final int count; + boolean flag = a_flag || b_flag; + if (a_flag && b_flag) { + count = Math.max(a_count, b_count); + } else if (a_flag) { + count = a_count; + } else if (b_flag) { + count = b_count; + } else { + count = Math.min(a_count, b_count); + } + + rll.append(count, flag); + + { + int c = count; + while (a_count <= c) { + c -= a_count; + if (++a_ptr >= a_size) { + a_count = Integer.MAX_VALUE; + a_flag = false; + } else { + a_count = a.data.get(a_ptr); + a_flag = !a_flag; + } + } + if (a_count < Integer.MAX_VALUE) + a_count -= c; + } + + { + int c = count; + while (b_count <= c) { + c -= b_count; + if (++b_ptr >= b_size) { + b_count = Integer.MAX_VALUE; + b_flag = false; + } else { + b_count = b.data.get(b_ptr); + b_flag = !b_flag; + } + } + if (b_count < Integer.MAX_VALUE) + b_count -= c; + } + } + + return rll; + } + + /////////////// + + public void clear() + { + hash = 0; + width = 0; + headOn = tailOn = false; + data.clear(); + } + + public boolean isEmpty() + { + return (width == 0); + } + + public boolean equals(Object obj) + { + if (this == obj) return true; + if (obj instanceof RunLengthEncodedLine) { + RunLengthEncodedLine rll = (RunLengthEncodedLine) obj; + return rll.hash == hash + && rll.width == width + && rll.headOn == headOn + && rll.tailOn == tailOn + && rll.data.equals(data) + ; + } + + return false; + } + + public int hashCode() + { + return hash; + } + + @SuppressWarnings({"unchecked"}) + public Object clone() + { + try { + RunLengthEncodedLine rll = (RunLengthEncodedLine) super.clone(); + rll.data = (ArrayList) rll.data.clone(); + return rll; + } catch (CloneNotSupportedException ex) { + throw new InternalError(); // this shouldn't happen. + } + } + + public String toString() + { + StringBuilder sb = new StringBuilder(); + boolean flag = headOn; + int s = data.size(); + for (int i=0; i 0) + sb.append("*"); + else + while (count-- > 0) + sb.append("-"); + flag = !flag; + } + return sb.toString(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/SequencePacker.java b/src/jp/sourceforge/dvibrowser/dvicore/font/SequencePacker.java new file mode 100644 index 0000000..21da8be --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/SequencePacker.java @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; + +import java.util.ArrayList; + + +public class SequencePacker +{ + private final ArrayList data; // We don't modify its content. + + public SequencePacker(ArrayList data) + { + this.data = data; + } + + private byte [] _buf; + private int _ptr; + private int _highNyb; + + private void writeNyb(int a) + { + if (_highNyb != 0) { + _buf[_ptr] |= (byte)((a & 15) << 4); + _highNyb = 0; + } else { + _buf[_ptr] |= (byte)(a & 15); + _ptr++; + _highNyb = 1; + } + } + + public PackedSequence pack() + { + Config cfg = findBestConfig(data); + return pack(cfg); + } + + private PackedSequence pack(final Config cfg) + { + final int nybLength = cfg.nybLength; + final byte [] buf = new byte [(nybLength + 1)>>>1]; + final int dynF = cfg.dynF; + final int dynG = computeDynG(dynF); + final int dynH = computeDynH(dynF); + + _buf = buf; + _ptr = 0; + _highNyb = 1; + + final int ds = data.size(); + for (int i=0; i>> 4); + writeNyb(cc >>> 0); + } else { + final int cc = c - dynG + 16; + int k = cc >>> 4; + int nl = 0; + while (k > 0) { + writeNyb(0); + k >>>= 4; + nl += 4; + } + while (nl >= 0) { + writeNyb(cc >>> nl); + nl -= 4; + } + } + } + + _buf = null; + + return new PackedSequence(buf, dynF, nybLength); + } + + private static int computeDynG(int dynF) + { + return ((13-dynF) << 4) + dynF + 1; + } + + private static int computeDynH(int dynF) + { + return ((dynF+1) << 4) - dynF - 1; // 15 * (dynF + 1) + } + + private static final int [] cc2diffPos; + + static { + cc2diffPos = new int[13*15]; + for (int d=0; d<13; d++) { + for (int j=0; j<15; j++) { + int cc = d * 15 + j; + cc2diffPos[cc] = 12 - d; + } + } + } + + private static class Config + { + private final int dynF; + private final int nybLength; + private Config(int dynF, int nybLength) { + this.dynF = dynF; + this.nybLength = nybLength; + } + } + + private static Config findBestConfig(ArrayList data) + { + int len = 0; + int [] diff = new int [13]; + + // We first compute the nyb length, assuming that dynF=0. + // At the same time, we store the difference information to diff, + // which is used later to compute the nyb length for other + // values of dynF. + final int ds = data.size(); + for (int i=0; i= 13) + break; + + len += diff[dynF]; + dynF++; + } + + Config cfg = new Config(bestDynF, bestSize); + return cfg; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/TexFontMetrics.java b/src/jp/sourceforge/dvibrowser/dvicore/font/TexFontMetrics.java new file mode 100644 index 0000000..3b8c334 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/TexFontMetrics.java @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; + +import jp.sourceforge.dvibrowser.dvicore.DviConstants; +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviInput; +import jp.sourceforge.dvibrowser.dvicore.api.FullMetrics; +import jp.sourceforge.dvibrowser.dvicore.io.DviInputStreamReader; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + + +// TODO: support Tategumi + +public class TexFontMetrics +extends DviObject +implements FullMetrics +{ + private static final long serialVersionUID = 962603909880917980L; + + // TODO: outsource JFM configuration + private boolean enableJFM = true; + + private boolean isJFM; // For Japanese pTeX + +private int checkSum; + private int designSize; + + private final String name; + + private final HashMap ct2rec + = new HashMap(); + private HashMap code2ct; + + public TexFontMetrics(DviContextSupport dcs, File file) + throws DviException + { + super(dcs); + FileInputStream is = null; + try { + is = new FileInputStream(file); + parseInputStream(is); + } catch (IOException ex) { + DviUtils.silentClose(is); + throw new DviException(ex); + } + name = getClass().getName() + + "--" + file.getPath() + + "--" + file.lastModified() + ; + } + + public TexFontMetrics(DviContextSupport dcs, InputStream is) + throws DviException + { + super(dcs); + try { + parseInputStream(is); + } catch (IOException ex) { + throw new DviException(ex); + } + name = getClass().getName() + + "--" + is + + "--" + System.currentTimeMillis() + ; + } + + @SuppressWarnings("unused") + protected void parseInputStream(InputStream is) + throws IOException, DviException + { + DviInputStreamReader in = new DviInputStreamReader( + new BufferedInputStream(is, 1024) + ); + + long start = in.getOffset(); + + int id; // For Japanese pTeX + int nt; // For Japanese pTeX + int lf; + int lh; + int bc; + int ec; + int nw; + int nh; + int nd; + int ni; + int nl; + int nk; + int ne; + int np; + + int numChars; + + if (enableJFM) { + id = in.readU2(); + nt = in.readU2(); + isJFM = (id == DviConstants.TFM_ID_TATEGUMI || id == DviConstants.TFM_ID_YOKOGUMI); + if (isJFM) { + lf = in.readU2(); + lh = in.readU2(); + } else { + lf = id; + lh = nt; + id = 0; + nt = 0; + } + } else { + id = 0; + nt = 0; + lf = in.readU2(); + lh = in.readU2(); + isJFM = false; + } + + bc = in.readU2(); + ec = in.readU2(); + nw = in.readU2(); + nh = in.readU2(); + nd = in.readU2(); + ni = in.readU2(); + nl = in.readU2(); + nk = in.readU2(); + ne = in.readU2(); + np = in.readU2(); + numChars = ec - bc + 1; + + // header + int [] header_t = readBuffer(in, lh); + { + checkSum = header_t[0]; + designSize = header_t[1]; + } + + // character type map (for Japanese JFM) + if (isJFM) { + code2ct = new HashMap(); + for (int i=0; i>> 24) & 0xff; + final int hi = (ci >>> 20) & 0x0f; + final int di = (ci >>> 16) & 0x0f; + final int ii = (ci >>> 10) & 0x3f; + final int tag = (ci >>> 8) & 0x03; + final int rem = (ci >>> 0) & 0xff; + + final int width = width_t [wi]; + final int height = height_t[hi]; + final int depth = depth_t [di]; + final int italic = italic_t[ii]; + + ct2rec.put(ct, new Record(width, height, depth, italic)); + } + } + + private static int [] readBuffer(DviInput in, int length) + throws IOException + { + int [] buf = new int[length]; + for (int i=0; i glyphInfos + = new HashMap(); + + private final String name; + + public VirtualFont(DviContextSupport dcs, File file) + throws DviException + { + super(dcs); + try { + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + parseInputStream(fis); + } finally { + DviUtils.silentClose(fis); + } + } catch (IOException ex) { + throw new DviException(ex); + } + name = getClass().getName() + + "--" + file + + "--" + file.lastModified() + + "--[" + new String(comment) + "]" + ; + } + + public VirtualFont(DviContextSupport dcs, InputStream is) + throws DviException + { + super(dcs); + try { + parseInputStream(is); + } catch (IOException ex) { + throw new DviException(ex); + } + name = getClass().getName() + + "--" + is + + "--" + System.currentTimeMillis() + + "--[" + new String(comment) + "]" + ; + } + + + private int idByte; + private byte [] comment; + private int checkSum; + private int designSize; + private DviFontTable fontTable; + private int defaultFontNumber = DviConstants.UNDEFINED_FONT_NUMBER; + + public boolean hasChar(int code) + throws DviException + { + return glyphInfos.containsKey(code); + } + + public String getName() + { + return name; + } + + public int getIdByte() { + return idByte; + } + + public byte[] getComment() { + return comment.clone(); + } + + public int getCheckSum() { + return checkSum; + } + + public int getDesignSize() { + return designSize; + } + + public int getDefaultFontNumber() { + return defaultFontNumber; + } + + private void parseInputStream(InputStream is) + throws IOException, DviException + { + DviInputStreamReader in + = new DviInputStreamReader( + new BufferedInputStream(is, 1024) + ); + try { + if (DviCommand.DVI_PRE != in.readU1()) + throw new DviException + ("VF data doesn't start with PRE"); + + idByte = in.readU1(); + if (idByte != DviConstants.VF_ID_BYTE) + throw new DviException + ("unknown id byte: " + idByte); + + int commentSize = in.readU1(); + comment = new byte [commentSize]; + in.readFully(comment); + + checkSum = in.readS4(); + designSize = in.readS4(); + + int c; + + fontTable = new DviFontTable(); + + boolean stop = false; + do { + c = in.readU1(); + + switch (c) { + case DviCommand.DVI_FNT_DEF4: + case DviCommand.DVI_FNT_DEF3: + case DviCommand.DVI_FNT_DEF2: + case DviCommand.DVI_FNT_DEF1: { + int t = c - DviCommand.DVI_FNT_DEF1 + 1; + int fn, cs, ss, ds, al, nl; + byte [] fontName; + + fn = in.readS(t); + cs = in.readS4(); + ss = in.readS4(); + ds = in.readS4(); + al = in.readU1(); + nl = in.readU1(); + + if (defaultFontNumber == DviConstants.UNDEFINED_FONT_NUMBER) + defaultFontNumber = fn; + + fontName = new byte[al+nl]; + in.readFully(fontName); + + fontTable.put( + fn, + DviFontSpec.getInstance( + cs, ss, ds, al, nl, fontName + ) + ); + break; + } + default: + stop = true; + } + } while (!stop); + + while (true) { +// int cmdLength = 1; + + GlyphInfo gi = new GlyphInfo(); + int macroLength; +// int packetLength; + + if (c < 242) { // short chararacter + gi.type = DviConstants.VF_SHORT_CHAR; + macroLength = c; +// packetLength = c + 5; + gi.code = in.readU1(); + gi.tfmw = in.readS3(); + gi.macro = new byte [macroLength]; + in.readFully(gi.macro); + } else if (c == 242) { // long character + gi.type = DviConstants.VF_LONG_CHAR; + macroLength = in.readS4(); +// packetLength = macroLength + 13; + gi.code = in.readS4(); + gi.tfmw = in.readS4(); + gi.macro = new byte [macroLength]; + in.readFully(gi.macro); + } else if (c == DviCommand.DVI_POST) { + break; + } else { + throw new DviException + ("VF data doesn't terminate with POST"); + } + glyphInfos.put(gi.code, gi); + + c = in.readU1(); + } + } catch (EOFException ex) { + throw new DviException + ("VF file ended while reading glyphs.", ex); + } catch (IOException ex) { + throw new DviException(ex); + } + } + + private static class GlyphInfo + implements java.io.Serializable + { + private static final long serialVersionUID = -3968612702338551000L; + private int type; + private int code; + private int tfmw; + private byte [] macro; + + public String toString() { + return getClass().getName() + + "[type=" + type + + " code=" + code + + " tfwm=" + tfmw + + " macroLength=" + macro.length + + "]"; + } + } + + protected PkGlyph generatePkGlyph(LogicalFont lf, int code) + throws DviException + { + GlyphInfo gi = glyphInfos.get(code); + if (gi == null) return null; + + DviResolution res = lf.resolution(); + + RunLengthEncodedGlyph rlg = new RunLengthEncodedGlyph(); + BinaryDevice dev = rlg.getBinaryDevice(res); + // This is a trick to use VirtualFontGeometer. + dev.translate(-res.dpi(), -res.dpi()); + + DviExecutor exe = getDviContext().newDviExecutor(); + DevicePainter dp = getDviContext().newDevicePainter(); + dp.setOutput(dev); + Geometer geometer = new VirtualFontGeometer(this, lf.fontSpec()); + geometer.setPainter(dp); + DviFontTable ft = + fontTable.transformForVirtualFont( + lf.fontSpec(), designSize + ); + + { + final byte [] buf = new byte[gi.macro.length + 1 + 4]; + final int fn = defaultFontNumber; + buf[0] = (byte) DviCommand.DVI_FONT4; + buf[1] = (byte)((fn >>> 24) & 0xff); + buf[2] = (byte)((fn >>> 16) & 0xff); + buf[3] = (byte)((fn >>> 8) & 0xff); + buf[4] = (byte)((fn >>> 0) & 0xff); + System.arraycopy(gi.macro, 0, buf, 5, gi.macro.length); + + exe.execute( + new ByteArrayDviData( + buf, lf.dviUnit(), ft + ), + geometer + ); + } + + return rlg.toPkGlyph(); + } + + public static String getDviResourceName(LogicalFont logicalFont) + { + return logicalFont.fontSpec().name() + ".vf"; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/font/VirtualFontResolver.java b/src/jp/sourceforge/dvibrowser/dvicore/font/VirtualFontResolver.java new file mode 100644 index 0000000..48e348d --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/font/VirtualFontResolver.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.font; +import java.io.InputStream; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviFont; + + +public class VirtualFontResolver +extends AbstractDviFontResolver +{ +// private static final Logger LOGGER = Logger.getLogger(DviFontResolver.class +// .getName()); + public VirtualFontResolver(DviContextSupport dcs, LogicalFont logicalFont) + { + super(dcs, logicalFont); + } + + @Override + protected DviFont createInstanceFromStream(InputStream openStream) throws DviException + { + return new VirtualFont(this, openStream); + } + + @Override + protected String mapToDviResourceName(LogicalFont logicalFont) + { + return VirtualFont.getDviResourceName(logicalFont); + } + +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/gs/GhostscriptBBOXParser.java b/src/jp/sourceforge/dvibrowser/dvicore/gs/GhostscriptBBOXParser.java new file mode 100644 index 0000000..ecac366 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/gs/GhostscriptBBOXParser.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.gs; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Scanner; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.util.CommandShellHandler; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + +public class GhostscriptBBOXParser implements CommandShellHandler { + private static final Logger LOGGER = Logger + .getLogger(GhostscriptBBOXParser.class.getName()); + + private final ArrayList list = new ArrayList(); + + private static final Pattern patPostscriptBoundingBox = Pattern.compile + ("%%BoundingBox:\\s*([+-]?\\d\\d*)\\s\\s*([+-]?\\d\\d*)\\s\\s*([+-]?\\d\\d*)\\s\\s*([+-]?\\d\\d*)\\s*"); + + public static DviRect parsePostscriptBoundingBox(String line) + { + Matcher mat = patPostscriptBoundingBox.matcher(line); + if (mat.matches()) { + int llx = Integer.parseInt(mat.group(1)); + int lly = Integer.parseInt(mat.group(2)); + int urx = Integer.parseInt(mat.group(3)); + int ury = Integer.parseInt(mat.group(4)); + return DviRect.getDviRect(llx, lly, urx, ury); + } + return null; + } + + public GhostscriptBBOXParser() + { + } + + public int getTotalPages() { + return list.size(); + } + + public DviRect getBoundingBoxOfPage(int page) + { + return list.get(page); + } + + public void handleStderr(InputStream in) throws IOException { + try { + Scanner s = new Scanner(in); + while (s.hasNext()) { + String line = s.nextLine(); + DviRect bbox = parsePostscriptBoundingBox(line); + if (bbox != null) { + list.add(bbox); + } + } + } finally { + DviUtils.silentClose(in); + } + } + + public void handleStdin(OutputStream out) throws IOException { + out.close(); + } + + public void handleStdout(InputStream in) throws IOException { + in.close(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/gs/GhostscriptCommandBuilder.java b/src/jp/sourceforge/dvibrowser/dvicore/gs/GhostscriptCommandBuilder.java new file mode 100644 index 0000000..fa89b43 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/gs/GhostscriptCommandBuilder.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.gs; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviSize; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.util.CommandShell; + + +public class GhostscriptCommandBuilder +extends DviObject +{ + private static final Logger LOGGER = Logger.getLogger(GhostscriptCommandBuilder.class.getName()); + + public GhostscriptCommandBuilder(DviContextSupport dcs) { + super(dcs); + } + + private String dev = "png256"; + public void setDevice(String dev) + { + this.dev = dev; + } + + private File outputFile; + public void setOutputFile(File outputFile) + { + this.outputFile = outputFile; + } + + private File inputFile; + public void setInputFile(File inputFile) + { + this.inputFile = inputFile; + } + + + + private int dpi = 300; + public void setResolution(int dpi) + { + this.dpi = dpi; + } + + private int firstPage = -1; + private int lastPage = -1; + + private DviSize size = null; + public void setPaperSize(DviSize size) + { + this.size = size; + } + + private String gsPath = null; + public String getGhostscriptExecutablePath() throws DviException + { + if (gsPath == null) { + return getDviContext().getExecutableName("gs"); + } + return gsPath; + } + + private int textAlpha = 0; + private int graphicsAlpha = 0; + + private String stdoutData = null; + private String stderrData = null; + + // TODO: externalize ghostscript configurations + protected Collection buildCommandLine() + throws DviException + { + ArrayList cl = new ArrayList(); + String gscmd = getGhostscriptExecutablePath(); + cl.add(gscmd); + cl.add("-q"); + cl.add("-dSAFER"); + cl.add("-dPARANOIDSAFER"); + cl.add("-dDELAYSAFER"); + cl.add("-dNOPAUSE"); + cl.add("-dBATCH"); + cl.add("-sDEVICE=" + dev); + if (outputFile != null) { + cl.add("-sOutputFile=" + outputFile); // TODO: Escape characters in outputFile. + } else { + cl.add("-sOutputFile=-"); // the output will be sent to stdout. + } + if (firstPage > 0) { + cl.add("-dFirstPage=" + firstPage); + } + if (lastPage > 0) { + cl.add("-dLastPage=" + lastPage); + } + cl.add("-r" + dpi); + if (size != null) + cl.add("-g" + size); + if (textAlpha > 0) { + cl.add("-dTextAlphaBits=" + textAlpha); + } + if (graphicsAlpha > 0) { + cl.add("-dGraphicsAlphaBits=" + graphicsAlpha); + } + + if (inputFile != null) { + cl.add("-f" + inputFile); + } else { + cl.add("-"); + } + + return cl; + } + + public CommandShell createCommandShell() throws DviException + { + CommandShell cs = new CommandShell(); + Collection cl = buildCommandLine(); + cs.setCommandLine(cl); + return cs; + } + + + public void setTextAlpha(int textAlpha) + { + this.textAlpha = textAlpha; + } + + public int getTextAlpha() + { + return textAlpha; + } + + public void setGraphicsAlpha(int graphicsAlpha) + { + this.graphicsAlpha = graphicsAlpha; + } + + public int getGraphicsAlpha() + { + return graphicsAlpha; + } + + public void setFirstPage(int firstPage) { + this.firstPage = firstPage; + } + + public int getFirstPage() { + return firstPage; + } + + public void setLastPage(int lastPage) { + this.lastPage = lastPage; + } + + public int getLastPage() { + return lastPage; + } + + public void setGhostscriptExecutablePath(String gsPath) { + this.gsPath = gsPath; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/gs/GhostscriptUtils.java b/src/jp/sourceforge/dvibrowser/dvicore/gs/GhostscriptUtils.java new file mode 100644 index 0000000..778fadc --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/gs/GhostscriptUtils.java @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.gs; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Scanner; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviPaperSize; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.DviSize; +import jp.sourceforge.dvibrowser.dvicore.api.DviContext; +import jp.sourceforge.dvibrowser.dvicore.image.pnm.PnmSplitter; +import jp.sourceforge.dvibrowser.dvicore.image.split.SplitImageWriter; +import jp.sourceforge.dvibrowser.dvicore.util.BufferFilter; +import jp.sourceforge.dvibrowser.dvicore.util.CommandShell; +import jp.sourceforge.dvibrowser.dvicore.util.CommandShellHandler; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + +public class GhostscriptUtils { + private static final class CommandShellHandlerImpl implements + CommandShellHandler { + private final ArrayList list; + private final String path; + public CommandShellHandlerImpl(String path, ArrayList list) { + this.list = list; + this.path = path; + } + + public void handleStderr(InputStream in) throws IOException, + DviException { + DviUtils.logLinesFromStream("[stderr]", in, LOGGER, Level.WARNING); + } + + public void handleStdin(OutputStream out) throws IOException, + DviException { + out.close(); + } + + public void handleStdout(InputStream in) throws IOException, + DviException { + try { + Scanner s = new Scanner(in); + String line = s.nextLine(); + if (line.indexOf("Ghostscript") != -1) { + list.add(path); + } + in.close(); + } finally { + DviUtils.silentClose(in); + } + + } + } + + private static final Logger LOGGER = Logger.getLogger(GhostscriptUtils.class + .getName()); + + public static DviRect [] computePostScriptBoundingBoxes(DviContext ctx, File file, int dpi) throws DviException, IOException, InterruptedException + { + if (ctx == null) + throw new IllegalArgumentException("ctx can't be null"); + + if (file == null) + throw new IllegalArgumentException("file can't be null"); + + if (dpi <= 0) + throw new IllegalArgumentException("dpi <= 0: " + dpi); + + GhostscriptCommandBuilder gs = new GhostscriptCommandBuilder(ctx); + gs.setInputFile(file); + gs.setResolution(dpi); + gs.setDevice("bbox"); + CommandShell shell = gs.createCommandShell(); + GhostscriptBBOXParser handler = new GhostscriptBBOXParser(); + shell.setHandler(handler); + shell.execute(); + + ArrayList list = new ArrayList(); + + LOGGER.info("total pages=" + handler.getTotalPages()); + for (int i = 0; i < handler.getTotalPages(); i++) { + DviRect bbox = handler.getBoundingBoxOfPage(i); + LOGGER.info("bounding box[" + i + "]=" + bbox); + list.add(bbox); + } + return list.toArray(new DviRect[list.size()]); + } + + public static void renderAndSplit(final DviContext ctx, final InputStream is, + DviSize unitSize, final SplitImageWriter imageWriter, + DviResolution res, + String deviceName, final int pageNum, final long timeout, + final TimeUnit timeUnit) throws DviException { + if (deviceName == null) { + deviceName = "pnmraw"; + } + + GhostscriptCommandBuilder gs = new GhostscriptCommandBuilder(ctx); + gs.setInputFile(null); + gs.setOutputFile(null); + gs.setResolution(res.dpi()); + gs.setDevice(deviceName); + gs.setFirstPage(pageNum); + gs.setLastPage(pageNum); + gs.setTextAlpha(0); // textAlpha and graphicsAlpha have no effects for PNM + // devices. + gs.setGraphicsAlpha(0); + CommandShell shell = gs.createCommandShell(); + shell.setTimeout(timeout, timeUnit); + final PnmSplitter splitter = new PnmSplitter(unitSize, imageWriter); + splitter.setShrinkFactor(res.shrinkFactor()); + final BufferFilter stdoutFilter = new BufferFilter(16384); + CommandShellHandler handler = new CommandShellHandler() { + public void handleStderr(InputStream in) throws IOException { + try { + DviUtils.dumpStreamAsync("gs stderr", in, System.err).join(); + } catch (InterruptedException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + } + } + + public void handleStdin(OutputStream out) throws IOException { + try { + byte[] buf = new byte[16384]; + BufferedInputStream bis = new BufferedInputStream(is); + do { + int len = bis.read(buf); + if (len < 0) + break; + out.write(buf, 0, len); + } while (true); + } finally { + DviUtils.silentClose(out); + DviUtils.silentClose(is); + } + } + + public void handleStdout(InputStream in) throws IOException, DviException { + stdoutFilter.beginInput(in); + try { + splitter.splitImageFromStream(stdoutFilter); + } finally { + try { + stdoutFilter.endInput(); + } catch (Exception e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + } + DviUtils.silentClose(in); + } + } + }; + shell.setHandler(handler); + int ret; + + try { + ret = shell.execute(); + } catch (IOException e) { + LOGGER.warning("Ghostscript failed with output: " + new String(stdoutFilter.getBuffer())); + throw new DviException(e); + } catch (InterruptedException e) { + LOGGER.warning("Ghostscript failed with output: " + new String(stdoutFilter.getBuffer())); + throw new DviException(e); + } + if (ret != 0) { + LOGGER.warning("Ghostscript failed with output: " + new String(stdoutFilter.getBuffer())); + throw new DviException("Ghostscript failed with exit code " + ret); + } + } + + public static DviRect mapToDviCoordinate(DviRect postScriptRect, DviPaperSize paperSize, DviResolution res) + { + DviRect paperRect = paperSize.toBoundingBox(res); + return new DviRect(postScriptRect.x(), paperRect.y() - postScriptRect.y(), postScriptRect.width(), postScriptRect.height()); + } + + public static String [] listGhostscriptExecutables() + { + final ArrayList list = new ArrayList(); + final ArrayList candidates = new ArrayList(); + + if (DviUtils.isWindows()) { + candidates.add("gswin32c"); + } + candidates.add("gs"); + + LOGGER.fine("Start detecting Ghostscript."); + for (String path : candidates) { + LOGGER.fine("Trying " + path); + try { + CommandShell cs = new CommandShell(); + cs.setCommandLine(path, "-dSAFER", "-dPARANOIDSAFER", "-dDELAYSAFER", "-dNOPAUSE", "-dBATCH", "-help"); + cs.setHandler(new CommandShellHandlerImpl(path, list)); + cs.execute(); + } catch (Exception e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + } + } + LOGGER.fine("Finished detecting Ghostscript."); + + return list.toArray(new String[list.size()]); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/DefaultDviLayoutManager.java b/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/DefaultDviLayoutManager.java new file mode 100644 index 0000000..74537dd --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/DefaultDviLayoutManager.java @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.gui.swing; + +import java.awt.Color; +import java.awt.GridLayout; +import java.awt.LayoutManager; +import java.util.logging.Logger; + +import javax.swing.BorderFactory; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviPaperSize; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviDocument; +import jp.sourceforge.dvibrowser.dvicore.api.DviPage; +import jp.sourceforge.dvibrowser.dvicore.ctx.DviToolkit; + + +public class DefaultDviLayoutManager +extends DviObject +implements DviLayoutManager +{ + private static final Logger LOGGER = Logger.getLogger(DefaultDviLayoutManager.class.getName()); + private int cols; + private int horizontalSpacing; + private int verticalSpacing; + private int paddingSize; + private DviPaperSize paperSize; + private boolean crop; + private boolean enableDelayedRendering = true; + + public DefaultDviLayoutManager(DviContextSupport dcs, int cols, int paddingSize) + { + super(dcs); + setNumberOfColumns(cols); + setPaddingSize(paddingSize); + } + + public DefaultDviLayoutManager(DviContextSupport dcs, int cols) + { + this(dcs, cols, 0); + } + + private int computeRows(DviDocument doc) + throws DviException + { + int rows = (doc.getTotalPages() + cols - 1)/ cols; + return rows; + } + + public LayoutManager createLayout(DviDocument doc, DviResolution res) + throws DviException + { + return new GridLayout(computeRows(doc), cols, horizontalSpacing, verticalSpacing); +// return new FlowLayout(); + } + + public DviRect getPageBoundingBox(DviDocument doc, DviResolution res) + throws DviException + { + DviToolkit utils = getDviContext().getDviToolkit(); + if (getEnableCrop()) { + DviRect bbox = DviRect.union(utils.computeBoundingBoxes(doc, res)); + return bbox; + } else { + DviPaperSize ps = null; + try { + ps = getDviContext().getDefaultPaperSize(); + } catch (DviException e) { + LOGGER.warning(e.toString()); + } + return utils.computePageBoundingBox(ps, res); + } + } + + public DviRect getBoundingBox(DviDocument doc, DviResolution res) + throws DviException + { + int rows = computeRows(doc); + DviRect bbox = getPageBoundingBox(doc, res); + DviRect ret = new DviRect + (0, 0, bbox.width() * cols + horizontalSpacing * (cols -1) + paddingSize * (cols + 1) + 16 * (cols), + bbox.height() * rows + verticalSpacing * (rows - 1) + paddingSize * (rows + 1) + 16 * (cols)); + return ret; + } + + public int getNumberOfColumns() { return cols; } + public void setNumberOfColumns(int cols) { + this.cols = Math.max(0, cols); + } + + public int getHorizontalSpacing() + { + return horizontalSpacing; + } + + public void setHorizontalSpacing(int horizontalSpacing) + { + this.horizontalSpacing = horizontalSpacing; + } + + public int getVerticalSpacing() + { + return verticalSpacing; + } + + public void setVerticalSpacing(int verticalSpacing) + { + this.verticalSpacing = verticalSpacing; + } + + public void decoratePage(TDviDocument tdd, TDviPage dp) + throws DviException + { +// DviRect bbox = determinePageSize(dp); +// dp.setBoundingBox(bbox); + dp.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, new Color(190, 190, 190))); + } + + public int getPaddingSize() + { + return paddingSize; + } + + public void setPaddingSize(int paddingSize) + { + this.paddingSize = paddingSize; + } + + public void setPaperSize(DviPaperSize paperSize) + { + this.paperSize = paperSize; + } + + public DviPaperSize getPaperSize() + { + return paperSize; + } + + public void setEnableCrop(boolean crop) + { + this.crop = crop; + } + + public boolean getEnableCrop() + { + return crop; + } + + public boolean getEnableDelayedRendering(TDviPage dp) throws DviException + { + return enableDelayedRendering; + } + + public void setEnableDelayedRendering(boolean enableDelayedRendering) + { + this.enableDelayedRendering = enableDelayedRendering; + } + + public DviRect determinePageSize(TDviPage dp) throws DviException + { + DviRect bbox = null; + DviPage page = dp.getPage(); + ViewSpec viewSpec = dp.getViewSpec(); + DviResolution res = viewSpec.getResolution(); + if (page != null) { + bbox = getPageBoundingBox(page.getDocument(), res); + } + if (bbox == null) { + DviToolkit utils = getDviContext().getDviToolkit(); + bbox = utils.computePageBoundingBox(viewSpec.getPaperSize(), res); + } + return bbox.addPadding(paddingSize); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/DragToScroll.java b/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/DragToScroll.java new file mode 100644 index 0000000..f73ac3e --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/DragToScroll.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.gui.swing; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.MouseEvent; + +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.JViewport; +import javax.swing.SwingUtilities; +import javax.swing.event.MouseInputAdapter; + +// TODO: support logging +public class DragToScroll +extends MouseInputAdapter +{ + // Should we make them weak-references? + private final JScrollPane jsp; + private final JScrollBar hsb, vsb; + // TODO: Handle property change by sp.setXXXScrollBar(). + + public DragToScroll(JScrollPane jsp) { + this.jsp = jsp; + hsb = jsp.getHorizontalScrollBar(); + vsb = jsp.getVerticalScrollBar(); + } + + public JScrollPane scrollPane() { return jsp; } + + public void add(Component c) { + if (c == null) return; + addComponent(c); + if (c instanceof Container) { + Component [] cs = ((Container) c).getComponents(); + for (int i=0; i pageList + = new ArrayList(); + + private ViewSpec viewSpec; + private DviLayoutManager dviLayout = new DefaultDviLayoutManager(this, 1); + + public void setViewSpec(ViewSpec vs) throws DviException { + if (viewSpec != null) { + viewSpec.removeChangeListener(this); + } + viewSpec = vs; + if (viewSpec != null) { + viewSpec.addChangeListener(this); + } + reload(); + } + + public ViewSpec getViewSpec() { + return viewSpec; + } + + private final DviContextSupport dcs; + public DviContext getDviContext() { return dcs.getDviContext(); } + + public TDviDocument(DviContextSupport dcs) { + this.dcs = dcs; + viewSpec = new ViewSpec(this); + viewSpec.setResolution(viewSpec.getResolution().approximate(10)); + initializeComponents(); + } + + private void initializeComponents() + { +// setBackground(new Color(0xe0, 0xe0, 0xe0)); + setLayout(new FlowLayout()); + add(panel); + } + + private boolean enableDelayedRendering = false; + + private DviDocument doc; + public void setDviDocument(DviDocument doc) throws DviException + { + LOGGER.fine("Preparaing TDviDocument with viewSpec=" + viewSpec); + this.doc = doc; + try { + panel.removeAll(); + pageList.clear(); + LOGGER.finer("dvi document = " + doc); + if (doc != null) { + panel.setLayout(getDviLayout().createLayout(doc, viewSpec.getResolution())); + for (DviPage page : doc.getPages()) { + LOGGER.fine("preparing TDviPage viewSpec=" + viewSpec); + TDviPage dp = new TDviPage(this); + dp.setViewSpec(viewSpec); + dp.setDviLayout(dviLayout); + dp.setPage(page); + getDviLayout().decoratePage(this, dp); + dp.setVisible(true); + dp.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + TDviDocument.this.fireChangeEvent(); + } + }); + { + MouseListener[] mls = getMouseListeners(); + for (int j = 0; j < mls.length; j++) { + dp.addMouseListener(mls[j]); + } + } + { + MouseMotionListener[] mmls = getMouseMotionListeners(); + for (int j = 0; j < mmls.length; j++) { + dp.addMouseMotionListener(mmls[j]); + } + } + panel.add(dp); + pageList.add(dp); + } + } else { + LOGGER.finer("dvi document is null"); + } + } catch (Exception ex) { + LOGGER.severe(ex.toString()); + } + revalidate(); + repaint(); + } + + + public void reload() + throws DviException + { + setDviDocument(doc); + } + + public DviDocument getDviDocument() { + return doc; + } + + public DviLayoutManager getDviLayout() + { + return dviLayout; + } + + public void setDviLayout(DviLayoutManager dviLayout) + throws DviException + { + this.dviLayout = dviLayout; + reload(); + } + + public void setEnableDelayedRendering(boolean enableDelayedRendering) + { + this.enableDelayedRendering = enableDelayedRendering; + } + + public boolean getEnableDelayedRendering() + { + return enableDelayedRendering; + } + + public void stateChanged(ChangeEvent e) + { + LOGGER.fine("stateChanged: EDT=" + SwingUtilities.isEventDispatchThread() + " viewSpec=" + viewSpec); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + try { + reload(); + } catch (DviException e) { + LOGGER.warning(e.toString()); + } + } + }); + } + + public void addChangeListener(ChangeListener l) + { + listenerList.add(ChangeListener.class, l); + } + + public void removeChangeListener(ChangeListener l) + { + listenerList.remove(ChangeListener.class, l); + } + + protected void fireChangeEvent() + { + ChangeEvent event = null; + + Object[] listeners = listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i] == ChangeListener.class) { + if (event == null) + event = new ChangeEvent(this); + ((ChangeListener)listeners[i+1]).stateChanged(event); + } + } + } + + public boolean isBusy() + { + for (TDviPage dp : pageList) { + if (dp.isBusy()) return true; + } + return false; + } + +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/TDviPage.java b/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/TDviPage.java new file mode 100644 index 0000000..b4f4804 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/TDviPage.java @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.gui.swing; + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.logging.Logger; + +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.api.DviContext; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviPage; +import jp.sourceforge.dvibrowser.dvicore.ctx.DviToolkit; +import jp.sourceforge.dvibrowser.dvicore.util.DaemonThreadFactory; + + +public class TDviPage extends JPanel implements DviContextSupport, ChangeListener +{ + private static final Logger LOGGER = Logger.getLogger(TDviPage.class.getName()); + private static final long serialVersionUID = -7167678585159838308L; + + private boolean busy = false; + + private final DviContextSupport dcs; + public DviContext getDviContext() { return dcs.getDviContext(); } + + public TDviPage(DviContextSupport dcs, DviPage page) { + super(); + this.dcs = dcs; + this.viewSpec = new ViewSpec(this); + this.viewSpec.setResolution(viewSpec.getResolution().approximate(200)); + setPage(page); + } + + public TDviPage(DviContextSupport dcs) { + this(dcs, null); + } + + private DviPage page = null; + + public void setPage(DviPage page) + { + this.page = page; + determineSize(); + } + + public DviPage getPage() { return page; } + + private ViewSpec viewSpec; + + public void setViewSpec(ViewSpec viewSpec) + { + LOGGER.fine("page=" + page + ",viewSpec=" + viewSpec); + this.viewSpec = viewSpec; + determineSize(); + } + + public ViewSpec getViewSpec() { return viewSpec; } + +// private DviRect bbox; +// +// public void setBoundingBox(DviRect bbox) +// { +// this.bbox = bbox; +// determineSize(); +// } +// +// public DviRect getBoundingBox() +// { +// return bbox; +// } + +// private Anchor.Href myHref = null; +// private DviRect saveBBOX = null; +// +// public ByteRange getByteRangeFor(DviRect rect) +// { +// try { +// DviResolution res = viewSpec.getResolution(); +// +// rect = rect.intersect(displayRect); +// if (rect.isEmpty()) +// return null; +// rect = rect.magnify(res.shrinkFactor()); +// +// Geometer geometer = new BasicGeometer(this); +// ByteRangeComputer brc = new ByteRangeComputer(this, res, rect); +// geometer.setPainter(brc); +// getDviContext().execute(page, geometer); +// AnchorSet anchors = (AnchorSet) rsc.getDataSource().find(AnchorSet.class, +// page); +// if (myHref != null) { +// anchors.remove(myHref); +// } +// ByteRange br = brc.getByteRange(); +// anchors.add(myHref = new Anchor.Href(br.begin(), br.end(), "none")); +// if (saveBBOX != null) { +// DviRect r = saveBBOX; +// repaint(r.x(), r.y(), r.width(), r.height()); +// } +// DviRect r = brc.getBounds().shrink(res.shrinkFactor()); +// repaint(r.x(), r.y(), r.width(), r.height()); +// saveBBOX = r; +// return br; +// } catch (DviException ex) { +// Logger.trace(ex); +// return null; +// } +// } + + private DviRect displayRect = null; + + public void determineSize() + { + final DviToolkit utils = getDviContext().getDviToolkit(); + displayRect = null; + try { + if (layout != null) + displayRect = layout.determinePageSize(this); + } catch (Exception e) { + LOGGER.severe(e.toString()); + e.printStackTrace(); + } + if (displayRect == null) { + displayRect = utils.computePageBoundingBox + (viewSpec.getPaperSize(), viewSpec.getResolution()); + } + + setPreferredSize(new Dimension(displayRect.width(), displayRect.height())); + setSize(new Dimension(displayRect.width(), displayRect.height())); + revalidate(); + } + + private static ExecutorService exe = Executors.newFixedThreadPool(3, new DaemonThreadFactory()); + + protected ExecutorService getExecutorService() + { + return exe; + } + + protected void startPagePreparation(Graphics g, final Rectangle rect, final DviPage page, final ViewSpec viewSpec) + { + final DviToolkit utils = getDviContext().getDviToolkit(); + + LOGGER.finer("Preparing page for paint: " + page); + getExecutorService().submit(new Runnable() { + public void run() + { + try { + utils.prepareForRendering(page, viewSpec); + } catch (Exception e) { + LOGGER.warning(e.toString()); + } + SwingUtilities.invokeLater(new Runnable() { + public void run() + { + setBusy(false); + repaint(); + } + }); + } + }); + setBusy(true); + paintDummyContents(g, rect, viewSpec); + } + + private void paintDummyContents(Graphics g, final Rectangle rect, + final ViewSpec viewSpec) + { + g.setColor(viewSpec.getBackgroundColor().toColor()); + g.fillRect(rect.x, rect.y, rect.width, rect.height); + } + + protected void paintComponent(Graphics g) + { + super.paintComponent(g); + + final DviToolkit utils = getDviContext().getDviToolkit(); + + if (page == null) return; + + final Rectangle rect = g.getClipBounds(); + g.fillRect(rect.x, rect.y, rect.width, rect.height); + + boolean enableDelayedRendering = true; + + try { + enableDelayedRendering = getEnableDelayedRendering(); + } catch (DviException e1) { + LOGGER.warning(e1.toString()); + } + + if (enableDelayedRendering) { + if (!utils.canRenderPageImmediately(page, viewSpec)) { + LOGGER.finest("delayed rendering"); + startPagePreparation(g, rect, page, viewSpec); + return; + } + } + + try { + LOGGER.finest("rendering page=" + page.getPageNumber() + " rect=" + rect + " viewSpec=" + viewSpec); +// DviRect targetArea = new DviRect +// (rect.x + displayRect.x(), rect.y + displayRect.y(), rect.width+1, rect.height+1); + DviRect targetArea = DviRect.fromRectangle(rect).translate(displayRect.topLeft()); + if (!targetArea.isEmpty()) { + BufferedImage img = utils.renderToBufferedImage(page, targetArea, viewSpec); + g.drawImage(img, rect.x, rect.y, null); + } + } catch (DviException e) { + LOGGER.warning(e.toString()); + e.printStackTrace(); + paintDummyContents(g, rect, viewSpec); + } + } + + public void stateChanged(ChangeEvent e) + { + LOGGER.fine("stateChanged called: EDT=" + SwingUtilities.isEventDispatchThread()); + SwingUtilities.invokeLater(new Runnable() { + public void run() + { + determineSize(); + revalidate(); + repaint(); + } + }); + } + + private DviLayoutManager layout = new DefaultDviLayoutManager(this, 1); + + public boolean getEnableDelayedRendering() + throws DviException + { + if (layout == null) return true; + return layout.getEnableDelayedRendering(this); + } + + public DviLayoutManager getDviLayout() + { + return layout; + } + + public void setDviLayout(DviLayoutManager layout) + { + if (layout == null) + throw new NullPointerException("layout"); + this.layout = layout; + } + + protected void setBusy(boolean busy) { + this.busy = busy; + fireChangeEvent(); + } + + public boolean isBusy() { + return busy; + } + + protected EventListenerList listenerList = new EventListenerList(); + + public void addChangeListener(ChangeListener l) + { + listenerList.add(ChangeListener.class, l); + } + + public void removeChangeListener(ChangeListener l) + { + listenerList.remove(ChangeListener.class, l); + } + + protected void fireChangeEvent() + { + ChangeEvent event = null; + + Object[] listeners = listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i] == ChangeListener.class) { + if (event == null) + event = new ChangeEvent(this); + ((ChangeListener)listeners[i+1]).stateChanged(event); + } + } + } + +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/TScrollPane.java b/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/TScrollPane.java new file mode 100644 index 0000000..399a432 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/TScrollPane.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.gui.swing; + +import java.awt.Component; +import java.awt.Graphics; + +import javax.swing.JScrollPane; + +// Used in dvibrowser to minimize paints. +public class TScrollPane extends JScrollPane { + private static final long serialVersionUID = -2913809707498868152L; + + public TScrollPane() { + super(); + } + + public TScrollPane(Component view) { + super(view); + } + + private boolean updating = false; + + public void beginUpdate() { + updating = true; + } + + public void endUpdate() { + updating = false; + repaint(); + } + + public void paintComponent(Graphics g) { + if (!updating) { + super.paintComponent(g); + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/TexLogViewer.java b/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/TexLogViewer.java new file mode 100644 index 0000000..5b0089c --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/TexLogViewer.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.gui.swing; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; + +public class TexLogViewer extends JPanel { + private static final long serialVersionUID = 7630772409309800485L; + private final JScrollPane scroll; + private final JTextArea textArea; + private boolean hasError = false; + + private File dviFile; + public TexLogViewer(int rows, int cols) { + setDviFile(null); + textArea = new JTextArea(rows, cols); + textArea.setOpaque(true); + textArea.setEditable(false); + scroll = new JScrollPane(textArea); + setLayout(new BorderLayout()); + add(scroll, BorderLayout.CENTER); + } + + public File getDviFile() { return dviFile; } + public void setDviFile(File dviFile) { + this.dviFile = dviFile; + setupView(); + } + + private File getLogFile() { + String filename = dviFile.getPath(); + String filenameBase = filename.replaceFirst("\\.[_a-zA-Z0-9]*$", ""); + File logFile = new File(filenameBase + ".log"); + return logFile; + } + + private void setupView() { + hasError = false; + if (dviFile == null) return; + + File logFile = getLogFile(); + boolean success = true; + if (logFile.exists()) { + StringBuilder sb = new StringBuilder(); + String extraInfo = ""; + try { + Scanner s = new Scanner(logFile); + while (s.hasNextLine()) { + String line = s.nextLine(); + sb.append(line); + if (0 == line.indexOf("! Emergency stop.")) { + success = false; + Pattern pat = Pattern.compile("^l.([0-9]*) (.*)$"); + while (s.hasNextLine()) { + line = s.nextLine(); + sb.append(line); + Matcher mat = pat.matcher(line); + if (mat.matches()) { + extraInfo = line; + break; + } + } + } + sb.append("\n"); + } + s.close(); + sb.append("---[FOUND ERRORS]---\n"); + sb.append(extraInfo + "\n"); + textArea.setText(sb.toString()); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + if (success) { + textArea.setBackground(null); + } else { + textArea.setBackground(new Color(0xff, 0xcc, 0x60)); + } + hasError = !success; + } + + public boolean hasError() { return hasError; } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/ViewSpec.java b/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/ViewSpec.java new file mode 100644 index 0000000..3772fe8 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/gui/swing/ViewSpec.java @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.gui.swing; + +// mutable. +// TODO: make this class independent of Swing and move it to another package. +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; + +import jp.sourceforge.dvibrowser.dvicore.DviColor; +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviPaperSize; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.GammaCorrector; +import jp.sourceforge.dvibrowser.dvicore.render.DefaultGammaCorrector; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + + +public class ViewSpec +extends DviObject +implements Cloneable +{ + private static final Logger LOGGER = Logger.getLogger(ViewSpec.class.getName()); + + protected EventListenerList listenerList = new EventListenerList(); + + public void addChangeListener(ChangeListener l) + { + listenerList.add(ChangeListener.class, l); + } + + public void removeChangeListener(ChangeListener l) + { + listenerList.remove(ChangeListener.class, l); + } + + protected void fireChangeEvent() + { + ChangeEvent event = null; + + Object[] listeners = listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i] == ChangeListener.class) { + if (event == null) + event = new ChangeEvent(this); + ((ChangeListener)listeners[i+1]).stateChanged(event); + } + } + } + + // TODO: outsource configurations to a config file. + private DviColor backgroundColor = new DviColor(255, 255, 255); + private int epsResolutionDpi = 200; + private String epsImageFileExtension = ".jpg"; + private String epsImageDeviceName = "jpeg"; // passed to Ghostscript + + private DviColor foregroundColor = new DviColor(0, 0, 0); + private static final GammaCorrector defaultGammaCorrector = new DefaultGammaCorrector(1.4, 1.2); + private GammaCorrector gammaCorrector = defaultGammaCorrector; + + private DviPaperSize paperSize; + + private boolean postScriptEnabled = true; + + private DviResolution res; + + public ViewSpec(DviContextSupport dcs) { + super(dcs); + try { + res = getDviContext().getDefaultResolution(); + } catch (DviException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + } + if (res == null) { + res = new DviResolution(2400, 20); + } + } + + // Note that we don't copy the listeners. + public Object clone() + { + try { + ViewSpec vs = (ViewSpec) super.clone(); + vs.backgroundColor = this.backgroundColor; + vs.epsResolutionDpi = this.epsResolutionDpi; + vs.foregroundColor = this.foregroundColor; + vs.gammaCorrector = this.gammaCorrector; + vs.paperSize = this.paperSize; + vs.postScriptEnabled = this.postScriptEnabled; + vs.res = this.res; + vs.epsImageDeviceName = this.epsImageDeviceName; + vs.epsImageFileExtension = this.epsImageFileExtension; + vs.epsResolutionDpi = this.epsResolutionDpi; + return vs; + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + } + + public DviColor getBackgroundColor() + { + return backgroundColor; + } + + public int getEpsResolutionDpi() + { + return epsResolutionDpi; + } + + public DviColor getForegroundColor() + { + return foregroundColor; + } + + public GammaCorrector getGammaCorrector() + { + return gammaCorrector; + } + public DviPaperSize getPaperSize() + { + return paperSize; + } + public DviResolution getResolution() + { + return res; + } + + public boolean isPostScriptEnabled() + { + return postScriptEnabled; + } + public void setPostScriptEnabled(boolean postScriptEnabled) + { + this.postScriptEnabled = postScriptEnabled; + fireChangeEvent(); + } + + public void setBackgroundColor(DviColor c) + { + backgroundColor = c; + fireChangeEvent(); + } + + public void setEpsResolutionDpi(int epsResolutionDpi) + { + this.epsResolutionDpi = epsResolutionDpi; + fireChangeEvent(); + } + + public void setForegroundColor(DviColor c) + { + foregroundColor = c; + fireChangeEvent(); + } + + public void setGammaCorrector(GammaCorrector gc) + { + this.gammaCorrector = gc; + fireChangeEvent(); + } + + public void setPaperSize(DviPaperSize paperSize) + { + this.paperSize = paperSize; + fireChangeEvent(); + } + + public void setResolution(DviResolution res) + { + this.res = res; + LOGGER.finer("res=" + res); + fireChangeEvent(); + } + + public void setEpsImageFileExtension(String epsImageFileExtension) + { + this.epsImageFileExtension = epsImageFileExtension; + fireChangeEvent(); + } + + public String getEpsImageFileExtension() + { + return epsImageFileExtension; + } + + public void setEpsImageDeviceName(String epsImageDevice) + { + this.epsImageDeviceName = epsImageDevice; + fireChangeEvent(); + } + + public String getEpsImageDeviceName() + { + return epsImageDeviceName; + } + + public String toString() + { + return getClass().getName() + + "[backgroundColor=" + this.backgroundColor + + ",epsResolutionDpi=" + this.epsResolutionDpi + + ",foregroundColor=" + this.foregroundColor + + ",gammaCorrector=" + this.gammaCorrector + + ",paperSize=" + this.paperSize + + ",postScriptEnabled=" + this.postScriptEnabled + + ",resolution=" + this.res + + "]" + ; + } + + public void setApproximateDpi(double dpi) { + setResolution(res.approximate(dpi)); + } + + public static GammaCorrector getDefaultGammaCorrector() { + return defaultGammaCorrector; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/AbstractPnmAsciiFilter.java b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/AbstractPnmAsciiFilter.java new file mode 100644 index 0000000..6262601 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/AbstractPnmAsciiFilter.java @@ -0,0 +1,110 @@ +package jp.sourceforge.dvibrowser.dvicore.image.pnm; +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +public abstract class AbstractPnmAsciiFilter +extends FilterInputStream +{ + protected BufferedReader reader; + protected ByteArrayInputStream byteArrayInput; + + public AbstractPnmAsciiFilter(InputStream in) { + super(in); + reader = new BufferedReader(new InputStreamReader(in)); + } + + protected synchronized void fill() throws IOException + { + if (reader == null) { + throw new IOException("EOF detected while reading the input"); + } + if (byteArrayInput != null && byteArrayInput.available() > 0) { + return; + } + + byteArrayInput = new ByteArrayInputStream(fillBuffer()); + } + + protected abstract byte [] fillBuffer() throws IOException; + + @Override + public synchronized int available() throws IOException + { + fill(); + return byteArrayInput.available(); + } + + @Override + public synchronized void close() throws IOException + { + reader.close(); + } + + @Override + public void mark(int readLimit) + { + throw new UnsupportedOperationException("mark is not supported"); + } + + @Override + public void reset() + { + throw new UnsupportedOperationException("reset is not supported"); + } + + @Override + public boolean markSupported() + { + return false; + } + + @Override + public synchronized int read() throws IOException + { + fill(); + return byteArrayInput.read(); + } + + @Override + public synchronized int read(byte [] buf, int off, int len) throws IOException + { + fill(); + return byteArrayInput.read(buf, off, len); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/AbstractPnmSplitter.java b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/AbstractPnmSplitter.java new file mode 100644 index 0000000..31a1187 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/AbstractPnmSplitter.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ +package jp.sourceforge.dvibrowser.dvicore.image.pnm; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviRectSplitter; +import jp.sourceforge.dvibrowser.dvicore.DviSize; +import jp.sourceforge.dvibrowser.dvicore.image.split.ImageSplitter; +import jp.sourceforge.dvibrowser.dvicore.image.split.SplitImageWriter; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + + +public abstract class AbstractPnmSplitter +implements ImageSplitter +{ + private static final Logger LOGGER = Logger.getLogger(AbstractPnmSplitter.class + .getName()); + protected final SplitImageWriter imageWriter; + protected DataInputStream input; + protected PnmHeader header; + private final DviSize unitSize; + private int shrinkFactor = 1; + + public AbstractPnmSplitter(DviSize unitSize, SplitImageWriter imageWriter) + { + this.unitSize = unitSize; + if (imageWriter == null) + throw new IllegalArgumentException("imageWriter can't be null"); + + this.imageWriter = imageWriter; + header = null; + } + + public PnmHeader getPnmHeader() + { + return header; + } + + + protected void beginSplitInternal(PnmHeader header, InputStream is) + throws DviException + { + this.header = header; + LOGGER.fine("PnmHeader: " + header); + input = new DataInputStream(is); + } + + protected void endSplitInternal() + throws DviException + { + } + + protected abstract byte [] createLineBuffer(); + + protected abstract BufferedImage createBufferedImage(DviRect box); + + protected abstract int copyLineToDataBuffer(byte [] buf, int x, DviRect box, int i, DataBufferByte data); + + protected void readFully(byte [] buf) throws IOException + { + input.readFully(buf); + } + + protected DviRectSplitter createRectSplitter(DviRect rect, DviSize unitSize) + { + return new DviRectSplitter(rect, unitSize); + } + + public void splitImageFromStream(InputStream is) + throws IOException, DviException + { + try { + PnmHeader header = PnmHeader.parseHeader(is); + beginSplitInternal(header, is); + try { + DviRect rect = new DviRect(0, 0, header.getWidth(), header.getHeight()); + final int sf = shrinkFactor; + final DviSize samplingSize = unitSize.magnify(sf); + DviRectSplitter splitter = createRectSplitter(rect.shrink(sf), unitSize); + DviRectSplitter samplingSplitter = createRectSplitter(rect, samplingSize); + + DviRect [][] rects = splitter.getRects(); + DviRect [][] samplingRects = samplingSplitter.getRects(); + int rows = splitter.getNumRows(); + int cols = splitter.getNumColumns(); + + imageWriter.beginSplitImage(this, splitter); + + try { + byte [] buf = createLineBuffer(); + for (int row=0; row= shrinkFactor) + throw new IllegalArgumentException("shrinkFactor is non-positive."); + this.shrinkFactor = shrinkFactor; + } + + public int getShrinkFactor() { + return shrinkFactor; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PbmSplitter.java b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PbmSplitter.java new file mode 100644 index 0000000..7a608ac --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PbmSplitter.java @@ -0,0 +1,73 @@ +package jp.sourceforge.dvibrowser.dvicore.image.pnm; +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.awt.image.IndexColorModel; + +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviSize; +import jp.sourceforge.dvibrowser.dvicore.image.split.SplitImageWriter; + +public class PbmSplitter +extends AbstractPnmSplitter +{ +// private static final Logger LOGGER = Logger.getLogger(PbmSplitter.class +// .getName()); + public PbmSplitter(DviSize unitSize, SplitImageWriter imageWriter) + { + super(unitSize, imageWriter); + } + + @Override + protected byte [] createLineBuffer() + { + return new byte [(header.getWidth() + 7) / 8]; + } + + @Override + protected BufferedImage createBufferedImage(DviRect box) + { + final byte[] colors = {(byte)255, 0}; + final IndexColorModel cm = new IndexColorModel(1,2,colors,colors,colors); + return new BufferedImage(box.width(), box.height(), BufferedImage.TYPE_BYTE_BINARY, cm); + } + + @Override + protected int copyLineToDataBuffer(byte [] buf, int x, DviRect box, int i, DataBufferByte data) + { + final int uw = (box.width() + 7) /8; + System.arraycopy(buf, x, data.getData(), i * uw, uw); + return uw; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PgmSplitter.java b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PgmSplitter.java new file mode 100644 index 0000000..a23ecf6 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PgmSplitter.java @@ -0,0 +1,95 @@ +package jp.sourceforge.dvibrowser.dvicore.image.pnm; +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.io.InputStream; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviSize; +import jp.sourceforge.dvibrowser.dvicore.image.split.SplitImageWriter; + +public class PgmSplitter +extends AbstractPnmSplitter +{ +// private static final Logger LOGGER = Logger.getLogger(PgmSplitter.class +// .getName()); + public PgmSplitter(DviSize unitSize, SplitImageWriter imageWriter) + { + super(unitSize, imageWriter); + } + + private final int [] table = new int[256]; + + @Override + protected void beginSplitInternal(PnmHeader header, InputStream is) throws DviException + { + super.beginSplitInternal(header, is); + int maxval = header.getMaxValue(); + for (int i=0; i<256; i++) { + table[i] = Math.max(Math.min(i * maxval / 255, maxval), 0); + } + } + + @Override + protected byte [] createLineBuffer() + { + return new byte [header.getWidth()]; + } + + @Override + protected BufferedImage createBufferedImage(DviRect box) + { + //TODO: use color model. + BufferedImage bi = new BufferedImage(box.width(), box.height(), BufferedImage.TYPE_BYTE_GRAY); + return bi; + } + + @Override + protected int copyLineToDataBuffer(final byte [] buf, final int x, final DviRect box, final int i, final DataBufferByte data) + { + final int w = box.width(); + final int uw = w; + final byte [] dst = data.getData(); + for (int j=0; j= 0) return b; + return 256 + b; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PnmBitAsciiFilter.java b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PnmBitAsciiFilter.java new file mode 100644 index 0000000..c0e6f3c --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PnmBitAsciiFilter.java @@ -0,0 +1,73 @@ +package jp.sourceforge.dvibrowser.dvicore.image.pnm; +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + + +public class PnmBitAsciiFilter +extends AbstractPnmAsciiFilter +{ + public PnmBitAsciiFilter(InputStream in) { + super(in); + } + + protected synchronized byte [] fillBuffer() throws IOException + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + String line = reader.readLine(); + if (line == null) { + throw new IOException("EOF detected while reading the input"); + } + while (line.length() > 0) { + String d = null; + if (line.length() >= 8) { + d = line.substring(0, 8); + line = line.substring(8); + } else { + d = (line + "0000000").substring(0, 8); + line = ""; + } + try { + baos.write(Integer.parseInt(d, 2)); + } catch (NumberFormatException e) { + throw new IOException("Input format error: data is not binary: " + line); + } + } + if (baos.size() == 0) { + throw new IOException("EOF detected while reading the input"); + } + return baos.toByteArray(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PnmByteAsciiFilter.java b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PnmByteAsciiFilter.java new file mode 100644 index 0000000..bceb63d --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PnmByteAsciiFilter.java @@ -0,0 +1,72 @@ +package jp.sourceforge.dvibrowser.dvicore.image.pnm; +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.StringTokenizer; + + +public class PnmByteAsciiFilter +extends AbstractPnmAsciiFilter +{ + private static final int BUFFER_SIZE = 1024; + private static final String DELIMS = " \t\r\n"; + + public PnmByteAsciiFilter(InputStream in) { + super(in); + } + + protected synchronized byte [] fillBuffer() throws IOException + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + String line = reader.readLine(); + if (line == null) { + throw new IOException("EOF detected while reading the input"); + } + StringTokenizer st = new StringTokenizer(line, DELIMS); + while (st.hasMoreTokens() && baos.size() < BUFFER_SIZE) { + String hex = st.nextToken(); + try { + int value = Integer.parseInt(hex, 10); + baos.write(value); + } catch (NumberFormatException e) { + throw new IOException("Input value is not a hexadecimal: " + hex); + } + } + if (baos.size() == 0) { + throw new IOException("EOF detected while reading the input"); + } + return baos.toByteArray(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PnmHeader.java b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PnmHeader.java new file mode 100644 index 0000000..226aae2 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PnmHeader.java @@ -0,0 +1,241 @@ +package jp.sourceforge.dvibrowser.dvicore.image.pnm; +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + + +import java.io.IOException; +import java.io.InputStream; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + + + +public final class PnmHeader +{ + private static final Logger LOGGER = Logger.getLogger(PnmHeader.class + .getName()); + + public static final String PNM_COMMENT_NEWLINE = "\n"; + + public static final int PNM_TYPE_BITMAP_ASCII = 1; + public static final int PNM_TYPE_GRAYMAP_ASCII = 2; + public static final int PNM_TYPE_PIXMAP_ASCII = 3; + public static final int PNM_TYPE_BITMAP_BINARY = 4; + public static final int PNM_TYPE_GRAYMAP_BINARY = 5; + public static final int PNM_TYPE_PIXMAP_BINARY = 6; + + private final int type; + private final int width; + private final int height; + private final int maxval; + private final String comment; + + public PnmHeader(int type, String comment, int width, int height, int maxval) + { + this.type = type; + this.comment = comment; + this.width = width; + this.height = height; + this.maxval = maxval; + } + + public boolean isBitmap() + { + return (PNM_TYPE_BITMAP_ASCII == type || PNM_TYPE_BITMAP_BINARY == type); + } + + public boolean isGraymap() + { + return (PNM_TYPE_GRAYMAP_ASCII == type || PNM_TYPE_GRAYMAP_BINARY == type); + } + + public boolean isPixmap() + { + return (PNM_TYPE_PIXMAP_ASCII == type || PNM_TYPE_PIXMAP_BINARY == type); + } + + public boolean isASCII() + { + return (1 <= type && type <= 3); + } + + public boolean isBinary() + { + return !isASCII(); + } + + public int getType() { + return type; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public int getMaxValue() { + return maxval; + } + + public String toString() { + return getClass().getName() + "[type=" + type + ",width=" + width + + ",height=" + height + ",maxval=" + maxval + ",comment=" + comment + "]"; + } + + // P1: bitmap (ASCII) + // P2: graymap (ASCII) + // P3: pixmap (ASCII) + // P4: bitmap (binary) + // P5: graymap (binary) + // P6: pixmap (binary) + +// private static final Pattern patPnmMagicNumbers = Pattern.compile("P([1-6])"); + private static final Pattern patPnmComment = Pattern.compile("#\\s?(.*)"); + private static final Pattern patPnmSize = Pattern.compile("([0-9][0-9]*)\\s\\s*([0-9][0-9]*)"); + + public String readLine(InputStream is) + throws IOException + { + StringBuilder sb = new StringBuilder(); + + int c = -1; + do { + c = is.read(); + } while (c != '\n'); + + return sb.toString(); + } + + public static String readLine(InputStream is, int c, int delim) + throws IOException + { + String line = ""; + do { + if (c >= 0) { + line += (char) c; + } + c = is.read(); + if (c < 0) + return null; + } while (c != delim); + return line; + } + + + public static PnmHeader parseHeader(InputStream is) + throws IOException + { + int type=-1, width=-1, height=-1, maxval=-1; + String comment = null; + + { + int c1 = is.read(); + int c2 = is.read(); + + if (!(c1 == 'P' && '1' <= c2 && c2 <= '6')) + throw new IOException("Invalid PNM magic number: c1=" + (char) c1 + " c2=" + (char) c2); + type = c2 - '0'; + } + + int c = -1; + int delim = -1; + + c = is.read(); + + while (isNewLine(c)) { + delim = c; + c = is.read(); + } + + if (delim < 0) { + throw new IOException("Illegal data after PNM magic number: " + c); + } + + // Parse Comments. + String line = readLine(is, c, delim); + while (null != line) { + Matcher mat = patPnmComment.matcher(line); + if (!mat.matches()) break; + String s = mat.group(1); + comment = (comment == null) ? s : comment + PNM_COMMENT_NEWLINE + s; + line = readLine(is, -1, delim); + } + + // Parse size. + { + Matcher mat2 = patPnmSize.matcher(line); + if (mat2.matches()) { + try { + width = Integer.parseInt(mat2.group(1)); + height = Integer.parseInt(mat2.group(2)); + } catch (NumberFormatException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + } + } + } + if (width < 0 || height < 0) { + throw new IOException("Failed to decode PNM image size: " + line); + } + + // Parse max value (which is required for graymap and pixmap). + if (PNM_TYPE_BITMAP_ASCII == type || PNM_TYPE_BITMAP_BINARY == type) { + maxval = 1; + } else { + line = readLine(is, -1, delim); + try { + maxval = Integer.parseInt(line); + } catch (NumberFormatException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + } + if (maxval < 0) { + throw new IOException("Failed to decode PNM max value: " + line); + } + } + + return new PnmHeader(type, comment, width, height, maxval); + } + + private static boolean isNewLine(int c) { + return (c == '\r' || c == '\n'); + } + + public String getComment() { + return comment; + } +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PnmSplitter.java b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PnmSplitter.java new file mode 100644 index 0000000..446dee2 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PnmSplitter.java @@ -0,0 +1,118 @@ +package jp.sourceforge.dvibrowser.dvicore.image.pnm; +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.io.IOException; +import java.io.InputStream; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviSize; +import jp.sourceforge.dvibrowser.dvicore.image.split.SplitImageWriter; + +public class PnmSplitter +extends AbstractPnmSplitter +{ +// private static final Logger LOGGER = Logger.getLogger(PnmSplitter.class +// .getName()); + protected AbstractPnmSplitter delegate; + + public PnmSplitter(DviSize unitSize, SplitImageWriter imageWriter) + { + super(unitSize, imageWriter); + delegate = null; + } + + @Override + public void beginSplitInternal(PnmHeader header, InputStream is) throws DviException + { + super.beginSplitInternal(header, is); + final int type = header.getType(); + switch (type) { + case PnmHeader.PNM_TYPE_BITMAP_ASCII: + delegate = new PbmSplitter(getUnitSize(), imageWriter); + is = new PnmBitAsciiFilter(is); + break; + case PnmHeader.PNM_TYPE_GRAYMAP_ASCII: + delegate = new PgmSplitter(getUnitSize(), imageWriter); + is = new PnmByteAsciiFilter(is); + break; + case PnmHeader.PNM_TYPE_PIXMAP_ASCII: + delegate = new PpmSplitter(getUnitSize(), imageWriter); + is = new PnmByteAsciiFilter(is); + break; + case PnmHeader.PNM_TYPE_BITMAP_BINARY: delegate = new PbmSplitter(getUnitSize(), imageWriter); break; + case PnmHeader.PNM_TYPE_GRAYMAP_BINARY: delegate = new PgmSplitter(getUnitSize(), imageWriter); break; + case PnmHeader.PNM_TYPE_PIXMAP_BINARY: delegate = new PpmSplitter(getUnitSize(), imageWriter); break; + } + if (delegate != null) { + delegate.beginSplitInternal(header, is); + } else { + throw new IllegalStateException("Unsupported PNM image type: " + type); + } + } + + @Override + public void readFully(byte [] buf) throws IOException + { + delegate.readFully(buf); + } + + @Override + public void endSplitInternal() throws DviException + { + if (delegate != null) { + delegate.endSplitInternal(); + delegate = null; + } + } + + @Override + protected byte [] createLineBuffer() + { + return delegate.createLineBuffer(); + } + + @Override + protected BufferedImage createBufferedImage(DviRect box) + { + return delegate.createBufferedImage(box); + } + + @Override + protected int copyLineToDataBuffer(byte [] buf, int x, DviRect box, int i, DataBufferByte data) + { + return delegate.copyLineToDataBuffer(buf, x, box, i, data); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PpmSplitter.java b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PpmSplitter.java new file mode 100644 index 0000000..6d62efb --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/pnm/PpmSplitter.java @@ -0,0 +1,95 @@ +package jp.sourceforge.dvibrowser.dvicore.image.pnm; +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.io.InputStream; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviSize; +import jp.sourceforge.dvibrowser.dvicore.image.split.SplitImageWriter; + +public class PpmSplitter +extends AbstractPnmSplitter +{ +// private static final Logger LOGGER = Logger.getLogger(PpmSplitter.class +// .getName()); + public PpmSplitter(DviSize unitSize, SplitImageWriter imageWriter) + { + super(unitSize, imageWriter); + } + + private final int [] table = new int[256]; + + @Override + public void beginSplitInternal(PnmHeader header, InputStream is) throws DviException + { + super.beginSplitInternal(header, is); + int maxval = header.getMaxValue(); + for (int i=0; i<256; i++) { + table[i] = Math.max(Math.min(i * maxval / 255, maxval), 0); + } + } + + @Override + protected byte [] createLineBuffer() + { + return new byte [header.getWidth() * 3]; + } + + @Override + protected BufferedImage createBufferedImage(DviRect box) + { + return new BufferedImage(box.width(), box.height(), BufferedImage.TYPE_3BYTE_BGR); + } + + @Override + protected int copyLineToDataBuffer(byte [] buf, int x, DviRect box, int i, DataBufferByte data) + { + final int w = box.width(); + final int uw = w * 3; + final byte [] dst = data.getData(); + for (int j=0; j= 0) return b; + return 256 + b; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/split/AbstractSplitPiece.java b/src/jp/sourceforge/dvibrowser/dvicore/image/split/AbstractSplitPiece.java new file mode 100644 index 0000000..737c1d7 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/split/AbstractSplitPiece.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ +package jp.sourceforge.dvibrowser.dvicore.image.split; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviRectSplitter; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; + +public abstract class AbstractSplitPiece +implements SplitPiece +{ +// private static final Logger LOGGER = Logger +// .getLogger(AbstractSplitPiece.class.getName()); + private final DviResolution res; + private final DviRectSplitter rectSplitter; + private final int row; + private final int col; + private final SplitImage splitImage; + + public AbstractSplitPiece(SplitImage splitImage, DviResolution res, DviRectSplitter rectSplitter, int row, int col) + { + this.splitImage = splitImage; + this.res = res; + this.rectSplitter = rectSplitter; + this.row = row; + this.col = col; + } + + public DviResolution getResolution() + { + return res; + } + + public DviRectSplitter getRectSplitter() { + return rectSplitter; + } + + public int getRow() { + return row; + } + + public int getColumn() { + return col; + } + + public SplitImage getSplitImage() { + return splitImage; + } + + public DviRect getRect() throws DviException { + return getRectSplitter().getRectAt(row, col); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/split/DefaultSplitImageWriter.java b/src/jp/sourceforge/dvibrowser/dvicore/image/split/DefaultSplitImageWriter.java new file mode 100644 index 0000000..58ae2d7 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/split/DefaultSplitImageWriter.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.image.split; +import java.awt.image.RenderedImage; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; + +import javax.imageio.ImageIO; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviRectSplitter; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.DviSize; + +public class DefaultSplitImageWriter implements SplitImageWriter { +// private static final Logger LOGGER = Logger +// .getLogger(DefaultSplitImageWriter.class.getName()); + private static class SplitImageImpl implements SplitImage { + private final DviRectSplitter rectSplitter; + private final ArrayList imagePieces = new ArrayList(); + private final DviResolution res; + + public SplitImageImpl(DviResolution res, DviRectSplitter rectSplitter) { + this.res = res; + this.rectSplitter = rectSplitter; + } + + public Collection getPieces() throws DviException { + return Collections.unmodifiableCollection(imagePieces); + } + + public DviRectSplitter getRectSplitter() throws DviException { + return rectSplitter; + } + + public Iterator iterator() { + return imagePieces.iterator(); + } + + public DviRect getRect() throws DviException { + return rectSplitter.getRect(); + } + + public DviResolution getResolution() { + return res; + } + } + + private final File outputFile; + private final ImageFileConfig imgConf; + + protected DviRectSplitter rectSplitter; + protected SplitImageImpl splitImage; + private final DviResolution res; + + public DefaultSplitImageWriter(File outputFile, ImageFileConfig imgConf, DviResolution res) + { + this.outputFile = outputFile; + this.imgConf = imgConf; + this.res = res; + this.rectSplitter = null; + this.splitImage = null; + } + + public ImageFileConfig getImageFileConfig() throws DviException { + return imgConf; + } + + protected String generateFilename(int rows, int cols, DviSize unit, int row, + int col) throws DviException + { + String filename = getOutputFile().getName() + "-" + res.dpi() + "_" + res.shrinkFactor() + "-" + + unit.width() + "-" + unit.height() + "-" + rows + "-" + cols + "-" + + row + "-" + col + getImageFileConfig().getImageExtension(); + + return filename; + } + + public File getOutputFile() { + return outputFile; + } + + + public void beginSplitImage(ImageSplitter ImageSplitter, + DviRectSplitter rectSplitter) throws DviException { + this.rectSplitter = rectSplitter; + this.splitImage = new SplitImageImpl(getResolution(), rectSplitter); + } + + + public void endSplitImage() throws DviException { + } + + protected URLImagePiece writeImageToFile(RenderedImage img, + DviRectSplitter splitter, int row, int col) throws IOException, + DviException { + final int rows = splitter.getNumRows(); + final int cols = splitter.getNumColumns(); + final DviSize unit = splitter.getUnitSize(); + String filename = generateFilename(rows, cols, unit, row, col); + File imgFile = new File(getOutputFile().getParentFile(), filename); + ImageIO.write(img, imgConf.getImageType(), imgFile); + return new URLImagePiece(splitImage, imgFile.toURL(), getResolution(), splitter, row, col); + } + + public void writeImagePiece(RenderedImage img, int row, int col) + throws DviException { + try { + URLImagePiece piece = writeImageToFile(img, rectSplitter, row, col); + splitImage.imagePieces.add(piece); + } catch (IOException e) { + throw new DviException(e); + } + } + + public SplitImage getSplitImage() throws DviException { + return splitImage; + } + + public DviResolution getResolution() { + return res; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/split/DviImage.java b/src/jp/sourceforge/dvibrowser/dvicore/image/split/DviImage.java new file mode 100644 index 0000000..f253329 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/split/DviImage.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.image.split; +import java.awt.Image; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviRectSplitter; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + + +public class DviImage +implements SplitImage +{ + private static final Logger LOGGER = Logger.getLogger(DviImage.class + .getName()); + private final Image img; + private final DviResolution res; + private DviRect rect; + private final ArrayList pieces = new ArrayList(); + + public DviImage(Image img, int dpi) + { + if (img == null) throw new IllegalArgumentException("img can't be null"); + this.img = img; + this.res = new DviResolution(dpi, 1); + pieces.add(new SplitPiece() { + public int getColumn() throws DviException { + return 0; + } + + public Image getImage() throws DviException { + return DviImage.this.img; + } + + public DviRect getRect() throws DviException { + return DviImage.this.getRect(); + } + + public DviRectSplitter getRectSplitter() throws DviException { + return DviImage.this.getRectSplitter(); + } + + public DviResolution getResolution() throws DviException { + return DviImage.this.getResolution(); + } + + public int getRow() throws DviException { + return 0; + } + + public SplitImage getSplitImage() throws DviException { + return DviImage.this; + } + }); + } + + public Image getImage() + { + return img; + } + + public int getDpi() + { + return res.dpi(); + } + + public Collection getPieces() throws DviException { + return pieces; + } + + public synchronized DviRect getRect() throws DviException { + if (rect == null) { + rect = new DviRect(0, 0, img.getWidth(null), img.getHeight(null)); + } + return rect; + } + + public DviRectSplitter getRectSplitter() throws DviException { + DviRect r = getRect(); + return new DviRectSplitter(r, r.size()); + } + + public DviResolution getResolution() { + return res; + } + + public Iterator iterator() { + try { + return getPieces().iterator(); + } catch (DviException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + // TODO: Think about better handle this. Should we really use a RuntimeException? + throw new RuntimeException(e); + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/split/FileImagePiece.java b/src/jp/sourceforge/dvibrowser/dvicore/image/split/FileImagePiece.java new file mode 100644 index 0000000..9382f97 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/split/FileImagePiece.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.image.split; +import java.awt.Image; +import java.io.File; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.imageio.ImageIO; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRectSplitter; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + + +public class FileImagePiece +extends AbstractSplitPiece +{ + private static final Logger LOGGER = Logger.getLogger(FileImagePiece.class.getName()); + + private final ImageFileConfig imageConf; + private final File file; + + public FileImagePiece(SplitImage splitImage, File file, DviResolution res, ImageFileConfig imageConf, DviRectSplitter rectSplitter, int row, int col) + { + super(splitImage, res, rectSplitter, row, col); + this.file = file; + this.imageConf = imageConf; + } + + public ImageFileConfig getImageFileConfig() { + return imageConf; + } + + public Image getImage() throws DviException { + try { + Image img = ImageIO.read(file); + return img; + } catch (IOException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + throw new DviException(e); + } + } + + public File getFile() { + return file; + } + +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/split/ImageFileConfig.java b/src/jp/sourceforge/dvibrowser/dvicore/image/split/ImageFileConfig.java new file mode 100644 index 0000000..5f5656e --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/split/ImageFileConfig.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.image.split; +public class ImageFileConfig { + public static final ImageFileConfig PNG = new ImageFileConfig("png", ".png"); + public static final ImageFileConfig GIF = new ImageFileConfig("gif", ".gif"); + public static final ImageFileConfig JPEG = new ImageFileConfig("jpeg", ".jpg"); + + private final String imageType; + private final String imageExt; + + public ImageFileConfig(String imageType, String imageExt) + { + if (imageType == null) + throw new IllegalArgumentException("imageType can't be null"); + if (imageExt == null) + throw new IllegalArgumentException("imageExt can't be null"); + + this.imageType = imageType; + this.imageExt = imageExt; + } + + public String getImageType() { + return imageType; + } + + public String getImageExtension() { + return imageExt; + } + + public boolean equals(Object o) + { + if (!(o instanceof ImageFileConfig)) + return false; + + ImageFileConfig oo = (ImageFileConfig) o; + return oo.imageType.equals(imageType) && oo.imageExt.equals(imageExt); + } + + public int hashCode() + { + return imageType.hashCode() + 33*imageExt.hashCode(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/split/ImageSplitter.java b/src/jp/sourceforge/dvibrowser/dvicore/image/split/ImageSplitter.java new file mode 100644 index 0000000..9adfb3b --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/split/ImageSplitter.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.image.split; + +import java.io.IOException; +import java.io.InputStream; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviSize; + + +public interface ImageSplitter { + public DviSize getUnitSize() throws DviException; + public void splitImageFromStream(InputStream is) throws IOException, DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/split/SplitImage.java b/src/jp/sourceforge/dvibrowser/dvicore/image/split/SplitImage.java new file mode 100644 index 0000000..057b55c --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/split/SplitImage.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ +package jp.sourceforge.dvibrowser.dvicore.image.split; + +import java.util.Collection; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviRectSplitter; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; + + +public interface SplitImage +extends Iterable +{ + public DviResolution getResolution(); + public DviRect getRect() throws DviException; + public DviRectSplitter getRectSplitter() throws DviException; + public Collection getPieces() throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/split/SplitImageUtils.java b/src/jp/sourceforge/dvibrowser/dvicore/image/split/SplitImageUtils.java new file mode 100644 index 0000000..b1aa9f7 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/split/SplitImageUtils.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ +package jp.sourceforge.dvibrowser.dvicore.image.split; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.RenderingHints; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviSize; + + +public class SplitImageUtils { + public static void renderToGraphics(Graphics g, SplitImage img, int x, int y, double scale) throws DviException + { + if (g == null) throw new NullPointerException("Graphics object can't be null"); + if (img == null) throw new NullPointerException("img can't be null"); + + Graphics2D gg = (Graphics2D) g; + + DviSize unit = img.getRectSplitter().getUnitSize(); + DviSize scaleUnit = unit.magnify(scale); + DviRect clip = DviRect.fromRectangle(g.getClipBounds()); + + for (SplitPiece piece : img) { + int row = piece.getRow(); + int col = piece.getColumn(); + DviRect scaledRect = piece.getRect().magnify(scale).moveTo(x + col * scaleUnit.width, y + row * scaleUnit.height); + if (clip != null && !scaledRect.intersects(clip)) continue; + Rectangle r = scaledRect.toRectangle(); + Image img2 = piece.getImage(); + gg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + gg.drawImage(piece.getImage(), r.x, r.y, r.x + r.width + 1, r.y + r.height + 1, 0, 0, img2.getWidth(null), img2.getHeight(null), null); + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/split/SplitImageWriter.java b/src/jp/sourceforge/dvibrowser/dvicore/image/split/SplitImageWriter.java new file mode 100644 index 0000000..c51905e --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/split/SplitImageWriter.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.image.split; + +import java.awt.image.RenderedImage; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRectSplitter; + + +public interface SplitImageWriter { + public void beginSplitImage(ImageSplitter ImageSplitter, DviRectSplitter rectSplitter) throws DviException; + public void endSplitImage() throws DviException; + public void writeImagePiece(RenderedImage img, int row, int col) throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/split/SplitPiece.java b/src/jp/sourceforge/dvibrowser/dvicore/image/split/SplitPiece.java new file mode 100644 index 0000000..e561295 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/split/SplitPiece.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.image.split; +import java.awt.Image; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviRectSplitter; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; + +public interface SplitPiece +{ + public DviResolution getResolution() throws DviException; + public DviRectSplitter getRectSplitter() throws DviException; + public int getRow() throws DviException; + public int getColumn() throws DviException; + public Image getImage() throws DviException; + public DviRect getRect() throws DviException; + public SplitImage getSplitImage() throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/split/URLImagePiece.java b/src/jp/sourceforge/dvibrowser/dvicore/image/split/URLImagePiece.java new file mode 100644 index 0000000..01f7d63 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/split/URLImagePiece.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.image.split; +import java.awt.Image; +import java.io.IOException; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.imageio.ImageIO; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRectSplitter; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + +public class URLImagePiece +extends AbstractSplitPiece +{ + private static Logger LOGGER = Logger.getLogger(URLImagePiece.class.getName()); + + private final URL url; + + public URLImagePiece(SplitImage splitImage, URL url, DviResolution res, DviRectSplitter rectSplitter, int row, int col) + { + super(splitImage, res, rectSplitter, row, col); + this.url = url; + } + + public URL getURL() { + return url; + } + + public Image getImage() throws DviException { + try { + Image img = ImageIO.read(url); + return img; + } catch (IOException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + throw new DviException(e); + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/split/ZipImagePiece.java b/src/jp/sourceforge/dvibrowser/dvicore/image/split/ZipImagePiece.java new file mode 100644 index 0000000..d271e34 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/split/ZipImagePiece.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.image.split; +import java.awt.Image; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import javax.imageio.ImageIO; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRectSplitter; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + +public class ZipImagePiece +extends AbstractSplitPiece +{ + private static Logger LOGGER = Logger.getLogger(ZipImagePiece.class.getName()); + + private final File file; + private final String entryName; + + public ZipImagePiece(SplitImage splitImage, File file, String entryName, DviResolution res, DviRectSplitter rectSplitter, int row, int col) + { + super(splitImage, res, rectSplitter, row, col); + this.file = file; + this.entryName = entryName; + } + + public Image getImage() throws DviException { + try { + ZipFile zipFile = new ZipFile(file); + try { + ZipEntry entry = zipFile.getEntry(entryName); + if (entry != null) { + InputStream is = zipFile.getInputStream(entry); + try { + Image img = ImageIO.read(is); + return img; + } finally { + DviUtils.silentClose(is); + } + } else { + throw new DviException("zip entry not found: entryName=" + entryName + " file=" + file.getAbsolutePath()); + } + } finally { + zipFile.close(); + } + } catch (IOException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + throw new DviException(e); + } + } + + public File getFile() { + return file; + } + + public String getEntryName() { + return entryName; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/image/split/ZipSplitImageReader.java b/src/jp/sourceforge/dvibrowser/dvicore/image/split/ZipSplitImageReader.java new file mode 100644 index 0000000..582a420 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/image/split/ZipSplitImageReader.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ +package jp.sourceforge.dvibrowser.dvicore.image.split; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviRectSplitter; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.DviSize; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + + +public class ZipSplitImageReader { + private static final Logger LOGGER = Logger + .getLogger(ZipSplitImageReader.class.getName()); + private final File file; + + private static class SplitImageImpl implements SplitImage + { + private DviRectSplitter rectSplitter; + private final ArrayList pieces = new ArrayList(); + private final File file; + private final Properties props; + private final DviResolution res; + + public SplitImageImpl(File file, Properties props, DviResolution res, DviRectSplitter rectSplitter) + { + this.file = file; + this.props = props; + this.res = res; + this.rectSplitter = rectSplitter; + } + + public Collection getPieces() throws DviException { + return Collections.unmodifiableCollection(pieces); + } + + public DviRectSplitter getRectSplitter() throws DviException { + return rectSplitter; + } + + public Iterator iterator() { + return pieces.iterator(); + } + + public Properties getProperties() { + return props; + } + + public DviRect getRect() throws DviException { + return rectSplitter.getRect(); + } + + public DviResolution getResolution() { + return res; + } + + public File getFile() { + return file; + } + } + + public ZipSplitImageReader(File file) + { + this.file = file; + } + + public SplitImage getSplitImage() throws DviException + { + try { + ZipFile zipFile = new ZipFile(file); + try { + String indexEntryName = "images/index.properties"; + ZipEntry entry = zipFile.getEntry(indexEntryName); + if (entry == null) { + throw new DviException("Image bundle has no index file: " + file.getAbsolutePath()); + } + Properties props = new Properties(); + props.load(zipFile.getInputStream(entry)); + String fmt = props.getProperty("image.format.name"); + if ("image-bundle".equals(fmt)) { + final int dpi = Integer.parseInt(props.getProperty("image.hres.dpi")); + final int sf = Integer.parseInt(props.getProperty("image.hres.sf")); + final int width = Integer.parseInt(props.getProperty("image.total.width")); + final int height = Integer.parseInt(props.getProperty("image.total.height")); + final int uw = Integer.parseInt(props.getProperty("image.unit.width")); + final int uh = Integer.parseInt(props.getProperty("image.unit.height")); + final DviResolution res = new DviResolution(dpi, sf); + final DviSize unitSize = new DviSize(uw, uh); + final DviRect rect = new DviRect(0, 0, width, height); + final DviRectSplitter rectSplitter = new DviRectSplitter(rect, unitSize); + SplitImageImpl splitImage = new SplitImageImpl(file, props, res, rectSplitter); + { // populate the image with pieces. + int rows = rectSplitter.getNumRows(); + int cols = rectSplitter.getNumColumns(); + for (int i=0; i imagePieces = new ArrayList(); + + public SplitImageImpl(DviResolution res, DviRectSplitter rectSplitter) { + this.res = res; + this.rectSplitter = rectSplitter; + } + + public DviResolution getResolution() + { + return res; + } + + public Collection getPieces() throws DviException { + return Collections.unmodifiableCollection(imagePieces); + } + + public DviRectSplitter getRectSplitter() throws DviException { + return rectSplitter; + } + + public Iterator iterator() { + return imagePieces.iterator(); + } + + public DviRect getRect() throws DviException { + return rectSplitter.getRect(); + } + } + + private static class SplitPieceImpl extends AbstractSplitPiece { + private final String path; + + public SplitPieceImpl(SplitImage splitImage, String path, DviResolution res, + DviRectSplitter rectSplitter, int row, + int col) { + super(splitImage, res, rectSplitter, row, col); + this.path = path; + } + + public String getPath() { + return path; + } + + public Image getImage() throws DviException { + return null; + } + + } + + private final String outputBasename; + private final ImageFileConfig imgConf; + private final String path = "images"; + + protected DviRectSplitter rectSplitter; + private SplitImageImpl splitImage; + private final ZipBuilder zip; + private final DviResolution res; + + public ZipSplitImageWriter(String outputBasename, ImageFileConfig imgConf, DviResolution res, ZipBuilder zip) { + this.outputBasename = outputBasename; + this.imgConf = imgConf; + this.res = res; + this.zip = zip; + this.rectSplitter = null; + this.splitImage = null; + } + + public ImageFileConfig getImageFileConfig() throws DviException { + return imgConf; + } + + protected String generateFilename(int row, int col) throws DviException { + final DviSize unit = rectSplitter.getUnitSize(); + final int rows = rectSplitter.getNumRows(); + final int cols = rectSplitter.getNumColumns(); + String filename = getOutputBasename() + "/" + res.dpi() + "_" + res.shrinkFactor() + "-" + + unit.width() + "-" + unit.height() + "-" + rows + "-" + cols + "-" + + row + "-" + col + getImageFileConfig().getImageExtension(); + + return filename; + } + + public void beginSplitImage(ImageSplitter ImageSplitter, + DviRectSplitter rectSplitter) throws DviException { + if (rectSplitter == null) { + throw new IllegalArgumentException("rectSplitter is null"); + } + this.rectSplitter = rectSplitter; + this.splitImage = new SplitImageImpl(res, rectSplitter); + } + + public void endSplitImage() throws DviException { + try { + writeMetadata(); + writeHtmlView(); + } finally { + DviUtils.silentClose(zip); + } + } + + protected void writeHtmlView() throws DviException { + try { + OutputStream os = getZipBuilder().openOutputStream("html/index.html"); + try { + int rows = rectSplitter.getNumRows(); + int cols = rectSplitter.getNumColumns(); + DviRect totalRect = rectSplitter.getRect(); + + double baseWidth = 640.0; + double scale = (totalRect.width() > 0) ? (baseWidth / totalRect.width()) : baseWidth; + + PrintWriter pw = new PrintWriter(new OutputStreamWriter(os)); + pw.print(""); + String closingTag = ""; + for (SplitPiece piece : splitImage) { + if (piece instanceof SplitPieceImpl) { + SplitPieceImpl p = (SplitPieceImpl) piece; + String filename = "../" + p.getPath(); + DviRect r = p.getRect(); + double x = r.x() * scale; + double y = r.y() * scale; + int w = (int) Math.floor(r.width() * scale); + int h = (int) Math.floor(r.height() * scale); + if (piece.getColumn() == 0) { + pw.print(closingTag); + pw.printf(""); + closingTag = ""; + } + pw.printf(""); + } + } + pw.print(closingTag); + pw.print("
", scale); + pw.printf("", filename, w, h); + pw.printf("
"); + pw.flush(); + pw.close(); + } finally { + DviUtils.silentClose(os); + } + } catch (IOException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + throw new DviException(e); + } + } + + protected void writeMetadata() throws DviException { + try { + DviRect rect = rectSplitter.getRect(); + DviSize unit = rectSplitter.getUnitSize(); + // TODO: use XML instead of .properties. + Properties props = new Properties(); + props.setProperty("image.format.name", "image-bundle"); + props.setProperty("image.basepath", path); + props.setProperty("image.path", path + "/" + getOutputBasename()); // TODO: + // make + // the + // path + // computation + // a + // method. + props.setProperty("image.format.version", "0.1"); + props.setProperty("image.total.width", String.valueOf(rect.width())); + props.setProperty("image.total.height", String.valueOf(rect.height())); + props.setProperty("image.unit.width", String.valueOf(unit.width())); + props.setProperty("image.unit.height", String.valueOf(unit.height())); + props.setProperty("image.hres.dpi", String.valueOf(res.dpi())); + props.setProperty("image.hres.sf", String.valueOf(res.shrinkFactor())); + props.setProperty("image.vres.dpi", String.valueOf(res.dpi())); + props.setProperty("image.vres.sf", String.valueOf(res.shrinkFactor())); + props.setProperty("image.piece.length", String.valueOf(splitImage + .getPieces().size())); + int rows = rectSplitter.getNumRows(); + int cols = rectSplitter.getNumColumns(); + props.setProperty("image.piece.rows", String.valueOf(rows)); + props.setProperty("image.piece.cols", String.valueOf(cols)); + for (SplitPiece piece : splitImage) { + if (piece instanceof SplitPieceImpl) { + SplitPieceImpl p = (SplitPieceImpl) piece; + String filename = p.getPath(); + props.setProperty("image.piece." + piece.getRow() + "." + + piece.getColumn() + ".file", filename); + } + } + + OutputStream os = getZipBuilder().openOutputStream( + "images/index.properties"); + try { + props.store(os, "image-bundle"); + } finally { + DviUtils.silentClose(os); + } + } catch (IOException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + throw new DviException(e); + } + } + + protected File createTempFile() throws IOException + { + // TODO: add a temporary file manager to DviContext. + File file = File.createTempFile("zip-png", "tmp"); + file.deleteOnExit(); + return file; + } + + public void writeImagePiece(RenderedImage img, int row, int col) + throws DviException { + try { + // TODO: Think about the directory structure of the output zip file. + // TODO: Compute md5 of piece image and store it. Make a flag to denote if the data contains md5 or not. + String filename = path + "/" + generateFilename(row, col); + File tmpFile = createTempFile(); + try { + ImageIO.write(img, imgConf.getImageType(), tmpFile); + getZipBuilder().write(filename, tmpFile); + SplitPiece piece = new SplitPieceImpl(splitImage, filename, res, rectSplitter, row, col); + splitImage.imagePieces.add(piece); + } finally { + tmpFile.delete(); + } + } catch (IOException e) { + throw new DviException(e); + } + } + + public ZipBuilder getZipBuilder() { + return zip; + } + + public String getOutputBasename() { + return outputBasename; + } + + public SplitImage getSplitImage() + { + return splitImage; + } + + public DviResolution getResolution() { + return res; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/io/ByteArrayDviData.java b/src/jp/sourceforge/dvibrowser/dvicore/io/ByteArrayDviData.java new file mode 100644 index 0000000..4ed0707 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/io/ByteArrayDviData.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.io; + +import java.io.ByteArrayInputStream; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontTable; +import jp.sourceforge.dvibrowser.dvicore.DviUnit; +import jp.sourceforge.dvibrowser.dvicore.api.DviData; +import jp.sourceforge.dvibrowser.dvicore.api.DviInput; + + +public class ByteArrayDviData +implements DviData +{ + private final byte [] buf; + private final DviFontTable fontTable; + private final DviUnit dviUnit; + + public ByteArrayDviData(byte [] buf) + { + this(buf, null, null); + } + + public ByteArrayDviData(byte [] buf, DviUnit dviUnit) + { + this(buf, dviUnit, null); + } + + public ByteArrayDviData(byte [] buf, DviUnit dviUnit, DviFontTable fontTable) + { + this.buf = buf; + this.dviUnit = dviUnit; + this.fontTable = fontTable; + if (buf == null) + throw new IllegalArgumentException + ("dvi data buffer cannot be null"); + } + + public DviInput getInput() { + return + new DviInputStreamReader( + new ByteArrayInputStream(buf) + ); + } + + public DviFontTable getFontTable() { + return fontTable; + } + + public DviUnit getDviUnit() { + return dviUnit; + } + + public long getDataSize() throws DviException + { + return buf.length; + } + + public DviInput getInput(long start, long end) throws DviException + { + if (start < 0 || end < 0 || end < start) + throw new IllegalArgumentException + (String.format("Invalid byte range: (%d,%d)", start, end)); + if (start >= buf.length) + throw new IllegalArgumentException + ("start position out of bounds: " + start); + if (end >= buf.length) + throw new IllegalArgumentException + ("end position out of bounds: " + end); + + DviInputStreamReader in = new DviInputStreamReader( + new ByteArrayInputStream( + this.buf, (int) start, (int)(end - start) + 1 + ) + ); + in.setOffset(start); + return in; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/io/DviByteBufferInput.java b/src/jp/sourceforge/dvibrowser/dvicore/io/DviByteBufferInput.java new file mode 100644 index 0000000..76c7071 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/io/DviByteBufferInput.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.io; + +import java.io.IOException; +import java.io.EOFException; +import java.nio.ByteBuffer; + +import jp.sourceforge.dvibrowser.dvicore.api.DviInput; + + +public class DviByteBufferInput +implements DviInput +{ + private final ByteBuffer in; + public DviByteBufferInput(ByteBuffer in) { + this.in = in; + } + + public void close() + throws IOException + { + } + + private long offset = 0; + public long getOffset() { return offset; } + public void setOffset(long offset) { this.offset = offset; } + + private long end = Long.MAX_VALUE; + public void setEnd(long end) { this.end = end; } + + public boolean ready() + throws IOException + { + return (offset <= end && in.hasRemaining()); + } + + public int readU1() + throws IOException + { + if (offset > end) + throw new EOFException(); + int c = in.get(); + if (c < 0) c += 256; + offset++; + return c; + } + + public void readFully(byte [] buf) + throws IOException + { + if (buf == null) return; + if (buf.length <= 0) return; + if (offset + buf.length - 1> end) + throw new EOFException(); + in.get(buf); + offset += buf.length; + } + + public int readU(int len) + throws IOException + { + int v = 0; + + if (len <= 0 || len > 4) + throw new IllegalArgumentException + ("illegal value of len."); + + while (len > 0) { + v = (v << 8) | readU1(); + len--; + } + + return v; + } + + public int readS(int len) + throws IOException + { + int bits = len * 8; + int a = 1; + int v = 0; + + if (len <= 0 || len > 4) + throw new IllegalArgumentException + ("illegal value of len."); + + while (len > 0) { + v = (v << 8) | readU1(); + a <<= 8; + len--; + } + if (0 != (v & (1 << (bits - 1)))) { + v -= a; + } + + return v; + } + + public int readU2() + throws IOException + { + return ((readU1() << 8) | + readU1()); + } + + public int readU3() + throws IOException + { + return ((readU1() << 16) | + (readU1() << 8) | + readU1()); + } + + public int readU4() + throws IOException + { + return ((readU1() << 24) | + (readU1() << 16) | + (readU1() << 8) | + readU1()); + } + + public int readS1() + throws IOException + { + return readS(1); + } + + public int readS2() + throws IOException + { + return readS(2); + } + + public int readS3() + throws IOException + { + return readS(3); + } + + public int readS4() + throws IOException + { + return readS(4); + } + + public void skip(int len) + throws IOException + { + if (len <= 0) return; + byte [] buf = new byte[len]; + readFully(buf); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/io/DviInputStreamReader.java b/src/jp/sourceforge/dvibrowser/dvicore/io/DviInputStreamReader.java new file mode 100644 index 0000000..6ea1086 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/io/DviInputStreamReader.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.io; + +import java.io.InputStream; +import java.io.IOException; +import java.io.EOFException; + +import jp.sourceforge.dvibrowser.dvicore.api.DviInput; + + +public class DviInputStreamReader +implements DviInput +{ + private final InputStream in; + public DviInputStreamReader(InputStream in) + { + this.in = in; + } + + public void close() + throws IOException + { + in.close(); + } + + private long offset = 0; + public long getOffset() { return offset; } + public void setOffset(long offset) { this.offset = offset; } + + private long end = Long.MAX_VALUE; + public void setEnd(long end) { this.end = end; } + +/* + public boolean ready() throws IOException { + return (offset <= end); // && 0 < in.available()); + } + */ + + public int readU1() + throws IOException + { + if (offset > end) + throw new EOFException(); + int c = in.read(); + if (c < 0) + throw new EOFException(); + offset++; + return c; + } + + public void readFully(byte [] buf) + throws IOException + { + if (buf == null) return; + if (buf.length <= 0) return; + if (offset + buf.length - 1> end) + throw new EOFException(); + if (buf.length != in.read(buf)) + throw new EOFException + ("while filling the buffer."); + offset += buf.length; + } + + public int readU(int len) + throws IOException + { + int v = 0; + + if (len <= 0 || len > 4) + throw new IllegalArgumentException + ("illegal value of len: " + len); + + while (len > 0) { + v = (v << 8) | readU1(); + len--; + } + + return v; + } + + public int readS(int len) + throws IOException + { + int bits = len * 8; + int a = 1; + int v = 0; + + if (len <= 0 || len > 4) + throw new IllegalArgumentException + ("illegal value of len: " + len); + + while (len > 0) { + v = (v << 8) | readU1(); + a <<= 8; + len--; + } + if (0 != (v & (1 << (bits - 1)))) { + v -= a; + } + + return v; + } + + public int readU2() + throws IOException + { + return ((readU1() << 8) | + readU1()); + } + + public int readU3() + throws IOException + { + return ((readU1() << 16) | + (readU1() << 8) | + readU1()); + } + + public int readU4() + throws IOException + { + return ((readU1() << 24) | + (readU1() << 16) | + (readU1() << 8) | + readU1()); + } + + public int readS1() + throws IOException + { + return readS(1); + } + + public int readS2() + throws IOException + { + return readS(2); + } + + public int readS3() + throws IOException + { + return readS(3); + } + + public int readS4() + throws IOException + { + return readS(4); + } + + public void skip(int len) + throws IOException + { + long skipped = in.skip(len); + if (skipped > 0) { + offset += skipped; + } + long left = len - skipped; + while (left > 0) { + readU1(); + left--; + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/io/DviRandomAccessFileInput.java b/src/jp/sourceforge/dvibrowser/dvicore/io/DviRandomAccessFileInput.java new file mode 100644 index 0000000..3d6a30a --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/io/DviRandomAccessFileInput.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.io; + +import java.io.RandomAccessFile; +import java.io.IOException; +import java.io.EOFException; + +import jp.sourceforge.dvibrowser.dvicore.api.DviInput; + + +public class DviRandomAccessFileInput +implements DviInput +{ + private final RandomAccessFile in; + + public DviRandomAccessFileInput(RandomAccessFile in) + { + this.in = in; + } + + public void close() + throws IOException + { + in.close(); + } + + private long offset = 0; + public long getOffset() { return offset; } + public void setOffset(long offset) { this.offset = offset; } + + private long end = Long.MAX_VALUE; + public void setEnd(long end) { this.end = end; } + + public boolean ready() + throws IOException + { + return (offset <= end && (in.getFilePointer() < in.length())); + } + + public int readU1() + throws IOException + { + if (offset > end) + throw new EOFException(); + int c = in.readUnsignedByte(); + if (c < 0) c += 256; + offset++; + return c; + } + + public void readFully(byte [] buf) + throws IOException + { + if (buf == null) return; + if (buf.length <= 0) return; + if (offset + buf.length - 1> end) + throw new EOFException(); + in.readFully(buf); + offset += buf.length; + } + + public int readU(int len) + throws IOException + { + int v = 0; + + if (len <= 0 || len > 4) + throw new IllegalArgumentException + ("illegal value of len."); + + while (len > 0) { + v = (v << 8) | readU1(); + len--; + } + + return v; + } + + public int readS(int len) + throws IOException + { + int bits = len * 8; + int a = 1; + int v = 0; + + if (len <= 0 || len > 4) + throw new IllegalArgumentException + ("illegal value of len."); + + while (len > 0) { + v = (v << 8) | readU1(); + a <<= 8; + len--; + } + if (0 != (v & (1 << (bits - 1)))) { + v -= a; + } + + return v; + } + + public int readU2() + throws IOException + { + return ((readU1() << 8) | + readU1()); + } + + public int readU3() + throws IOException + { + return ((readU1() << 16) | + (readU1() << 8) | + readU1()); + } + + public int readU4() + throws IOException + { + return ((readU1() << 24) | + (readU1() << 16) | + (readU1() << 8) | + readU1()); + } + + public int readS1() + throws IOException + { + return readS(1); + } + + public int readS2() + throws IOException + { + return readS(2); + } + + public int readS3() + throws IOException + { + return readS(3); + } + + public int readS4() + throws IOException + { + return readS(4); + } + + public void skip(int len) + throws IOException + { + in.seek(in.getFilePointer() + len-1); + // TODO: use in.skipBytes(); + offset += len - 1; + if (!ready()) { + throw new EOFException(); + } + readU1(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/plat/cygwin/CygwinUtils.java b/src/jp/sourceforge/dvibrowser/dvicore/plat/cygwin/CygwinUtils.java new file mode 100644 index 0000000..bc99303 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/plat/cygwin/CygwinUtils.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.plat.cygwin; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.util.CommandShell; +import jp.sourceforge.dvibrowser.dvicore.util.CommandShellHandler; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + +public class CygwinUtils { + private static final Logger LOGGER = Logger.getLogger(CygwinUtils.class + .getName()); + + public static String posixPathToJavaPath(String posixPath) + throws IOException, InterruptedException, DviException + { + CommandShell cs = new CommandShell(); + ArrayList list = new ArrayList(); + list.add("cygpath"); + list.add("-w"); + list.add(posixPath); + cs.setCommandLine(list); + final ArrayList outputs = new ArrayList(); + cs.setHandler(new CommandShellHandler() { + public void handleStderr(InputStream in) throws IOException { + DviUtils.logLinesFromStream("cygpath stderr", in, LOGGER, Level.FINE); + } + public void handleStdout(InputStream in) throws IOException { + String [] lines = DviUtils.readLinesFromStream(in); + for (String line : lines) { + outputs.add(line); + } + } + public void handleStdin(OutputStream out) throws IOException { + out.close(); + } + }); + int ret = cs.execute(); + if (ret != 0) { + LOGGER.warning("command failed: " + DviUtils.join(" ", list)); + return null; + } else { + if (outputs.size() > 0) { + return outputs.get(0); + } else { + return null; + } + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/AbstractDevice.java b/src/jp/sourceforge/dvibrowser/dvicore/render/AbstractDevice.java new file mode 100644 index 0000000..154f0b4 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/AbstractDevice.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import java.util.Stack; + +import jp.sourceforge.dvibrowser.dvicore.DviColor; +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviPoint; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.api.Device; + + +public abstract class AbstractDevice +implements Device +{ + private final DviResolution res; + public AbstractDevice(DviResolution res) { + this.res = res; + } + public DviResolution getResolution() + throws DviException { + return res; + } + + protected DviPoint point = DviPoint.ORIGIN; + public DviPoint getReferencePoint() throws DviException { + return point; + } + public void setReferencePoint(DviPoint point) throws DviException { + this.point = point; + } + + public void translate(DviPoint p) throws DviException { + point = point.translate(p); + } + public void translate(int dx, int dy) throws DviException { + point = point.translate(dx, dy); + } + + private DviColor color = new DviColor(0, 0, 0); + public void setColor(DviColor color) throws DviException + { + this.color = color; + } + public DviColor getColor() throws DviException + { + return color; + } + + protected final Stack stack = new Stack(); + + public void save() throws DviException { + stack.push(new StackItem(color, point)); + } + public void restore() throws DviException { + if (stack.empty()) + throw new IllegalStateException + ("stack underflow"); + + StackItem it = stack.pop(); + color = it.color; + point = it.point; + } + + private static class StackItem + { + private final DviColor color; + private final DviPoint point; + public StackItem(DviColor color, DviPoint point) + { + this.color = color; + this.point = point; + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/BasicExecutor.java b/src/jp/sourceforge/dvibrowser/dvicore/render/BasicExecutor.java new file mode 100644 index 0000000..3c044ff --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/BasicExecutor.java @@ -0,0 +1,713 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import java.io.EOFException; +import java.io.IOException; + +import jp.sourceforge.dvibrowser.dvicore.DviByteRange; +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviUnit; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviData; +import jp.sourceforge.dvibrowser.dvicore.api.DviExecutor; +import jp.sourceforge.dvibrowser.dvicore.api.DviExecutorContext; +import jp.sourceforge.dvibrowser.dvicore.api.DviExecutorHandler; +import jp.sourceforge.dvibrowser.dvicore.api.DviInput; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviBop; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviCommand; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostPost; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostamble; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPreamble; + + +// TODO: support logging + +public class BasicExecutor +extends DviObject +implements DviExecutor +{ + protected static class DviExecutorContextImpl + extends DviObject + implements DviExecutorContext + { + private DviData data; + private DviInput in; + private DviExecutorHandler handler; + + private int command; + private long commandBegin; + private long commandEnd; + private boolean terminate = false; + + public DviExecutorContextImpl(DviContextSupport dcs) + { + super(dcs); + } + + public DviData getData() { return data; } + public int getCommand() { return command; } + public DviByteRange getCommandRange() { + return new DviByteRange(commandBegin, commandEnd); + } + public void setTerminate(boolean f) { terminate = f; } + + private void commandDetermined() { + commandEnd = in.getOffset() - 1; + } + } + + public BasicExecutor(DviContextSupport dcs) + { + super(dcs); + } + + private static final DviExecutorHandler defaultHandler + = new EmptyDviExecutorHandler(); + + public void execute(DviData data) + throws DviException + { + execute(data, null); + } + + private DviExecutorContextImpl ctx; + protected DviExecutorContextImpl getExecutorContext() + { + return ctx; + } + + public void execute(DviData data, DviExecutorHandler handler) + throws DviException + { + ctx = new DviExecutorContextImpl(this); + ctx.data = data; + ctx.handler = (handler != null) ? handler : defaultHandler; + ctx.in = data.getInput(); + ctx.terminate = false; + + if (ctx.handler == null) + throw new NullPointerException + ("handler is null"); + if (ctx.data == null) + throw new NullPointerException + ("data is null"); + if (ctx.in == null) + throw new NullPointerException + ("input is null"); + + try { + begin(ctx); + try { + while (!ctx.terminate) { + executeOneCommand(ctx); + } + } catch (EOFException ex) { + // ignored. + } finally { + end(); + } + } catch(DviException ex) { + throw ex; + } catch(Throwable ex) { + ex.printStackTrace(); + throw new DviException(ex); + } finally { + try { + ctx.in.close(); + } catch (IOException ex) { + // ignored. + } + } + } + + protected void executeOneCommand(DviExecutorContextImpl ctx) + throws IOException, DviException + { + final int t; + final DviInput in = ctx.in; + + ctx.commandBegin = ctx.commandEnd = in.getOffset(); + t = ctx.command = in.readU1(); + + if (t <= 127) { + if (wantSet()) { + ctx.commandDetermined(); + doSet(t); + } + } else if (171 <= t && t <= 234) { + if (wantSelectFont()) { + ctx.commandDetermined(); + doSelectFont(t - 171); + } + } else { + switch(t) { + case DviCommand.DVI_SET4: + case DviCommand.DVI_SET3: + case DviCommand.DVI_SET2: + case DviCommand.DVI_SET1: { + final int alen = t - DviCommand.DVI_SET1 + 1; + if (wantSet()) { + final int code; + + code = in.readU(alen); + ctx.commandDetermined(); + doSet(code); + } else { + in.skip(alen); + } + break; + } + + case DviCommand.DVI_PUT4: + case DviCommand.DVI_PUT3: + case DviCommand.DVI_PUT2: + case DviCommand.DVI_PUT1: { + final int alen = t - DviCommand.DVI_PUT1 + 1; + if (wantPut()) { + final int code; + + code = in.readU(alen); + ctx.commandDetermined(); + doPut(code); + } else { + in.skip(alen); + } + break; + } + + case DviCommand.DVI_FONT4: + case DviCommand.DVI_FONT3: + case DviCommand.DVI_FONT2: + case DviCommand.DVI_FONT1: { + final int alen = t - DviCommand.DVI_FONT1 + 1; + if (wantSelectFont()) { + final int fn; + + fn = in.readU(alen); + ctx.commandDetermined(); + doSelectFont(fn); + } else { + in.skip(alen); + } + break; + } + + case DviCommand.DVI_XXX4: + case DviCommand.DVI_XXX3: + case DviCommand.DVI_XXX2: + case DviCommand.DVI_XXX1: { + final int alen = t - DviCommand.DVI_XXX1 + 1; + final int k; + k = in.readU(alen); + if (wantSpecial()) { + final byte [] xxx = new byte[k]; + in.readFully(xxx); + + ctx.commandDetermined(); + doSpecial(xxx); + } else { + in.skip(alen + k); + } + break; + } + + case DviCommand.DVI_SET_RULE: { + if (wantSetRule()) { + final int h, w; + + h = in.readS4(); + w = in.readS4(); + + ctx.commandDetermined(); + doSetRule(w, h); + } else { + in.skip(4 + 4); + } + break; + } + + case DviCommand.DVI_PUT_RULE: { + if (wantPutRule()) { + final int h, w; + + h = in.readS4(); + w = in.readS4(); + + ctx.commandDetermined(); + doPutRule(w, h); + } else { + in.skip(4 + 4); + } + break; + } + + case DviCommand.DVI_FNT_DEF4: + case DviCommand.DVI_FNT_DEF3: + case DviCommand.DVI_FNT_DEF2: + case DviCommand.DVI_FNT_DEF1: { + final int alen = t - DviCommand.DVI_FNT_DEF1 + 1; + if (wantDefineFont()) { + final int fn, cs, ss, ds, al, nl; + final byte [] fontName; + + fn = in.readU(alen); + cs = in.readS4(); + ss = in.readS4(); + ds = in.readS4(); + al = in.readU1(); + nl = in.readU1(); + + fontName = new byte[al+nl]; + in.readFully(fontName); + + ctx.commandDetermined(); + doDefineFont( + fn, + DviFontSpec.getInstance(cs, ss, ds, al, nl, fontName) + ); + } else { + final int al, nl; + in.skip(alen + 4 + 4 + 4); + al = in.readU1(); + nl = in.readU1(); + in.skip(al + nl); + } + break; + } + + case DviCommand.DVI_RIGHT4: + case DviCommand.DVI_RIGHT3: + case DviCommand.DVI_RIGHT2: + case DviCommand.DVI_RIGHT1: { + final int alen = t - DviCommand.DVI_RIGHT1 + 1; + if (wantRight()) { + final int dh; + + dh = in.readS(alen); + + ctx.commandDetermined(); + doRight(dh); + } else { + in.skip(alen); + } + break; + } + + case DviCommand.DVI_W4: + case DviCommand.DVI_W3: + case DviCommand.DVI_W2: + case DviCommand.DVI_W1: { + final int alen = t - DviCommand.DVI_W1 + 1; + if (wantW()) { + final int dh; + + dh = in.readS(alen); + + ctx.commandDetermined(); + doW(dh); + } else { + in.skip(alen); + } + break; + } + case DviCommand.DVI_W0: { + if (wantW0()) { + ctx.commandDetermined(); + doW0(); + } + break; + } + + case DviCommand.DVI_X4: + case DviCommand.DVI_X3: + case DviCommand.DVI_X2: + case DviCommand.DVI_X1: { + final int alen = t - DviCommand.DVI_X1 + 1; + if (wantX()) { + final int dh; + + dh = in.readS(alen); + + ctx.commandDetermined(); + doX(dh); + } else { + in.skip(alen); + } + break; + } + case DviCommand.DVI_X0: { + if (wantX0()) { + ctx.commandDetermined(); + doX0(); + } + break; + } + + + case DviCommand.DVI_DOWN4: + case DviCommand.DVI_DOWN3: + case DviCommand.DVI_DOWN2: + case DviCommand.DVI_DOWN1: { + final int alen = t - DviCommand.DVI_DOWN1 + 1; + if (wantDown()) { + final int dv; + + dv = in.readS(alen); + + ctx.commandDetermined(); + doDown(dv); + } else { + in.skip(alen); + } + break; + } + + case DviCommand.DVI_Y4: + case DviCommand.DVI_Y3: + case DviCommand.DVI_Y2: + case DviCommand.DVI_Y1: { + final int alen = t - DviCommand.DVI_Y1 + 1; + if (wantY()) { + final int dv; + + dv = in.readS(alen); + + ctx.commandDetermined(); + doY(dv); + } else { + in.skip(alen); + } + break; + } + case DviCommand.DVI_Y0: { + if (wantY0()) { + ctx.commandDetermined(); + doY0(); + } + break; + } + + case DviCommand.DVI_Z4: + case DviCommand.DVI_Z3: + case DviCommand.DVI_Z2: + case DviCommand.DVI_Z1: { + final int alen = t - DviCommand.DVI_Z1 + 1; + if (wantZ()) { + final int dv; + + dv = in.readS(alen); + + ctx.commandDetermined(); + doZ(dv); + } else { + in.skip(alen); + } + break; + } + case DviCommand.DVI_Z0: { + if (wantZ0()) { + ctx.commandDetermined(); + doZ0(); + } + break; + } + + case DviCommand.DVI_PUSH: { + if (wantPush()) { + ctx.commandDetermined(); + doPush(); + } + break; + } + case DviCommand.DVI_POP: { + if (wantPop()) { + ctx.commandDetermined(); + doPop(); + } + break; + } + + case DviCommand.DVI_NOP: { + if (wantNop()) { + ctx.commandDetermined(); + doNop(); + } + break; + } + + case DviCommand.DVI_BOP: { + if (wantBop()) { + final int [] count = new int [10]; + final int backPointer; + + for (int i=0; i<10; i++) + count[i] = in.readS4(); + backPointer = in.readS4(); + + ctx.commandDetermined(); + doBop( + new DviBop(count, backPointer) + ); + } else { + in.skip(10 * 4 + 4); + } + break; + } + case DviCommand.DVI_EOP: { + if (wantEop()) { + ctx.commandDetermined(); + doEop(); + } + break; + } + case DviCommand.DVI_PRE: { + if (wantPre()) { + final int idByte, num, den, mag, commentSize; + + idByte = in.readU1(); + num = in.readS4(); + den = in.readS4(); + mag = in.readS4(); + commentSize = in.readU1(); + + final byte [] comment = new byte [commentSize]; + in.readFully(comment); + + ctx.commandDetermined(); + doPre( + new DviPreamble( + idByte, + DviUnit.getInstance(num, den, mag), + comment + ) + ); + } else { + final int commentSize; + in.skip(1 + 4 + 4 + 4); + commentSize = in.readU1(); + in.skip(commentSize); + } + break; + } + case DviCommand.DVI_POST: { + if (wantPost()) { + final int firstBackPointer; + final int num, den, mag, maxV, maxH, maxStackDepth, totalPages; + + firstBackPointer = in.readS4(); + num = in.readS4(); + den = in.readS4(); + mag = in.readS4(); + maxV = in.readS4(); + maxH = in.readS4(); + maxStackDepth = in.readU2(); + totalPages = in.readU2(); + + ctx.commandDetermined(); + doPost( + new DviPostamble( + firstBackPointer, + DviUnit.getInstance(num, den, mag), + maxV, maxH, + maxStackDepth, + totalPages + ) + ); + } else { + in.skip(6 * 4 + 2 * 2); + } + break; + } + case DviCommand.DVI_POST_POST: { + if (wantPostPost()) { + final int postamblePointer; + final int idByte; + + postamblePointer = in.readS4(); + idByte = in.readU1(); + + ctx.commandDetermined(); + doPostPost( + new DviPostPost( + postamblePointer, + idByte + ) + ); + } else { + in.skip(4 + 1); + } + ctx.setTerminate(true); + break; + } + case DviCommand.DVI_UNDEF1: + case DviCommand.DVI_UNDEF2: + case DviCommand.DVI_UNDEF3: + case DviCommand.DVI_UNDEF4: + case DviCommand.DVI_UNDEF5: { + ctx.commandDetermined(); + /* TODO: handle these commands. */ + break; + } + + case DviCommand.DVI_UNDEF6: { + ctx.commandDetermined(); + /* FIXME: handle TDIR */ + break; + } + + default: + /* not reached. */ + throw new IllegalStateException + ("Illegal executer state."); + } + } + } + + public boolean wantSet() { return true; } + public boolean wantPut() { return true; } + public boolean wantSelectFont() { return true; } + public boolean wantSpecial() { return true; } + public boolean wantSetRule() { return true; } + public boolean wantPutRule() { return true; } + public boolean wantDefineFont() { return true; } + public boolean wantRight() { return true; } + public boolean wantW() { return true; } + public boolean wantW0() { return true; } + public boolean wantX() { return true; } + public boolean wantX0() { return true; } + public boolean wantDown() { return true; } + public boolean wantY() { return true; } + public boolean wantY0() { return true; } + public boolean wantZ() { return true; } + public boolean wantZ0() { return true; } + public boolean wantPush() { return true; } + public boolean wantPop() { return true; } + public boolean wantNop() { return true; } + public boolean wantBop() { return true; } + public boolean wantEop() { return true; } + public boolean wantPre() { return true; } + public boolean wantPost() { return true; } + public boolean wantPostPost() { return true; } + + public void begin(DviExecutorContext ctx) throws DviException { + this.ctx.handler.begin(ctx); + } + public void end() throws DviException { + ctx.handler.end(); + } + + public void doSet(int code) throws DviException { + ctx.handler.doSet(code); + } + public void doSetRule(int w, int h) throws DviException { + ctx.handler.doSetRule(w, h); + } + public void doPut(int code) throws DviException { + ctx.handler.doPut(code); + } + public void doPutRule(int w, int h) throws DviException { + ctx.handler.doPutRule(w, h); + } + public void doNop() throws DviException { + ctx.handler.doNop(); + } + + public void doSelectFont(int fn) throws DviException { + ctx.handler.doSelectFont(fn); + } + public void doDefineFont(int fn, DviFontSpec fs) throws DviException { + ctx.handler.doDefineFont(fn, fs); + } + + public void doPush() throws DviException { + ctx.handler.doPush(); + } + public void doPop() throws DviException { + ctx.handler.doPop(); + } + + public void doPre(DviPreamble preamble) throws DviException { + ctx.handler.doPre(preamble); + } + public void doBop(DviBop bop) throws DviException { + ctx.handler.doBop(bop); + } + public void doEop() throws DviException { + ctx.handler.doEop(); + } + public void doPost(DviPostamble postamble) throws DviException { + ctx.handler.doPost(postamble); + } + public void doPostPost(DviPostPost postPost) throws DviException { + ctx.handler.doPostPost(postPost); + } + + public void doRight(int by) throws DviException { + ctx.handler.doRight(by); + } + public void doW(int by) throws DviException { + ctx.handler.doW(by); + } + public void doW0() throws DviException { + ctx.handler.doW0(); + } + public void doX(int by) throws DviException { + ctx.handler.doX(by); + } + public void doX0() throws DviException { + ctx.handler.doX0(); + } + + public void doDown(int by) throws DviException { + ctx.handler.doDown(by); + } + public void doY(int by) throws DviException { + ctx.handler.doY(by); + } + public void doY0() throws DviException { + ctx.handler.doY0(); + } + public void doZ(int by) throws DviException { + ctx.handler.doZ(by); + } + public void doZ0() throws DviException { + ctx.handler.doZ0(); + } + + public void doSpecial(byte [] xxx) throws DviException { + ctx.handler.doSpecial(xxx); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/BasicGeometer.java b/src/jp/sourceforge/dvibrowser/dvicore/render/BasicGeometer.java new file mode 100644 index 0000000..66a078e --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/BasicGeometer.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import java.util.Stack; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.DviFontTable; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviRegister; +import jp.sourceforge.dvibrowser.dvicore.api.DevicePainter; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviExecutorContext; +import jp.sourceforge.dvibrowser.dvicore.api.Geometer; +import jp.sourceforge.dvibrowser.dvicore.api.GeometerContext; +import jp.sourceforge.dvibrowser.dvicore.api.SimpleMetrics; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviBop; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostPost; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostamble; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPreamble; + + + +public class BasicGeometer +extends DviObject +implements Geometer +{ + private static final Logger LOGGER = Logger.getLogger(BasicGeometer.class.getName()); + + public BasicGeometer(DviContextSupport dcs) + { + super(dcs); + } + + protected DevicePainter dp; + public void setPainter(DevicePainter dp) { this.dp = dp; } + + private static final class GeometerContextImpl + implements GeometerContext + { + private DviFontSpec fs = null; + private SimpleMetrics sm = null; + private final Stack stack = new Stack(); + private DviRegister reg; + private DviExecutorContext exe_ctx; + + public DviFontSpec currentFontSpec() { return fs; } + public DviRegister getRegister() { return reg; } + public DviExecutorContext getExecuterContext() { return exe_ctx; } + } + + private GeometerContextImpl ctx = null; + private DviFontTable ft = null; + + public void begin(DviExecutorContext ctx) + throws DviException + { + this.ctx = new GeometerContextImpl(); + this.ctx.reg = new DviRegister(); + this.ctx.exe_ctx = ctx; + ft = ctx.getData().getFontTable(); + + dp.begin(this.ctx); + } + + public void end() + throws DviException + { + if (ctx.fs != null) { + dp.endFont(); + } + dp.end(); + ctx = null; + ft = null; + } + + + public void doSet(int code) + throws DviException + { + dp.drawChar(code); + + int tfmw = 0; + if (ctx.sm != null) { + tfmw = ctx.sm.getTfmWidth(code); + } else { + } + if (ctx.fs != null) { + ctx.reg.addH(ctx.fs.tfmToDvi(tfmw)); + } + } + + public void doSetRule(int width, int height) + throws DviException + { + dp.drawRule(width, height); + ctx.reg.addH(width); + } + + public void doPut(int code) throws DviException { + dp.drawChar(code); + } + + public void doPutRule(int w, int h) throws DviException { + dp.drawRule(w, h); + } + + public void doNop() throws DviException { + } + + public void doSelectFont(int fn) throws DviException { + if (ctx.fs != null) + dp.endFont(); + + ctx.fs = ft.get(fn); + ctx.sm = getDviContext().findDviSimpleMetrics(ctx.fs); + if (ctx.sm == null) { + LOGGER.fine("No metric for font number " + fn + " font spec: " + ctx.fs); + } + dp.beginFont(ctx.fs); + } + public void doDefineFont(int fn, DviFontSpec fs) throws DviException { + /* ignored. */ + } + + public void doPush() throws DviException { + ctx.stack.push((DviRegister) ctx.reg.clone()); + } + public void doPop() throws DviException { + if (ctx.stack.empty()) + throw new DviException("stack underflow."); + + ctx.reg.copy(ctx.stack.pop()); + } + + public void doPre(DviPreamble preamble) throws DviException { + } + public void doBop(DviBop bop) throws DviException { + ctx.reg.reset(); + ctx.stack.clear(); + dp.beginPage(bop); + } + public void doEop() throws DviException { + dp.endPage(); + } + public void doPost(DviPostamble postamble) throws DviException { + } + public void doPostPost(DviPostPost postPost) throws DviException { + ctx.exe_ctx.setTerminate(true); + } + + public void doRight(int by) throws DviException { + ctx.reg.addH(by); + } + public void doW(int by) throws DviException { + ctx.reg.setW(by); + ctx.reg.addH(by); + } + public void doW0() throws DviException { + ctx.reg.addH(ctx.reg.getW()); + } + public void doX(int by) throws DviException { + ctx.reg.setX(by); + ctx.reg.addH(by); + } + public void doX0() throws DviException { + ctx.reg.addH(ctx.reg.getX()); + } + + public void doDown(int by) throws DviException { + ctx.reg.addV(by); + } + public void doY(int by) throws DviException { + ctx.reg.setY(by); + ctx.reg.addV(by); + } + public void doY0() throws DviException { + ctx.reg.addV(ctx.reg.getY()); + } + public void doZ(int by) throws DviException { + ctx.reg.setZ(by); + ctx.reg.addV(by); + } + + public void doZ0() throws DviException { + ctx.reg.addV(ctx.reg.getZ()); + } + + public void doSpecial(byte [] xxx) throws DviException { + dp.drawSpecial(xxx); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/BinaryImage.java b/src/jp/sourceforge/dvibrowser/dvicore/render/BinaryImage.java new file mode 100644 index 0000000..e68fe7f --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/BinaryImage.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.api.BinaryDevice; + +public class BinaryImage +{ + private final byte [] buf; + private final int pitch; + private final int width; + private final int height; + + public BinaryImage(int width, int height) + { + this.width = width; + this.height = height; + this.pitch = (width + 7) >>> 3; + this.buf = new byte [pitch * height]; + } + + public BinaryImage(byte [] buf, int width, int height) + { + this.width = width; + this.height = height; + this.pitch = (width + 7) >>> 3; + this.buf = buf; + if (buf.length != pitch * height) + throw new IllegalArgumentException + ("buffer size mismatch."); + } + + public byte [] getBuffer() { return buf; } + + public int width() { return width; } + public int height() { return height; } + public int pitch() { return pitch; } + + public void fill(int c) + { + for (int i=0; i>> 3); + final byte bitMask = (byte)(1 << (7 - (x & 7))); + return (0 != (buf[bytePos + y * pitch] & bitMask)) ? 1 : 0; + } + + public void setPixel(int x, int y, int val) + { + if (x < 0 || width <= x) + throw new ArrayIndexOutOfBoundsException + (String.valueOf(x)); + if (y < 0 || height <= y) + throw new ArrayIndexOutOfBoundsException + (String.valueOf(y)); + + final int bytePos = (x >>> 3); + final int bitMask = 1 << (7 - (x & 7)); + byte c = (byte)(buf[bytePos + y * pitch] & ((0xff) ^ bitMask)); + if (val != 0) c |= bitMask; + + buf[bytePos + y * pitch] = c; + } + + public void dump() + { + for (int i=0; i>> 3]; + y = 0; + return true; + } + public void endRaster() { + } + + public void beginLine() { + for (int i=0; i>> 3)] & (1 << (7 - (j & 7))); + if (bit != 0) { + setPixel(point.x + j, point.y + y, 1); + } + } + y++; + } + } + + public void putBits(int count, boolean paintFlag) { + if (paintFlag) { + while (count-- > 0) { + l_buf[(xx >>> 3)] |= 1 << (7 - (xx & 7)); + xx++; + } + } else { + xx += count; + } + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/BoundingBoxComputer.java b/src/jp/sourceforge/dvibrowser/dvicore/render/BoundingBoxComputer.java new file mode 100644 index 0000000..0239e38 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/BoundingBoxComputer.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.api.BinaryDevice; + +public class BoundingBoxComputer +extends AbstractDevice +implements BinaryDevice +{ + private DviRect bbox = DviRect.EMPTY; + public BoundingBoxComputer(DviResolution res) + { + super(res); + } + + public DviRect getBoundingBox() + throws DviException + { + return bbox; + } + + public void begin() + throws DviException + { + } + + public void end() + throws DviException + { + } + + public boolean beginRaster(int w, int h) + throws DviException + { + bbox = bbox.union(new DviRect(getReferencePoint(), w, h)); + return false; + } + + public void endRaster() + throws DviException + { + } + + public void beginLine() + throws DviException + { + // not called. + } + + public void endLine(int repeat) + throws DviException + { + // not called. + } + + public void putBits(int count, boolean paintFlag) + throws DviException + { + // not called. + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/ByteRGBImage.java b/src/jp/sourceforge/dvibrowser/dvicore/render/ByteRGBImage.java new file mode 100644 index 0000000..df2ee31 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/ByteRGBImage.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.api.ImageDevice; + +// TODO: use GammaCorrector. +// TODO: test this class + +public class ByteRGBImage +{ + private final byte [] buf; + private final int width; + private final int height; + private final int pitch; + + public ByteRGBImage(int width, int height) + { + this.width = width; + this.height = height; + this.pitch = width * 3; + this.buf = new byte [pitch * height]; + } + + public ByteRGBImage(byte [] buf, int width, int height, int pitch) + { + this.buf = buf; + this.width = width; + this.height = height; + this.pitch = pitch; + } + + public ByteRGBImage(byte [] buf, int width, int height) + { + this(buf, width, height, 3*width); + } + + public byte [] getBuffer() { return buf; } + + public int width() { return width; } + public int height() { return height; } + + public void fill(int rgb) + { + final byte r = (byte) (rgb >>> 16); + final byte g = (byte) (rgb >>> 8); + final byte b = (byte) (rgb >>> 0); + int p0 = 0; + for (int i=0; i>> 16); + final byte g = (byte) (color >>> 8); + final byte b = (byte) (color >>> 0); + int p = ptr; + for (int i=0; i>> 10)); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/ByteRangeComputer.java b/src/jp/sourceforge/dvibrowser/dvicore/render/ByteRangeComputer.java new file mode 100644 index 0000000..c7e8399 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/ByteRangeComputer.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import jp.sourceforge.dvibrowser.dvicore.DviByteRange; +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.api.BinaryDevice; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviExecutorContext; +import jp.sourceforge.dvibrowser.dvicore.api.DviFont; +import jp.sourceforge.dvibrowser.dvicore.api.Glyph; +import jp.sourceforge.dvibrowser.dvicore.font.LogicalFont; + +public class ByteRangeComputer +extends DefaultDevicePainter +{ + private DviByteRange range = DviByteRange.EMPTY; + private final DviRect rect; + private final BinaryDevice out; + private DviRect bbox = DviRect.EMPTY; + private DviResolution res; + + public ByteRangeComputer(DviContextSupport dcs, DviResolution res, DviRect rect) + throws DviException + { + super(dcs); + this.rect = rect; + this.res = res; + out = new EmptyBinaryDevice(res); + setOutput(out); + } + + public DviByteRange getByteRange() + { + return range; + } + + public DviRect getBounds() + { + return bbox; + } + + protected void realDrawChar(LogicalFont lf, int code) + throws DviException + { + DviFont font = getFont(); + if (font != null) { + Glyph glyph = font.getGlyph(lf, code); + if (glyph != null) { + shipOutBOX( + glyph.bounds().translate(out.getReferencePoint()) + ); + } + } + } + + protected void realDrawRule(int w, int h) + throws DviException + { + shipOutBOX( + new DviRect(0, 0, w, h).translate(out.getReferencePoint()) + ); + } + + private void shipOutBOX(DviRect box) + throws DviException + { + if (box.intersects(rect)) { + bbox = bbox.union(box); + DviExecutorContext ctx = getGeometerContext().getExecuterContext(); + range = range.union( + ctx.getCommandRange() + ); + } + } + + public void drawSpecial(byte [] _xxx) + throws DviException + { + // ignored. + } + + public DviResolution getResolution() { + return res; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/DefaultDevicePainter.java b/src/jp/sourceforge/dvibrowser/dvicore/render/DefaultDevicePainter.java new file mode 100644 index 0000000..ce721ac --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/DefaultDevicePainter.java @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviByteRange; +import jp.sourceforge.dvibrowser.dvicore.DviColor; +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviRegister; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.DviUnit; +import jp.sourceforge.dvibrowser.dvicore.api.BinaryDevice; +import jp.sourceforge.dvibrowser.dvicore.api.DevicePainter; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviData; +import jp.sourceforge.dvibrowser.dvicore.api.DviFont; +import jp.sourceforge.dvibrowser.dvicore.api.DviPage; +import jp.sourceforge.dvibrowser.dvicore.api.FullMetrics; +import jp.sourceforge.dvibrowser.dvicore.api.GeometerContext; +import jp.sourceforge.dvibrowser.dvicore.api.Glyph; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviBop; +import jp.sourceforge.dvibrowser.dvicore.ctx.DviToolkit; +import jp.sourceforge.dvibrowser.dvicore.font.LogicalFont; +import jp.sourceforge.dvibrowser.dvicore.special.Anchor; +import jp.sourceforge.dvibrowser.dvicore.special.AnchorSet; + + +// TODO: support color special across pages. + +public class DefaultDevicePainter +extends DviObject +implements DevicePainter +{ + private static final Logger LOGGER = Logger.getLogger(DefaultDevicePainter.class.getName()); + private BinaryDevice out = null; + private DviColor defaultColor; + + public DefaultDevicePainter(DviContextSupport dcs) + { + super(dcs); + } + + public void setOutput(BinaryDevice out) + throws DviException + { + this.out = out; + defaultColor = out.getColor(); + } + + public BinaryDevice getOutput() { return out; } + + + private GeometerContext geom_ctx = null; + + protected GeometerContext getGeometerContext() + { + return geom_ctx; + } + + private DviUnit dviUnit = null; + + protected DviUnit getDviUnit() + { + return dviUnit; + } + + private DviResolution res = null; + private double factor; + + public void begin(GeometerContext ctx) + throws DviException + { + geom_ctx = ctx; + dviUnit = geom_ctx.getExecuterContext() + .getData() + .getDviUnit(); + res = out.getResolution(); + out.begin(); + out.translate(res.dpi(), res.dpi()); + factor = dviUnit.factorDouble(res.dpi()); + } + + public void end() + throws DviException + { + out.end(); + res = null; + dviUnit = null; + geom_ctx = null; + } + + private AnchorSet anchors = null; + + public void beginPage(DviBop bop) + throws DviException + { + DviToolkit utils = getDviContext().getDviToolkit(); + DviData data = geom_ctx.getExecuterContext().getData(); + if (data instanceof DviPage) { + anchors = utils.getAnchorSet((DviPage) data); + LOGGER.finer("anchors=" + anchors); + } + } + + public void endPage() + throws DviException + { + anchors = null; + } + + private LogicalFont lf = null; + + protected LogicalFont getLogicalFont() + { + return lf; + } + + private boolean fontResolved = false; + private DviFont font = null; + + protected DviFont getFont() + { + return font; + } + + public void beginFont(DviFontSpec fs) + throws DviException + { + lf = LogicalFont.getInstance(fs, dviUnit, res); + fontResolved = false; + font = null; + } + + public void endFont() + throws DviException + { + fontResolved = false; + font = null; + lf = null; + } + + private boolean enableCharRendering = true; + private boolean enableCharBoundingBox = false; + + private void drawRectInternal(int ax, int ay, int ex, int ey) + throws DviException + { + out.save(); + try { + out.translate(ax, ay); + realDrawRule(ex - ax + 1, ey - ay + 1); + } finally { + out.restore(); + } + } + + protected void drawCharBoundingBox(int code) + throws DviException + { + final DviRegister reg = geom_ctx.getRegister(); + + DviFontSpec fs = lf.fontSpec(); + FullMetrics fm = getDviContext().findDviFullMetrics(fs); + if (fm != null) { + int width = fs.tfmToDvi(fm.getTfmWidth(code)); + int height = fs.tfmToDvi(fm.getTfmHeight(code)); + int depth = fs.tfmToDvi(fm.getTfmDepth(code)); + + final int ax_sf = (int)(factor * reg.getH() + 0.5); + final int ex_sf = (int)(factor * (reg.getH() + width - 1) + 0.5); + final int ay_sf = (int)(factor * (reg.getV() - height + 1) + 0.5); + final int ey_sf = (int)(factor * (reg.getV() + depth - 1) + 0.5); + final int by_sf = (int)(factor * (reg.getV() ) + 0.5); + + drawRectInternal(ax_sf, ay_sf, ex_sf, ay_sf); + drawRectInternal(ax_sf, ey_sf, ex_sf, ey_sf); + drawRectInternal(ax_sf, ay_sf, ax_sf, ey_sf); + drawRectInternal(ex_sf, ay_sf, ex_sf, ey_sf); + drawRectInternal(ax_sf, by_sf, ex_sf, by_sf); + } + } + + public void drawChar(int code) + throws DviException + { + handleAnchors(); + + if (getEnableCharRendering()) { + final DviRegister reg = geom_ctx.getRegister(); + final int rx_sf = (int) (factor * reg.getH() + 0.5); + final int ry_sf = (int) (factor * reg.getV() + 0.5); + + out.save(); + try { + out.translate(rx_sf, ry_sf); + realDrawChar(lf, code); + } finally { + out.restore(); + } + } + if (getEnableCharBoundingBox()) { + drawCharBoundingBox(code); + } + } + + protected void resolveFont() + { + if (!fontResolved) { + try { + font = getDviContext().findDviFont(lf); + } catch (DviException ex) { + // TODO: logging + ex.printStackTrace(); + font = null; + } finally { + fontResolved = true; + } + } + } + + protected void realDrawChar(LogicalFont lf, int code) + throws DviException + { + resolveFont(); + if (font == null) + return; + + determineColor(out); + Glyph g = font.getGlyph(lf, code); + + if (g != null) { + g.rasterizeTo(out); + } + } + + public void drawRule(int width, int height) + throws DviException + { + handleAnchors(); + if (width <= 0 || height <= 0) return; + + final DviRegister reg = geom_ctx.getRegister(); + + final int ax_sf = (int)(factor * reg.getH() + 0.5); + final int ex_sf = (int)(factor * (reg.getH() + width - 1) + 0.5); + final int ay_sf = (int)(factor * (reg.getV() - height + 1) + 0.5); + final int ey_sf = (int)(factor * reg.getV() + 0.5); + + out.save(); + try { + out.translate(ax_sf, ay_sf); + realDrawRule(ex_sf - ax_sf + 1, ey_sf - ay_sf + 1); + } finally { + out.restore(); + } + } + + protected void realDrawRule(int w_sf, int h_sf) + throws DviException + { + if (out.beginRaster(w_sf, h_sf)) { + determineColor(out); + out.beginLine(); + out.putBits(w_sf, true); + out.endLine(h_sf); + } + out.endRaster(); + } + + private final java.util.Stack colorStack + = new java.util.Stack(); + private static final java.util.regex.Pattern pushPat + = java.util.regex.Pattern.compile( + "color\\s+push\\s+(.*)", + java.util.regex.Pattern.CASE_INSENSITIVE + ); + private static final java.util.regex.Pattern popPat + = java.util.regex.Pattern.compile( + "color\\s+pop", + java.util.regex.Pattern.CASE_INSENSITIVE + ); + private static final java.util.regex.Pattern colorPat + = java.util.regex.Pattern.compile( + "color\\s+(.*)", + java.util.regex.Pattern.CASE_INSENSITIVE + ); + private DviColor specialColor = DviColor.INVALID; + + + // TODO: outsource color special handler. + public void drawSpecial(byte [] _xxx) + throws DviException + { + handleAnchors(); + String xxx = new String(_xxx); + java.util.regex.Matcher mat; + if ((mat = pushPat.matcher(xxx)).matches()) { + DviColor aColor = DviColor.parseColor(mat.group(1)); + colorStack.push(out.getColor()); + specialColor = aColor; + } else if ((mat = popPat.matcher(xxx)).matches()) { + if (colorStack.empty()) + // TODO: Handle this as a warning. + throw new IllegalStateException + ("Color stack underflow"); + specialColor = colorStack.pop(); + } else if ((mat = colorPat.matcher(xxx)).matches()) { + DviColor aColor = DviColor.parseColor(mat.group(1)); + specialColor = aColor; + } + } + + // TODO: make anchor renderer injectable. + private DviColor anchorColor = DviColor.INVALID; + private void handleAnchors() + throws DviException + { + if (anchors == null || anchors.size() == 0) return; + LOGGER.finer("Rendering Anchor" + anchors); + long begin = geom_ctx.getExecuterContext().getCommandRange().begin(); + anchorColor = DviColor.INVALID; + for (DviByteRange br : anchors) { + if (!br.contains(begin)) continue; + if (br instanceof Anchor.Href) { + // Anchor.Href href = (Anchor.Href) br; + //TODO: outsource the color settings. + anchorColor = DviColor.parseColor("blue"); +// } else if (br instanceof Anchor.Source) { +// Anchor.Source source = (Anchor.Source) br; + // anchorColor = DviColor.parseColor("yellow"); + } + } + } + + private void determineColor(BinaryDevice out) + throws DviException + { + if (anchorColor.isValid()) { + out.setColor(anchorColor); + } else if (specialColor.isValid()) { + out.setColor(specialColor); + } else { + out.setColor(defaultColor); + } + } + + public void setEnableCharRendering(boolean enableCharRendering) + { + this.enableCharRendering = enableCharRendering; + } + + public boolean getEnableCharRendering() + { + return enableCharRendering; + } + + public void setEnableCharBoundingBox(boolean enableCharBoundingBox) + { + this.enableCharBoundingBox = enableCharBoundingBox; + } + + public boolean getEnableCharBoundingBox() + { + return enableCharBoundingBox; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/DefaultGammaCorrector.java b/src/jp/sourceforge/dvibrowser/dvicore/render/DefaultGammaCorrector.java new file mode 100644 index 0000000..8f889bf --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/DefaultGammaCorrector.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import java.util.concurrent.atomic.AtomicLong; + +import jp.sourceforge.dvibrowser.dvicore.api.GammaCorrector; + + +public class DefaultGammaCorrector +implements GammaCorrector +{ + private static final AtomicLong serializer = new AtomicLong(); + private final double factor, exponent; + private final long serial; + + public DefaultGammaCorrector() + { + this(1.0, 1.0); + } + + public DefaultGammaCorrector(double factor, double exponent) + { + this.factor = factor; + this.exponent = exponent; + this.serial = serializer.incrementAndGet(); + } + + public double factor() { return factor; } + public double exponent() { return exponent; } + + public int correctGamma(int c, int maxval) + { + return (int) ( + 1024 * + Math.min( + 1.0, + Math.pow(factor * c / maxval, exponent) + ) + + 0.5 + ); + } + + @Override + public int hashCode() { + return (int) (33 * (factor + 33 * exponent)); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof DefaultGammaCorrector)) return false; + DefaultGammaCorrector gc = (DefaultGammaCorrector) o; + return (factor == gc.factor && exponent == gc.exponent); + } + + public String getCacheKey() { + return getClass().getName() + "--" + serial; + } + + @Override + public String toString() { + return getClass().getName() + "[factor=" + factor+ ",exponent=" + exponent + "]"; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/DumpBinaryDevice.java b/src/jp/sourceforge/dvibrowser/dvicore/render/DumpBinaryDevice.java new file mode 100644 index 0000000..8e77324 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/DumpBinaryDevice.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import java.io.PrintStream; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.api.BinaryDevice; + + +public class DumpBinaryDevice +extends AbstractDevice +implements BinaryDevice +{ + private final PrintStream out; + + // TODO: outsource the default resolution + public DumpBinaryDevice(PrintStream out) + { + super(new DviResolution(1200, 10)); + this.out = out; + } + + public void begin() throws DviException {} + public void end() throws DviException {} + + public boolean beginRaster(int gw_sf, int gh_sf) + throws DviException + { + return true; + } + + public void endRaster() + throws DviException + { + out.println(); + } + + String buf; + + public void beginLine() + throws DviException + { + buf = ""; + } + + public void endLine(int repeat) + throws DviException + { + for (int i=0; i<=repeat; i++) { + out.println(buf); + } + } + + public void putBits(int count, boolean paintFlag) + throws DviException + { + for (int i=0; i { + private static final Logger LOGGER = Logger + .getLogger(DviBoundingBoxPreparator.class.getName()); + private final DviPage page; + private final DviResolution res; + + public DviBoundingBoxPreparator(DviContextSupport dcs, DviPage page, DviResolution res) { + super(dcs); + this.page = page; + this.res = res; + } + + public DviRect call() throws Exception + { + BoundingBoxComputer bbc = new BoundingBoxComputer(res); + DefaultDevicePainter dp = new DefaultDevicePainter(this); + dp.setEnableCharBoundingBox(true); + dp.setEnableCharRendering(false); + dp.setOutput(bbc); + Geometer geometer = new BasicGeometer(this); + geometer.setPainter(dp); + getDviContext().execute(page, geometer); + DviRect bbox = bbc.getBoundingBox(); + LOGGER.finer("bounding box=" + bbox + " resolution=" + res + " page=" + page); + return bbox; + } + + public String getCacheKey() { + String key = page.getCacheKey() + "-" + res.dpi(); + return key; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/DviExecutorFilter.java b/src/jp/sourceforge/dvibrowser/dvicore/render/DviExecutorFilter.java new file mode 100644 index 0000000..6859d52 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/DviExecutorFilter.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.api.DviExecutorContext; +import jp.sourceforge.dvibrowser.dvicore.api.DviExecutorHandler; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviBop; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostPost; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostamble; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPreamble; + +public class DviExecutorFilter +implements DviExecutorHandler +{ + private static final EmptyDviExecutorHandler empty = new EmptyDviExecutorHandler(); + private final DviExecutorHandler next; + + public DviExecutorFilter(DviExecutorHandler next) + { + this.next = (next != null) ? next : empty; + } + + public void begin(DviExecutorContext ctx) + throws DviException + { + next.begin(ctx); + } + + public void end() + throws DviException + { + next.end(); + } + + public void doSet(int code) + throws DviException + { + next.doSet(code); + } + + public void doSetRule(int w, int h) + throws DviException + { + next.doSetRule(w, h); + } + + public void doPut(int code) + throws DviException + { + next.doPut(code); + } + + public void doPutRule(int w, int h) + throws DviException + { + next.doPutRule(w, h); + } + + public void doNop() + throws DviException + { + next.doNop(); + } + + public void doSelectFont(int fn) + throws DviException + { + next.doSelectFont(fn); + } + + public void doDefineFont(int fn, DviFontSpec fs) + throws DviException + { + next.doDefineFont(fn, fs); + } + + public void doPush() + throws DviException + { + next.doPush(); + } + + public void doPop() + throws DviException + { + next.doPop(); + } + + public void doPre(DviPreamble preamble) + throws DviException + { + next.doPre(preamble); + } + + public void doBop(DviBop bop) + throws DviException + { + next.doBop(bop); + } + + public void doEop() + throws DviException + { + next.doEop(); + } + + public void doPost(DviPostamble postamble) + throws DviException + { + next.doPost(postamble); + } + + public void doPostPost(DviPostPost postPost) + throws DviException + { + next.doPostPost(postPost); + } + + public void doRight(int by) + throws DviException + { + next.doRight(by); + } + + public void doW(int by) + throws DviException + { + next.doW(by); + } + + public void doW0() + throws DviException + { + next.doW0(); + } + + public void doX(int by) + throws DviException + { + next.doX(by); + } + + public void doX0() + throws DviException + { + next.doX0(); + } + + public void doDown(int by) + throws DviException + { + next.doDown(by); + } + + public void doY(int by) + throws DviException + { + next.doY(by); + } + + public void doY0() + throws DviException + { + next.doY0(); + } + + public void doZ(int by) + throws DviException + { + next.doZ(by); + } + + public void doZ0() + throws DviException + { + next.doZ0(); + } + + public void doSpecial(byte [] xxx) + throws DviException + { + next.doSpecial(xxx); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/DviPagePreparator.java b/src/jp/sourceforge/dvibrowser/dvicore/render/DviPagePreparator.java new file mode 100644 index 0000000..cbb553d --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/DviPagePreparator.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviPage; +import jp.sourceforge.dvibrowser.dvicore.ctx.DviToolkit; +import jp.sourceforge.dvibrowser.dvicore.gui.swing.ViewSpec; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.Computation; +import jp.sourceforge.dvibrowser.dvicore.util.progress.ProgressItem; + + +public class DviPagePreparator +extends DviObject +implements Computation { + private static final Logger LOGGER = Logger.getLogger(DviPagePreparator.class + .getName()); + private final DviPage page; + private final ViewSpec viewSpec; + + public DviPagePreparator(DviContextSupport dcs, DviPage page, ViewSpec viewSpec) + { + super(dcs); + this.page = page; + this.viewSpec = viewSpec; + } + + public Long call() throws Exception + { + if (page == null) return -1L; + final ProgressItem progress = getDviContext().getProgressRecorder().open("loading page " + (page.getPageNumber() + 1)); + try { + long start = System.currentTimeMillis(); + LOGGER.finer("Start preparation of page " + page); + ViewSpec dummyViewSpec = (ViewSpec) viewSpec.clone(); + DviResolution res = viewSpec.getResolution(); + dummyViewSpec.setResolution(res.approximate(10)); + DviToolkit utils = getDviContext().getDviToolkit(); + utils.renderToBufferedImage(page, null, dummyViewSpec); + long end = System.currentTimeMillis(); + LOGGER.finer("Finished preparation of page " + page); + LOGGER.finer(" Elapsed time = " + (end - start)); + return (end - start); + } finally { + progress.close(); + } + } + + public String getCacheKey() + { + return page.getCacheKey(); + } + + public DviPage getPage() + { + return page; + } + + public ViewSpec getViewSpec() + { + return viewSpec; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/EmptyBinaryDevice.java b/src/jp/sourceforge/dvibrowser/dvicore/render/EmptyBinaryDevice.java new file mode 100644 index 0000000..519a198 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/EmptyBinaryDevice.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.api.BinaryDevice; + +public class EmptyBinaryDevice +extends AbstractDevice +implements BinaryDevice +{ + public EmptyBinaryDevice(DviResolution res) + { + super(res); + } + + public void begin() throws DviException {} + public void end() throws DviException {} + + public boolean beginRaster(int gw_sf, int gh_sf) + throws DviException + { + return true; + } + public void endRaster() throws DviException {} + public void beginLine() throws DviException {} + public void endLine(int repeat) throws DviException {} + public void putBits(int count, boolean paintFlag) throws DviException {} +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/EmptyDevicePainter.java b/src/jp/sourceforge/dvibrowser/dvicore/render/EmptyDevicePainter.java new file mode 100644 index 0000000..ab8e26f --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/EmptyDevicePainter.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.api.BinaryDevice; +import jp.sourceforge.dvibrowser.dvicore.api.DevicePainter; +import jp.sourceforge.dvibrowser.dvicore.api.GeometerContext; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviBop; + +public class EmptyDevicePainter +implements DevicePainter +{ + public void setOutput(BinaryDevice out) throws DviException {} + + public void begin(GeometerContext ctx) throws DviException {} + public void end() throws DviException {} + public void beginPage(DviBop bop) throws DviException {} + public void endPage() throws DviException {} + + public void beginFont(DviFontSpec fs) throws DviException {} + public void endFont() throws DviException {} + + public void drawChar(int code) throws DviException {} + public void drawRule(int width, int height) throws DviException {} + public void drawSpecial(byte [] xxx) throws DviException {} +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/EmptyDviExecutorHandler.java b/src/jp/sourceforge/dvibrowser/dvicore/render/EmptyDviExecutorHandler.java new file mode 100644 index 0000000..c79ce40 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/EmptyDviExecutorHandler.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.api.DviExecutorContext; +import jp.sourceforge.dvibrowser.dvicore.api.DviExecutorHandler; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviBop; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostPost; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostamble; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPreamble; + +public class EmptyDviExecutorHandler +implements DviExecutorHandler +{ + public void begin(DviExecutorContext ctx) throws DviException {} + public void end() throws DviException {} + + public void doSet(int code) throws DviException {} + public void doSetRule(int w, int h) throws DviException {} + public void doPut(int code) throws DviException {} + public void doPutRule(int w, int h) throws DviException {} + public void doNop() throws DviException {} + + public void doSelectFont(int fn) throws DviException {} + public void doDefineFont(int fn, DviFontSpec fs) throws DviException {} + + public void doPush() throws DviException {} + public void doPop() throws DviException {} + + public void doPre(DviPreamble preamble) throws DviException {} + public void doBop(DviBop bop) throws DviException {} + public void doEop() throws DviException {} + public void doPost(DviPostamble postamble) throws DviException {} + public void doPostPost(DviPostPost postPost) throws DviException {} + + public void doRight(int by) throws DviException {} + public void doW(int by) throws DviException {} + public void doW0() throws DviException {} + public void doX(int by) throws DviException {} + public void doX0() throws DviException {} + + public void doDown(int by) throws DviException {} + public void doY(int by) throws DviException {} + public void doY0() throws DviException {} + public void doZ(int by) throws DviException {} + public void doZ0() throws DviException {} + + public void doSpecial(byte [] xxx) throws DviException {} +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/GammaCorrectorCache.java b/src/jp/sourceforge/dvibrowser/dvicore/render/GammaCorrectorCache.java new file mode 100644 index 0000000..7dbe436 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/GammaCorrectorCache.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import jp.sourceforge.dvibrowser.dvicore.api.GammaCorrector; +import jp.sourceforge.dvibrowser.dvicore.util.DviCache; + +public class GammaCorrectorCache +implements GammaCorrector +{ + private static final int MAX_LOOKUP_TABLE_SIZE = 65536; + private int maxval; + private LookupTable table; + private boolean canLookUp; + private final GammaCorrector gammaCorrector; + + private static class LookupTable + { + private final int[] data; + + public LookupTable(int maxval) + { + this.data = new int [maxval+1]; + } + } + + private static final DviCache + cache = new DviCache(10); + + public static GammaCorrector wrap(GammaCorrector gammaCorrector) + { + return new GammaCorrectorCache(gammaCorrector); + } + + private GammaCorrectorCache(GammaCorrector gammaCorrector) + { + this.gammaCorrector = gammaCorrector; + } + + public void setMaxValue(int maxval) + { + this.maxval = maxval; + if (maxval < MAX_LOOKUP_TABLE_SIZE) { + String key = gammaCorrector.getCacheKey() + "--" + maxval; + LookupTable table = cache.get(key); + if (table == null) { + table = new LookupTable(maxval); + for (int i=0; i<=maxval; i++) { + table.data[i] = doCorrectGamma(i, maxval); + } + cache.put(key, table); + } + this.table = table; + canLookUp = true; + } else { + canLookUp = false; + } + } + + public int correctGamma(int c, int maxval) + { + if (c < 0) throw new IllegalArgumentException("c is negative"); + if (maxval < 0) throw new IllegalArgumentException("maxval is negative"); + + if (gammaCorrector == null) return 0; + if (maxval != this.maxval) setMaxValue(maxval); + if (canLookUp && c <= maxval) { + return table.data[c]; + } + return doCorrectGamma(c, maxval); + } + + private int doCorrectGamma(int c, int maxval) + { + return gammaCorrector.correctGamma(c, maxval); + } + + public GammaCorrector getGammaCorrector() + { + return gammaCorrector; + } + + public String getCacheKey() { + return null; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/IntRGBImage.java b/src/jp/sourceforge/dvibrowser/dvicore/render/IntRGBImage.java new file mode 100644 index 0000000..9288c26 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/IntRGBImage.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.api.GammaCorrector; +import jp.sourceforge.dvibrowser.dvicore.api.ImageDevice; +import jp.sourceforge.dvibrowser.dvicore.gui.swing.ViewSpec; + + +public class IntRGBImage +{ + private final int [] buf; + private final int width; + private final int height; + + public IntRGBImage(int width, int height) { + this.buf = new int [width * height]; + this.width = width; + this.height = height; + } + + public IntRGBImage(int [] buf, int width, int height) { + this.buf = buf; + this.width = width; + this.height = height; + } + + public int [] getBuffer() { return buf; } + + public int width() { return width; } + public int height() { return height; } + + public void fill(int c) { + for (int i=0; i>> 10; + b &= 0xff; + c1 >>>= 8; + c2 >>>= 8; + + g = c1 & 0xff; + g += (alpha10 * ((c2 & 0xff) - g)) >>> 10; + g &= 0xff; + c1 >>>= 8; + c2 >>>= 8; + + r = c1 & 0xff; + r += (alpha10 * ((c2 & 0xff) - r)) >>> 10; + r &= 0xff; + + return 0xff000000 | (r << 16) | (g << 8) | b; + } + + private static int blend(int c1, int c2, final int alpha10) { + int r, g, b; + + b = c1 & 0xff; + b += (alpha10 * ((c2 & 0xff) - b)) >>> 10; + b &= 0xff; + c1 >>>= 8; + c2 >>>= 8; + + g = c1 & 0xff; + g += (alpha10 * ((c2 & 0xff) - g)) >>> 10; + g &= 0xff; + c1 >>>= 8; + c2 >>>= 8; + + r = c1 & 0xff; + r += (alpha10 * ((c2 & 0xff) - r)) >>> 10; + r &= 0xff; + + return (r << 16) | (g << 8) | b; + } + +} +//BenchMark: dvidump: 535 samples in 19.174 sec. 27.902 samples/sec. 35.839 msec./sample. diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/RunLengthSampler.java b/src/jp/sourceforge/dvibrowser/dvicore/render/RunLengthSampler.java new file mode 100644 index 0000000..0f22b4a --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/RunLengthSampler.java @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import jp.sourceforge.dvibrowser.dvicore.DviColor; +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviPoint; +import jp.sourceforge.dvibrowser.dvicore.DviRect; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.api.BinaryDevice; +import jp.sourceforge.dvibrowser.dvicore.api.ImageDevice; + +public class RunLengthSampler +extends AbstractDevice +implements BinaryDevice +{ + private final ImageDevice out; + private final int sf; + + public RunLengthSampler(ImageDevice out) + throws DviException + { + super(out.getResolution()); + this.out = out; + sf = out.getResolution().shrinkFactor(); + } + + public DviResolution getResolution() + throws DviException + { + return out.getResolution(); + } + + private int level = 0; + + public void begin() + throws DviException + { + if (level == 0) { + point = out.getReferencePoint().magnify(sf); + // TODO: fix by a floored mod. + + super.setColor(out.getColor()); + out.begin(sf*sf); + out.save(); + out.setReferencePoint(DviPoint.ORIGIN); + } else { + out.save(); + } + level++; + } + + public void end() + throws DviException + { + level--; + out.restore(); + if (level == 0) { + out.end(); + } + } + +/* + public void translate(int dx, int dy) throws DviException { + super.translate(dx, dy); + // TODO: propagate the change to out + // if this method is called from outside begin() .. end() block. + } + + public void save() throws DviException { + super.save(); + } + + public void restore() throws DviException { + super.restore(); + // TODO: propagate the change to out + // if this method is called from outside begin() .. end() block. + } + */ + + public void setColor(DviColor color) + throws DviException + { + super.setColor(color); + out.setColor(color); + } + + private boolean needPaint = false; + private DviRect cpy; + private int l_pad_sf; + + private int [] s_buf = null; + + private int cph; + private int s_sx; + private int s_sy; + + private int yy; + + private int [] l_buf = null; + private int [] empty_buf = null; + + public boolean beginRaster(int gw_sf, int gh_sf) + throws DviException + { + out.save(); + needPaint = false; + + DviRect r_in_sf = new DviRect(point, gw_sf, gh_sf); + DviRect r_in = r_in_sf.shrink(sf); + l_pad_sf = r_in_sf.x() - r_in.x() * sf; + int t_pad_sf = r_in_sf.y() - r_in.y() * sf; + + cpy = r_in; + DviRect bounds = out.getBounds(); + if (bounds != null) { + cpy = cpy.intersect(bounds); + } + + if (cpy.isEmpty()) { + return false; + } + + s_buf = new int [cpy.width()]; + yy = t_pad_sf; + + s_sx = cpy.x() - r_in.x(); + s_sy = cpy.y() - r_in.y(); + l_buf = new int [r_in.width()]; + empty_buf = new int [r_in.width()]; + cph = cpy.height(); + + out.setReferencePoint(cpy.topLeft()); + needPaint = out.beginImage(cpy.width(), cpy.height()); + return needPaint; + } + + public void endRaster() + throws DviException + { + out.restore(); + flushLine(); + out.endImage(); + s_buf = null; + l_buf = null; + empty_buf = null; + } + + private void flushLine() + throws DviException + { + if (needPaint == false) return; + if (cpy.width() == 0) return; // In this case s_buf == null. + + if (s_sy > 0) { + s_sy--; + } else { + if (cph > 0) { + out.putLine(s_buf, 0, s_buf.length); + cph--; + } + } + } + + private int xx; + private int x_pos; + public void beginLine() + throws DviException + { + System.arraycopy(empty_buf, 0, l_buf, 0, l_buf.length); + + x_pos = 0; + xx = l_pad_sf; + } + + public void endLine(int count) + throws DviException + { + count++; + final int left = sf - yy; + if (left <= count) { + for (int j=0; j= sf) { + for (int j=0; j= sf) { + flushLine(); + count -= sf; + } + } + System.arraycopy(empty_buf, 0, s_buf, 0, s_buf.length); + yy = count; + } else { + yy += count; + } + + if (count > 0) { + for (int j=0; j= sf) { + l_buf[x_pos++] += sf; + count -= sf; + } + xx = count; + } else { + xx += count; + } + if (count > 0) { + l_buf[x_pos] += count; + } + } else { + xx += count; + x_pos += xx / sf; + xx %= sf; + /* + while (xx >= sf) { + x_pos++; + xx -= sf; + } + */ + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/StopHandler.java b/src/jp/sourceforge/dvibrowser/dvicore/render/StopHandler.java new file mode 100644 index 0000000..2165d19 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/StopHandler.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.api.DviExecutorContext; +import jp.sourceforge.dvibrowser.dvicore.api.DviExecutorHandler; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviBop; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostPost; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostamble; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPreamble; + +public class StopHandler +implements DviExecutorHandler +{ + private DviExecutorContext ctx; + public void begin(DviExecutorContext ctx) throws DviException { + this.ctx = ctx; + } + public void end() throws DviException { ctx = null; } + + public void doSet(int code) throws DviException { + ctx.setTerminate(true); + } + public void doSetRule(int w, int h) throws DviException { + ctx.setTerminate(true); + } + public void doPut(int code) throws DviException { + ctx.setTerminate(true); + } + public void doPutRule(int w, int h) throws DviException { + ctx.setTerminate(true); + } + public void doNop() throws DviException { + ctx.setTerminate(true); + } + + public void doSelectFont(int fn) throws DviException { + ctx.setTerminate(true); + } + public void doDefineFont(int fn, DviFontSpec fs) throws DviException { + ctx.setTerminate(true); + } + + public void doPush() throws DviException { + ctx.setTerminate(true); + } + public void doPop() throws DviException { + ctx.setTerminate(true); + } + + public void doPre(DviPreamble preamble) throws DviException { + ctx.setTerminate(true); + } + public void doBop(DviBop bop) throws DviException { + ctx.setTerminate(true); + } + public void doEop() throws DviException { + ctx.setTerminate(true); + } + public void doPost(DviPostamble postamble) throws DviException { + ctx.setTerminate(true); + } + public void doPostPost(DviPostPost postPost) throws DviException { + ctx.setTerminate(true); + } + + public void doRight(int by) throws DviException { + ctx.setTerminate(true); + } + public void doW(int by) throws DviException { + ctx.setTerminate(true); + } + public void doW0() throws DviException { + ctx.setTerminate(true); + } + public void doX(int by) throws DviException { + ctx.setTerminate(true); + } + public void doX0() throws DviException { + ctx.setTerminate(true); + } + + public void doDown(int by) throws DviException { + ctx.setTerminate(true); + } + public void doY(int by) throws DviException { + ctx.setTerminate(true); + } + public void doY0() throws DviException { + ctx.setTerminate(true); + } + public void doZ(int by) throws DviException { + ctx.setTerminate(true); + } + public void doZ0() throws DviException { + ctx.setTerminate(true); + } + + public void doSpecial(byte [] xxx) throws DviException { + ctx.setTerminate(true); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/render/VirtualFontGeometer.java b/src/jp/sourceforge/dvibrowser/dvicore/render/VirtualFontGeometer.java new file mode 100644 index 0000000..91f1421 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/render/VirtualFontGeometer.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.render; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; + +public class VirtualFontGeometer +extends BasicGeometer +{ + private final DviFontSpec fs; + private final double factor; + public VirtualFontGeometer(DviContextSupport dcs, DviFontSpec fs) { + super(dcs); + this.fs = fs; + factor = (double) fs.spaceSize() / (double)(1 << 20); + } + + public DviFontSpec getFontSpec() { + return fs; + } + + private int scale(int a) { + return (int)(a * factor); + } + + public void doSetRule(int width, int height) throws DviException { + super.doSetRule( + scale(width), scale(height) + ); + } + + public void doPutRule(int width, int height) throws DviException { + super.doPutRule( + scale(width), scale(height) + ); + } + + public void doRight(int by) throws DviException { + super.doRight(scale(by)); + } + public void doW(int by) throws DviException { + super.doW(scale(by)); + } + public void doX(int by) throws DviException { + super.doX(scale(by)); + } + + public void doDown(int by) throws DviException { + super.doDown(scale(by)); + } + public void doY(int by) throws DviException { + super.doY(scale(by)); + } + public void doZ(int by) throws DviException { + super.doZ(scale(by)); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/special/AbstractDviSpecialExecutor.java b/src/jp/sourceforge/dvibrowser/dvicore/special/AbstractDviSpecialExecutor.java new file mode 100644 index 0000000..c80ada3 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/special/AbstractDviSpecialExecutor.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.special; + +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.render.BasicExecutor; + +public abstract class AbstractDviSpecialExecutor +extends BasicExecutor +{ + public AbstractDviSpecialExecutor(DviContextSupport dcs) { + super(dcs); + } + + public boolean wantSet() { return false; } + public boolean wantPut() { return false; } + public boolean wantSelectFont() { return false; } + public boolean wantSpecial() { return true; } + public boolean wantSetRule() { return false; } + public boolean wantPutRule() { return false; } + public boolean wantDefineFont() { return false; } + public boolean wantRight() { return false; } + public boolean wantW() { return false; } + public boolean wantW0() { return false; } + public boolean wantX() { return false; } + public boolean wantX0() { return false; } + public boolean wantDown() { return false; } + public boolean wantY() { return false; } + public boolean wantY0() { return false; } + public boolean wantZ() { return false; } + public boolean wantZ0() { return false; } + public boolean wantPush() { return false; } + public boolean wantPop() { return false; } + public boolean wantNop() { return false; } + public boolean wantBop() { return false; } + public boolean wantEop() { return false; } + public boolean wantPre() { return false; } + public boolean wantPost() { return false; } + public boolean wantPostPost() { return false; } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/special/Anchor.java b/src/jp/sourceforge/dvibrowser/dvicore/special/Anchor.java new file mode 100644 index 0000000..48432d4 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/special/Anchor.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.special; + +import jp.sourceforge.dvibrowser.dvicore.DviByteRange; + +public class Anchor +extends DviByteRange +{ + public Anchor(long begin, long end) { + super(begin, end); + } + + public static class StringValued + extends Anchor + { + private String str; + + public StringValued(long begin, long end, String str) { + super(begin, end); + this.str = str; + } + public String string() { return str; } + + public String toString() { + return getClass().getName() + + "[range=" + super.toString() + + ",str=" + str + + "]"; + } + } + + public static class Href + extends StringValued + { + public Href(long begin, long end, String str) { + super(begin, end, str); + } + public String getLocation() { return string(); } + } + + public static class Name + extends StringValued + { + public Name(long begin, long end, String str) { + super(begin, end, str); + } + public String name() { return string(); } + } + + public static class Source + extends StringValued + { + private final int lineNumber; + public Source(long begin, long end, String str, int lineNumber) { + super(begin, end, str); + this.lineNumber = lineNumber; + } + public String getFilename() { return string(); } + public int getLineNumber() + { + return lineNumber; + } + public String toString() { + return getClass().getName() + + "[range=" + super.toString() + + ",filename=" + string() + + ",lineNumber=" + lineNumber + + "]"; + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/special/AnchorSet.java b/src/jp/sourceforge/dvibrowser/dvicore/special/AnchorSet.java new file mode 100644 index 0000000..2cc7385 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/special/AnchorSet.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.special; + +public class AnchorSet +extends ByteRangeSet +{ + private static final long serialVersionUID = -1414405820823767279L; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/special/ByteRangeSet.java b/src/jp/sourceforge/dvibrowser/dvicore/special/ByteRangeSet.java new file mode 100644 index 0000000..6ff5b44 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/special/ByteRangeSet.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.special; + +import java.util.Comparator; +import java.util.SortedSet; +import java.util.TreeSet; + +import jp.sourceforge.dvibrowser.dvicore.DviByteRange; + + +public class ByteRangeSet +extends TreeSet +{ + private static final long serialVersionUID = -5733122326062424799L; + + public ByteRangeSet() + { + super( + new Comparator() { + public int compare(DviByteRange a, DviByteRange b) { + long _a = a.begin(); + long _b = b.begin(); + return (_a < _b) ? -1 + : (_a == _b) ? 0 + : 1; + } + } + ); + } + + public SortedSet intersect(DviByteRange range) + { + return subSet( + new DviByteRange(range.begin(), range.begin()), + new DviByteRange(range.end()+1, range.end()+1) + ); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/special/EPS2ImagePreparator.java b/src/jp/sourceforge/dvibrowser/dvicore/special/EPS2ImagePreparator.java new file mode 100644 index 0000000..2696c19 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/special/EPS2ImagePreparator.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.special; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.imageio.ImageIO; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviDocument; +import jp.sourceforge.dvibrowser.dvicore.api.DviPage; +import jp.sourceforge.dvibrowser.dvicore.api.HasURL; +import jp.sourceforge.dvibrowser.dvicore.ctx.DviToolkit; +import jp.sourceforge.dvibrowser.dvicore.gs.GhostscriptCommandBuilder; +import jp.sourceforge.dvibrowser.dvicore.gui.swing.ViewSpec; +import jp.sourceforge.dvibrowser.dvicore.image.split.DviImage; +import jp.sourceforge.dvibrowser.dvicore.util.CommandShell; +import jp.sourceforge.dvibrowser.dvicore.util.CommandShellHandler; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; +import jp.sourceforge.dvibrowser.dvicore.util.LineBuffer; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.Computation; + + +public class EPS2ImagePreparator +extends DviObject +implements Computation { + private static final Logger LOGGER = Logger + .getLogger(EPS2ImagePreparator.class.getName()); + + private final DviPage page; + private final ViewSpec viewSpec; + private final String postScriptData; + private final String hash; + + public EPS2ImagePreparator(DviContextSupport dcs, DviPage page, ViewSpec viewSpec) + throws DviException + { + super(dcs); + this.page = page; + this.viewSpec = viewSpec; + DviToolkit utils = getDviContext().getDviToolkit(); + this.postScriptData = utils.getEmbeddedPostScript(page, viewSpec); + this.hash = DviUtils.md5Hex(postScriptData); + } + + public DviImage call() throws Exception + { + if (postScriptData == null) return null; + + File dir = getDviContext().getTemporaryDirectory(); + String key = getCacheKey(); + String keyHash = DviUtils.md5Hex(key); + String basename = String.format("dvibrowser--%s--%08d", keyHash, page.getPageNumber()); + String imgExt = getViewSpec().getEpsImageFileExtension(); + File imgFile = new File(dir, basename + imgExt); + if (!imgFile.exists()) { + LOGGER.fine("Now creating postscript image for page " + page); + LOGGER.fine("Using key=" + key); + LOGGER.fine("Using keyHash=" + keyHash); + LOGGER.finer("PostScriptData= " + postScriptData); + File psFile = new File(dir, basename + ".ps"); + File tmpFile = File.createTempFile(basename, imgExt, dir); + try { + psFile.deleteOnExit(); + DviUtils.writeStringToFile(psFile, postScriptData); + GhostscriptCommandBuilder gs = new GhostscriptCommandBuilder(this); + gs.setInputFile(psFile); + gs.setOutputFile(tmpFile); + gs.setResolution(viewSpec.getEpsResolutionDpi()); + gs.setDevice(getViewSpec().getEpsImageDeviceName()); + CommandShell shell = gs.createCommandShell(); + // TODO: outsource the max line numbers to safe. + final LineBuffer stderr = new LineBuffer(100); + final LineBuffer stdout = new LineBuffer(100); + shell.setHandler(new CommandShellHandler() { + public void handleStderr(InputStream in) throws IOException { + DviUtils.accumulateToLineBuffer(in, stderr); + } + public void handleStdin(OutputStream out) throws IOException { + out.close(); + } + public void handleStdout(InputStream in) throws IOException { + DviUtils.accumulateToLineBuffer(in, stdout); + } + }); + int ret = shell.execute(); + if (ret == CommandShell.RETCODE_SUCCESS) { + if (!tmpFile.renameTo(imgFile)) { + throw new DviException("Failed to write image file: " + imgFile); + } + imgFile.deleteOnExit(); + LOGGER.fine("Saved image to " + imgFile); + } else { + LOGGER.warning("Ghostscript failed with retcode " + ret + "."); + LOGGER.warning("Ghosctscript stdout: " + stdout); + LOGGER.warning("Ghosctscript stderr: " + stderr); + } + } finally { + LOGGER.fine("Finished creating postscript image for page " + page); + if (DELETE_PSFILE_IMMEDIATELY) { + psFile.delete(); + } + tmpFile.delete(); + } + } + DviImage dviImage; + try { + BufferedImage image = ImageIO.read(imgFile); + dviImage = null; + if (image != null) { + dviImage = new DviImage(image, viewSpec.getEpsResolutionDpi()); + } + } catch (OutOfMemoryError e) { + LOGGER.severe("Unable to render image: imgFile=" + imgFile + " filesize=" + imgFile.length()); + DviUtils.logStackTrace(LOGGER, Level.SEVERE, e); + throw e; + } + + return dviImage; + } + + private static final boolean DELETE_PSFILE_IMMEDIATELY = false; + + public String getCacheKey() + { + // TODO: use viewSpec. + String pageKey = null; + try { + DviDocument doc = page.getDocument(); + if (doc instanceof HasURL) { + URL url = ((HasURL) doc).getURL(); + pageKey = url.toExternalForm() + "#page" + page.getPageNumber(); + } + } catch (DviException e) { + LOGGER.warning(e.toString()); + pageKey = page.getCacheKey(); + } + return getClass().getName() + "--" + hash + "-" + pageKey; + } + + public ViewSpec getViewSpec() + { + return viewSpec; + } + + public DviPage getPage() + { + return page; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/special/EPS2SplitImagePreparator.java b/src/jp/sourceforge/dvibrowser/dvicore/special/EPS2SplitImagePreparator.java new file mode 100644 index 0000000..c05a92f --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/special/EPS2SplitImagePreparator.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.special; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.DviSize; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviDocument; +import jp.sourceforge.dvibrowser.dvicore.api.DviPage; +import jp.sourceforge.dvibrowser.dvicore.api.HasURL; +import jp.sourceforge.dvibrowser.dvicore.ctx.DviToolkit; +import jp.sourceforge.dvibrowser.dvicore.gs.GhostscriptUtils; +import jp.sourceforge.dvibrowser.dvicore.gui.swing.ViewSpec; +import jp.sourceforge.dvibrowser.dvicore.image.split.ImageFileConfig; +import jp.sourceforge.dvibrowser.dvicore.image.split.SplitImage; +import jp.sourceforge.dvibrowser.dvicore.image.split.ZipSplitImageReader; +import jp.sourceforge.dvibrowser.dvicore.image.split.ZipSplitImageWriter; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; +import jp.sourceforge.dvibrowser.dvicore.util.ZipBuilder; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.Computation; + + +public class EPS2SplitImagePreparator +extends DviObject +implements Computation { + private static final Logger LOGGER = Logger + .getLogger(EPS2SplitImagePreparator.class.getName()); + + private final DviPage page; + private final ViewSpec viewSpec; + private final String postScriptData; + private final String hash; + + public EPS2SplitImagePreparator(DviContextSupport dcs, DviPage page, ViewSpec viewSpec) + throws DviException + { + super(dcs); + this.page = page; + this.viewSpec = viewSpec; + DviToolkit utils = getDviContext().getDviToolkit(); + this.postScriptData = utils.getEmbeddedPostScript(page, viewSpec); + this.hash = DviUtils.md5Hex(postScriptData); + } + + public SplitImage call() throws Exception + { + if (postScriptData == null) return null; + + File dir = getDviContext().getTemporaryDirectory(); + String key = getCacheKey(); + String keyHash = DviUtils.md5Hex(key); + String basename = String.format("gs--%s--%08d", keyHash, page.getPageNumber()); + String imgExt = ".zip"; + // TODO: outsource the resolution configuration. + DviResolution res = new DviResolution(400, 4); + DviSize unit = new DviSize(256, 256); + File imgFile = new File(dir, basename + imgExt); + imgFile.deleteOnExit(); + if (!imgFile.exists()) { + LOGGER.fine("Now creating postscript image for page " + page); + LOGGER.fine("Using key=" + key); + LOGGER.fine("Using keyHash=" + keyHash); + LOGGER.finer("PostScriptData= " + postScriptData); + try { + File tmpFile = File.createTempFile("gs-temp", null); + tmpFile.deleteOnExit(); + try { + final FileOutputStream fos = new FileOutputStream(tmpFile); + final ZipBuilder zb = new ZipBuilder(fos); + // TODO: outsource the encoding configuration. + final InputStream is = new ByteArrayInputStream(postScriptData.getBytes("UTF-8")); + try { + final ZipSplitImageWriter imageWriter = new ZipSplitImageWriter + (basename, ImageFileConfig.PNG, res, zb); + // Remark that Ghostscript counts pages from 1 not 0. + GhostscriptUtils.renderAndSplit(getDviContext(), is, unit, imageWriter, res, "pnmraw", 1, 0, null); + } finally { + DviUtils.silentClose(fos); + DviUtils.silentClose(is); + } + // TODO: lock before renaming to avoid race condition against other thread. + if (!tmpFile.renameTo(imgFile)) { + throw new DviException("Failed to create cache file: " + imgFile); + } + } finally { + tmpFile.delete(); + } + } catch (FileNotFoundException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + throw new DviException(e); + } catch (IOException e) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, e); + throw new DviException(e); + } + } + ZipSplitImageReader imageReader = new ZipSplitImageReader(imgFile); + return imageReader.getSplitImage(); + } + + public String getCacheKey() + { + // TODO: use viewSpec. + String pageKey = null; + try { + DviDocument doc = page.getDocument(); + if (doc instanceof HasURL) { + URL url = ((HasURL) doc).getURL(); + pageKey = url.toExternalForm() + "#page" + page.getPageNumber(); + } + } catch (DviException e) { + LOGGER.warning(e.toString()); + pageKey = page.getCacheKey(); + } + return getClass().getName() + "--" + hash + "-" + pageKey; + } + + public ViewSpec getViewSpec() + { + return viewSpec; + } + + public DviPage getPage() + { + return page; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/special/EmbeddedPostScript.java b/src/jp/sourceforge/dvibrowser/dvicore/special/EmbeddedPostScript.java new file mode 100644 index 0000000..053d94d --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/special/EmbeddedPostScript.java @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.special; + +import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.Vector; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviUnit; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + + +public class EmbeddedPostScript +{ +// private static final Logger LOGGER = Logger.getLogger(EmbeddedPostScript.class.getName()); + + private final Vector prologues = new Vector(); + private final Vector globals = new Vector(); + private final HashMap> page2locals + = new HashMap>(); + + private Vector locals = null; + + public void beginPage(int pageNum) + { + if (page2locals.containsKey(pageNum)) { + locals = page2locals.get(pageNum); + } else { + locals = new Vector(); + page2locals.put(pageNum, locals); + } + } + + public void endPage() + { + locals = null; + } + + public void add(Prologue a) + { + prologues.add(a); + } + + public void add(Global a) + { + globals.add(a); + } + + public void add(Local a) + { + locals.add(a); + } + + private static void writePostScript(Vector ce, + PrintWriter pw, Config cfg) throws DviException + { + for (Element e : ce) { + e.writePostScript(pw, cfg); + } + } + + public String toPostScript(int pageNum, int dpi) + throws DviException + { + if (!page2locals.containsKey(pageNum)) + return null; + + Vector ls = page2locals.get(pageNum); + + if (ls == null || ls.size() == 0) + return null; + + Config cfg = new Config(dpi); + + try { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + pw.println("%!PS-Adobe-2.0"); + pw.println("%%Pages: 1"); + pw.println("%%BoundingBox: 0 0 595 842"); // Change bounding box depending on paper sizes. + pw.println("%%EndComments"); + pw.println("%!"); + + writePostScript(prologues, pw, cfg); + + // TODO: Use the paper size to set the bounding boxes + pw.println( + "TeXDict begin" + + " 39158280 55380996 " + + " 1000 " + + dpi + " " + dpi + + " (a.dvi) " + + " @start end " + ); + pw.println("TeXDict begin 1 0 bop 0 0 a"); + + writePostScript(globals, pw, cfg); + + writePostScript(ls, pw, cfg); + + pw.println("end"); + pw.println("showpage"); + pw.close(); + sw.flush(); + return sw.toString(); + } catch (Exception ex) { + throw new DviException(ex); + } + } + + private static class Config + { + public final int dpi; + private Config(int dpi) { + this.dpi = dpi; + } + } + + private static interface Element + { + public abstract void writePostScript(PrintWriter pw, Config cfg) throws DviException; + } + + public static interface Local extends Element {} + public static interface Global extends Element {} + public static interface Prologue extends Element {} + + public static class ProloguePostScript + { + public final String postScript; + public ProloguePostScript(String postScript) { + this.postScript = postScript; + } + + public void writePostScript(PrintWriter pw, Config cfg) + { + pw.println(postScript); + } + } + + // TODO: support encoding. + private static String escapeFilenameForPS(String s) + { + return s.replaceAll("\\\\", "\\\\\\\\"); + } + + public static class PrologueFile + extends DviObject + implements Prologue + { + public final String fileName; + public PrologueFile(DviContextSupport dcs, String fileName) { + super(dcs); + this.fileName = fileName; + } + + public void writePostScript(PrintWriter pw, Config cfg) throws DviException + { + File file = DviUtils.toLocalFile(getDviContext().getDviResource(fileName)); + if (file == null || !file.exists()) + throw new DviException("Cannot find postscript prologue: " + fileName); + + String escapedFilename = escapeFilenameForPS(file.getAbsolutePath()); + pw.println( + " (" + escapedFilename + ") run" + ); + } + } + + public static class HeaderSpecial + implements Global + { + public final String fileName; + public HeaderSpecial(String fileName) { + this.fileName = fileName; + } + + public void writePostScript(PrintWriter pw, Config cfg) + { + String escapedFilename = escapeFilenameForPS(fileName); + pw.println( + " (" + escapedFilename + ") run" + ); + } + } + + public static class BangSpecial + implements Global + { + public final String postScript; + public BangSpecial(String postScript) { + this.postScript = postScript; + } + + public void writePostScript(PrintWriter pw, Config cfg) + { + pw.println( + " @defspecial " + postScript + " @fedspecial" + ); + } + } + + private static class WithReferencePoint + implements Local + { + public final int h; + public final int v; + public final DviUnit dviUnit; + private WithReferencePoint(int h, int v, DviUnit dviUnit) + { + this.h = h; + this.v = v; + this.dviUnit = dviUnit; + } + + public void writePostScript(PrintWriter pw, Config cfg) + { + double psH = dviUnit.mapToPixelDouble(h, cfg.dpi); + double psV = dviUnit.mapToPixelDouble(v, cfg.dpi); + pw.println( + " " + psH + " " + psV + " moveto " + ); + } + } + + public static class PSFileSpecial + extends WithReferencePoint + { + public final String fileName; + public final int llx; + public final int lly; + public final int urx; + public final int ury; + public final int rwi; + public final int rhi; + public final int angle; + public PSFileSpecial( + int h, int v, DviUnit dviUnit, + String fileName, + int llx, int lly, int urx, int ury, + int rwi, int rhi, int angle + ) { + super(h, v, dviUnit); + this.fileName = fileName; + this.llx = llx; + this.lly = lly; + this.urx = urx; + this.ury = ury; + this.rwi = rwi; + this.rhi = rhi; + this.angle = angle; + } + + public void writePostScript(PrintWriter pw, Config cfg) + { + super.writePostScript(pw, cfg); + String escapedFilename = escapeFilenameForPS(fileName); +// if (new File(realFile).exists()) { + pw.println( + " @beginspecial" + + " " + llx + " @llx" + + " " + lly + " @lly" + + " " + urx + " @urx" + + " " + ury + " @ury" + + ((rwi != 0) ? (" " + rwi + " @rwi") : "") + + ((rhi != 0) ? (" " + rhi + " @rhi") : "") + + ((angle != 0) ? (" " + angle + " @angle") : "") + + " @setspecial" + + " (" + escapedFilename + ") run" + + " @endspecial" + ); +// } else { +// } + } + } + + public static class PSSpecial + extends WithReferencePoint + { + public final String postScript; + public PSSpecial(int h, int v, DviUnit dviUnit, String postScript) + { + super(h, v, dviUnit); + this.postScript = postScript; + } + + public void writePostScript(PrintWriter pw, Config cfg) + { + super.writePostScript(pw, cfg); + pw.println( + " " + postScript + ); + } + } + + public static class QuoteSpecial + extends PSSpecial + { + public QuoteSpecial(int h, int v, DviUnit dviUnit, String postScript) + { + super(h, v, dviUnit, postScript); + } + + public void writePostScript(PrintWriter pw, Config cfg) + { + super.writePostScript(pw, cfg); + pw.println( + " @beginspecial" + + " @setspecial" + + " " + postScript + + " @endspecial" + ); + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/special/EmbeddedPostScriptPreparator.java b/src/jp/sourceforge/dvibrowser/dvicore/special/EmbeddedPostScriptPreparator.java new file mode 100644 index 0000000..31f208d --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/special/EmbeddedPostScriptPreparator.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.special; +import java.io.File; +import java.net.URL; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviResolution; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviDocument; +import jp.sourceforge.dvibrowser.dvicore.api.Geometer; +import jp.sourceforge.dvibrowser.dvicore.api.HasURL; +import jp.sourceforge.dvibrowser.dvicore.gui.swing.ViewSpec; +import jp.sourceforge.dvibrowser.dvicore.render.BasicGeometer; +import jp.sourceforge.dvibrowser.dvicore.render.EmptyBinaryDevice; +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; +import jp.sourceforge.dvibrowser.dvicore.util.concurrent.Computation; +import jp.sourceforge.dvibrowser.dvicore.util.progress.ProgressItem; + + +public class EmbeddedPostScriptPreparator +extends DviObject +implements Computation { + private static final Logger LOGGER = Logger.getLogger(EmbeddedPostScriptPreparator.class + .getName()); + private final DviDocument doc; + private final ViewSpec viewSpec; + + public EmbeddedPostScriptPreparator(DviContextSupport dcs, DviDocument doc, ViewSpec viewSpec) + { + super(dcs); + this.doc = doc; + this.viewSpec = viewSpec; + } + + public EmbeddedPostScript call() throws Exception + { + if (doc == null) return null; + final ProgressItem progress = getDviContext().getProgressRecorder().open("extracting EPS data"); + try { + PostScriptSpecialParser pse = new PostScriptSpecialParser(this); + if (doc instanceof HasURL) { + URL url = ((HasURL) doc).getURL(); + if (DviUtils.isFile(url)) { + File file = new File(url.getPath()); + File dir = file.getParentFile(); + LOGGER.finer("working dir=" + dir); + pse.setWorkDirectory(dir); + } else { + LOGGER.finer("Using default working dir"); + } + } else { + LOGGER.finer("No URL is available for doc " + doc); + } + pse.getEmbeddedPostScript().add( + new EmbeddedPostScript.PrologueFile(this, "texc.pro")); + pse.getEmbeddedPostScript().add( + new EmbeddedPostScript.PrologueFile(this, "special.pro")); + // This is a dummy output. + // Should we change this to use viewSpec instead? + pse.setOutput(new EmptyBinaryDevice(new DviResolution(600, 4))); + + Geometer gm = new BasicGeometer(this); + gm.setPainter(pse); + getDviContext().execute(doc, gm); + EmbeddedPostScript eps = pse.getEmbeddedPostScript(); + return eps; + } finally { + progress.close(); + } + } + + public String getCacheKey() + { + return "EPS--" + doc.getCacheKey(); + } + + public DviDocument getDocument() + { + return doc; + } + + public ViewSpec getViewSpec() + { + return viewSpec; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/special/HtmlSpecialParser.java b/src/jp/sourceforge/dvibrowser/dvicore/special/HtmlSpecialParser.java new file mode 100644 index 0000000..93f031c --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/special/HtmlSpecialParser.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.special; + +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviDocument; + + +// TODO: support Logging +public class HtmlSpecialParser +extends DviObject +{ + private final AnchorSet anchorSet = new AnchorSet(); + private final PrivateExecuter exe; + + public HtmlSpecialParser(DviContextSupport dcs) + { + super(dcs); + exe = new PrivateExecuter(dcs, anchorSet); + } + + private static final Pattern hrefPat + = Pattern.compile( + "\\s*html:\\s*", + Pattern.CASE_INSENSITIVE + ); + private static final Pattern namePat + = Pattern.compile( + "\\s*html:\\s*", + Pattern.CASE_INSENSITIVE + ); + private static final Pattern endPat + = Pattern.compile( + "\\s*html:\\s*", + Pattern.CASE_INSENSITIVE + ); + + public void execute(DviDocument doc) + throws DviException + { + for (int p=0; p stack + = new Stack(); + + public void doSpecial(byte [] _xxx) + throws DviException + { + String xxx = new String(_xxx); + Matcher mat; + DviExecutorContextImpl ctx = getExecutorContext(); + if ((mat = hrefPat.matcher(xxx)).matches()) { + stack.push( + new StackItem( + ctx.getCommandRange().begin(), + "href", + mat.group(1) + ) + ); + } else if ((mat = namePat.matcher(xxx)).matches()) { + stack.push( + new StackItem( + ctx.getCommandRange().begin(), + "name", + mat.group(1) + ) + ); + } else if ((mat = endPat.matcher(xxx)).matches()) { + Anchor el = null; + if (!stack.empty()) { + StackItem it = stack.pop(); + if ("href".equals(it.tag)) { + el = new Anchor.Href( + it.start, + ctx.getCommandRange().end(), + it.data + ); + } else if ("name".equals(it.tag)) { + el = new Anchor.Name( + it.start, + ctx.getCommandRange().end(), + it.data + ); + } + } else { + // TODO: logging +// System.out.println("html tag stack underflow."); + // This is an error. We ignore it. + } + if (el != null) { + anchorSet.add(el); + } + } + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/special/PostScriptSpecialParser.java b/src/jp/sourceforge/dvibrowser/dvicore/special/PostScriptSpecialParser.java new file mode 100644 index 0000000..137a7e9 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/special/PostScriptSpecialParser.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.special; + +import java.io.File; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.DviRegister; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviBop; +import jp.sourceforge.dvibrowser.dvicore.render.DefaultDevicePainter; + + +public class PostScriptSpecialParser +extends DefaultDevicePainter +{ + private static final Logger LOGGER = Logger.getLogger(PostScriptSpecialParser.class.getName()); + + private static final Pattern patPS + = Pattern.compile( + "\\s*ps:\\s*(.*)", + Pattern.CASE_INSENSITIVE + ); + private static final Pattern patHeader + = Pattern.compile( + "\\s*header\\s*=\\s*(.*)", + Pattern.CASE_INSENSITIVE + ); + private static final Pattern patPSFile + = Pattern.compile( + "\\s*PSFile\\s*=\\s*([^\\s]*)\\s+(.*)\\s*", + Pattern.CASE_INSENSITIVE + ); + + public PostScriptSpecialParser(DviContextSupport dcs) + { + super(dcs); + } + + private File workDir; + public void setWorkDirectory(File dir) + { + this.workDir = dir; + } + public File getWorkDirectory() + { + return workDir; + } + + private final EmbeddedPostScript eps = new EmbeddedPostScript(); + + public EmbeddedPostScript getEmbeddedPostScript() + { + return eps; + } + + private int pageNum = 0; + + public void beginPage(DviBop bop) + { + eps.beginPage(pageNum); + } + + public void endPage() + { + eps.endPage(); + pageNum++; + } + + public void beginFont(DviFontSpec fs) + { + } + + public void endFont() + { + } + + //////////// + + public void drawChar(int code) + { + // ignored. + } + + public void drawRule(int w, int h) + { + // ignored. + } + + protected String toAbsoluteFilename(String filename) + { + File file = new File(workDir, filename); + LOGGER.finer("Resolved filename=" + filename + " to " + file.getAbsolutePath()); + return file.getAbsolutePath(); + } + + public void drawSpecial(byte [] _xxx) + { + String xxx = new String(_xxx); + Matcher mat; + + LOGGER.finer("handling special: " + xxx); + if (xxx.startsWith("\"")) { + DviRegister reg = getGeometerContext().getRegister(); + eps.add( + new EmbeddedPostScript.QuoteSpecial( + reg.getH(), reg.getV(), + getDviUnit(), + xxx.substring(1).trim() + ) + ); + } else if (xxx.startsWith("!")) { + eps.add( + new EmbeddedPostScript.BangSpecial( + xxx.substring(1).trim() + ) + ); + } else if ((mat = patPS.matcher(xxx)).matches()) { + DviRegister reg = getGeometerContext().getRegister(); + eps.add( + new EmbeddedPostScript.PSSpecial( + reg.getH(), reg.getV(), + getDviUnit(), + mat.group(1) + ) + ); + } else if ((mat = patHeader.matcher(xxx)).matches()) { + LOGGER.finer("PSHeader special found: " + xxx); + eps.add( + new EmbeddedPostScript.HeaderSpecial( + trimQuotes(mat.group(1)) + ) + ); + } else if ((mat = patPSFile.matcher(xxx)).matches()) { + LOGGER.finer("page=" + pageNum + " PSFile special found: " + xxx); + String fileName = toAbsoluteFilename(trimQuotes(mat.group(1))); + String options = mat.group(2); + int llx = 0; + int lly = 0; + int urx = 0; + int ury = 0; + int rwi = 0; + int rhi = 0; + int angle = 0; + String [] os = Pattern.compile("\\s+").split(options); + for (int i=0; i stack + = new Stack(); + + @Override + public void end() throws DviException { + flushStack(); + super.end(); + } + + private void flushStack() + { + if (!stack.empty()) { + StackItem it = stack.pop(); + DviExecutorContextImpl ctx = getExecutorContext(); + Anchor a = null; + if ("src".equals(it.tag)) { + a = new Anchor.Source( + it.start, + ctx.getCommandRange().end(), + it.data, + it.lineNumber + ); + } + anchorSet.add(a); + } + } + + @Override + public void doSpecial(byte [] _xxx) + throws DviException + { + String xxx = new String(_xxx); + Matcher mat; + DviExecutorContextImpl ctx = getExecutorContext(); + if ((mat = srcPat.matcher(xxx)).matches()) { + flushStack(); + try { + stack.push( + new StackItem( + ctx.getCommandRange().begin(), + "src", + mat.group(2), // filename + Integer.parseInt(mat.group(1)) // linenumber + ) + ); + } catch (NumberFormatException e) { + LOGGER.warning(e.getMessage()); + } + } + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/Benchmark.java b/src/jp/sourceforge/dvibrowser/dvicore/util/Benchmark.java new file mode 100644 index 0000000..eeeed95 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/Benchmark.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util; + +import java.text.MessageFormat; + +public class Benchmark { + private boolean active = false; + private long start = 0; + private long end = 0; + private long lapsed = 0; + private long samples = 0; + private String name; + + public void begin(String name) + { + reset(); + start = getCurrentTime(); + this.name = name; + active = true; + } + + public void reset() + { + start = 0; + end = 0; + lapsed = 0; + samples = 0; + name = null; + active = false; + } + + public void addSample() + { + addSamples(1); + } + + public void addSamples(int count) + { + samples += count; + } + + public void end() + { + if (active) { + end = getCurrentTime(); + lapsed = end - start; + active = false; + } + } + + public long getCurrentTime() + { + return System.currentTimeMillis(); + } + + public long getLapsedTime() + { + if (active) { + long now = getCurrentTime(); + return now - start; + } else { + return lapsed; + } + } + + public long getSamples() + { + return samples; + } + + public double samplesPerSecond(long samples, long lapsed) + { + return (double) samples * 1000 / lapsed; + } + + public String format(String fmt) + { + long samples = getSamples(); + long lapsed = getLapsedTime(); + return MessageFormat.format( + fmt, + samples, + (double) lapsed / 1000, + samplesPerSecond(samples, lapsed), + 1./samplesPerSecond(samples, lapsed) * 1000 + ); + } + + public String format() + { + return format("Benchmark result: " + name + ": " + + "{0,number} samples in {1,number} sec." + + " {2,number} samples/sec. " + + " {3,number,##.###} msec./sample."); + } + + public String toString() + { + return format(); + } + + public long getStartTime() { + return start; + } + + public long getEndTime() { + return end; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/BufferFilter.java b/src/jp/sourceforge/dvibrowser/dvicore/util/BufferFilter.java new file mode 100644 index 0000000..e2f7e51 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/BufferFilter.java @@ -0,0 +1,155 @@ +package jp.sourceforge.dvibrowser.dvicore.util; +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class BufferFilter +extends InputStream +{ + protected ByteArrayInputStream byteArrayInput; + private InputStream input; + private final int bufferSize; + private byte [] buffer; + private int len; + + public BufferFilter(int bufferSize) { + this.byteArrayInput = null; + this.input = null; + this.bufferSize = bufferSize; + this.buffer = null; + this.len = 0; + } + + public synchronized void beginInput(InputStream in) throws IOException + { + input = in; + } + + public synchronized void endInput() throws IOException + { + input = null; + } + + protected synchronized void fill() throws IOException + { + if (input == null) { + throw new IllegalStateException("Input read before beginInput() is called."); + } + if (byteArrayInput != null && byteArrayInput.available() > 0) { + return; + } + + byteArrayInput = fillBuffer(); + } + + protected synchronized ByteArrayInputStream fillBuffer() throws IOException + { + byte [] buf = new byte [bufferSize]; + + int len = input.read(buf); + if (-1 == len) { + throw new IOException("EOF found while reading input."); + } + if (0 == len) { + throw new IOException("Read failed."); + } + + this.len = len; + this.buffer = buf; + + return new ByteArrayInputStream(buf, 0, len); + } + + public synchronized byte [] getBuffer() + { + if (buffer == null) return new byte[0]; + byte [] ret = new byte[len]; + System.arraycopy(buffer, 0, ret, 0, len); + return ret; + } + + @Override + public synchronized int available() throws IOException + { + fill(); + return byteArrayInput.available(); + } + + @Override + public synchronized void close() throws IOException + { + input.close(); + } + + @Override + public void mark(int readLimit) + { + throw new UnsupportedOperationException("mark is not supported"); + } + + @Override + public void reset() + { + throw new UnsupportedOperationException("reset is not supported"); + } + + @Override + public boolean markSupported() + { + return false; + } + + @Override + public synchronized int read() throws IOException + { + fill(); + return byteArrayInput.read(); + } + + @Override + public synchronized int read(byte [] buf, int off, int len) throws IOException + { + fill(); + return byteArrayInput.read(buf, off, len); + } + + public synchronized InputStream getInput() { + return input; + } + + public int getBufferSize() { + return bufferSize; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/Canonicalizer.java b/src/jp/sourceforge/dvibrowser/dvicore/util/Canonicalizer.java new file mode 100644 index 0000000..59d43a9 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/Canonicalizer.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util; + +public abstract interface Canonicalizer +{ + public T canonicalize(T obj); +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/CommandShell.java b/src/jp/sourceforge/dvibrowser/dvicore/util/CommandShell.java new file mode 100644 index 0000000..e48f938 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/CommandShell.java @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviException; + + +public class CommandShell +{ + public static final int RETCODE_SUCCESS = 0; + + private final ScheduledExecutorService exe = Executors.newSingleThreadScheduledExecutor + (new DaemonThreadFactory()); + + private static final Logger LOGGER = Logger.getLogger(CommandShell.class.getName()); + private ArrayList commandLine = new ArrayList(); + + public void setCommandLine(String ... commandLine) + { + ArrayList list = new ArrayList(); + for (String arg : commandLine) { + list.add(arg); + } + this.commandLine = list; + } + + public void setCommandLine(Collection cmdLine) + { + ArrayList list = new ArrayList(); + list.addAll(cmdLine); + this.commandLine = list; + } + + public Collection getCommandLine() + { + return Collections.unmodifiableCollection(commandLine); + } + + private ArrayList envs = null; + public void setEnvironment(Collection envs) + { + if (envs == null) { + this.envs = null; + return; + } else { + ArrayList list = new ArrayList(); + list.addAll(envs); + this.envs = list; + } + } + + public void setEnvironment(String ... envs) + { + ArrayList list = new ArrayList(); + for (String arg : envs) { + list.add(arg); + } + this.envs = list; + } + + public Collection getEnvironment() + { + if (envs == null) return null; + return Collections.unmodifiableCollection(envs); + } + + private File dir = null; + public void setWorkingDirectory(File dir) + { + this.dir = dir; + } + + public File getWorkingDirectory() + { + return dir; + } + + private TimeUnit timeUnit; + private long timeout = 0; + public void setTimeout(long timeout, TimeUnit timeUnit) + { + if (timeout < 0) { + throw new IllegalArgumentException("timeout is negative"); + } + this.timeout = timeout; + this.timeUnit = timeUnit; + } + + private CommandShellHandler handler = null; + public void setHandler(CommandShellHandler handler) + { + this.handler = handler; + } + + public CommandShellHandler getHandler() + { + return handler; + } + + protected void checkVars() + { + if (commandLine == null) + throw new IllegalArgumentException + ("commandLine can't be null"); + if (commandLine.size() < 1) + throw new IllegalArgumentException + ("commandLine can't be empty"); + } + + private volatile Process p = null; + private Thread stdoutThread = null; + private Thread stderrThread = null; + private Thread stdinThread = null; + private volatile Throwable stdoutThrowable = null; + private volatile Throwable stderrThrowable = null; + private volatile Throwable stdinThrowable = null; + + public int execute() + throws IOException, InterruptedException, DviException + { + int result = -1; + + p = null; + checkVars(); + + try { + final String commandLineStr = DviUtils.join(" ", commandLine); + LOGGER.fine("Running command: " + commandLineStr); + p = Runtime.getRuntime().exec( + commandLine.toArray(new String[commandLine.size()]), + getEnvironmentAsArray(), dir); + processStreams(); + ScheduledFuture future = null; + if (timeUnit != null && timeout > 0) { + LOGGER.fine("Starting timer: timeout=" + timeout + " timeUnit=" + timeUnit); + future = exe.schedule(new Runnable() { + public void run() { + LOGGER.warning("Command timed out: " + commandLineStr); + p.destroy(); + } + }, timeout, timeUnit); + } + LOGGER.fine("waiting for the process to terminate."); + result = p.waitFor(); + LOGGER.fine("process exit with retcode " + result); + if (future != null) { + future.cancel(false); + } + } catch (InterruptedException ex) { + if (p != null) { + p.destroy(); + } + throw ex; + } catch (IOException ex) { + if (p != null) { + p.destroy(); + } + throw ex; + } finally { + reapThread(stderrThread, "stderr"); + stderrThread = null; + reapThread(stdoutThread, "stdout"); + stdoutThread = null; + reapThread(stdinThread, "stdin"); + stdinThread = null; + + if (p != null) { + DviUtils.silentClose(p.getErrorStream()); + DviUtils.silentClose(p.getInputStream()); + DviUtils.silentClose(p.getOutputStream()); + } + } + + if (stdinThrowable != null) { + throw new DviException(stdinThrowable); + } + if (stdoutThrowable != null) { + throw new DviException(stdoutThrowable); + } + if (stderrThrowable != null) { + throw new DviException(stderrThrowable); + } + + p = null; + + return result; + } + + private String[] getEnvironmentAsArray() { + if (envs == null) return null; + return envs.toArray(new String[envs.size()]); + } + + private void reapThread(Thread thread, String name) + { + try { + LOGGER.fine("waiting for the " + name + " thread"); + if (thread != null) + thread.join(); + } catch (InterruptedException ex) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, ex); + } + } + + protected void processStreams() + throws IOException + { + if (handler != null) { + stdinThread = new Thread(new Runnable() { + public void run() { + OutputStream os = p.getOutputStream(); + try { + handler.handleStdin(os); + } catch (Throwable ex) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, ex); + stdinThrowable = ex; + p.destroy(); + } finally { + DviUtils.silentClose(os); + } + } + }); + stderrThread = new Thread(new Runnable() { + public void run() { + InputStream is = p.getErrorStream(); + try { + handler.handleStderr(is); + } catch (Throwable ex) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, ex); + stderrThrowable = ex; + p.destroy(); + } finally { + DviUtils.silentClose(is); + } + } + }); + stdoutThread = new Thread(new Runnable() { + public void run() { + InputStream is = p.getInputStream(); + try { + handler.handleStdout(is); + } catch (Throwable ex) { + DviUtils.logStackTrace(LOGGER, Level.WARNING, ex); + stdoutThrowable = ex; + p.destroy(); + } finally { + DviUtils.silentClose(is); + } + } + }); + + stdinThread .start(); + stderrThread.start(); + stdoutThread.start(); + } else { + DviUtils.silentClose(p.getOutputStream()); + DviUtils.silentClose(p.getInputStream()); + DviUtils.silentClose(p.getErrorStream()); + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/CommandShellHandler.java b/src/jp/sourceforge/dvibrowser/dvicore/util/CommandShellHandler.java new file mode 100644 index 0000000..507b4d3 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/CommandShellHandler.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import jp.sourceforge.dvibrowser.dvicore.DviException; + +public interface CommandShellHandler +{ + public void handleStdin(OutputStream out) throws IOException, DviException; + public void handleStdout(InputStream in) throws IOException, DviException; + public void handleStderr(InputStream in) throws IOException, DviException; +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/DaemonThreadFactory.java b/src/jp/sourceforge/dvibrowser/dvicore/util/DaemonThreadFactory.java new file mode 100644 index 0000000..843be23 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/DaemonThreadFactory.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util; + +import java.util.concurrent.ThreadFactory; + +public class DaemonThreadFactory +implements ThreadFactory +{ + public DaemonThreadFactory() + { + this(Thread.NORM_PRIORITY); + } + + private final int priority; + public DaemonThreadFactory(int priority) + { + this.priority = priority; + } + + public Thread newThread(Runnable r) + { + Thread t = new Thread(r); + t.setPriority(priority); + t.setDaemon(true); + return t; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/DefaultCommandShellHandler.java b/src/jp/sourceforge/dvibrowser/dvicore/util/DefaultCommandShellHandler.java new file mode 100644 index 0000000..e48bc9f --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/DefaultCommandShellHandler.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; +public class DefaultCommandShellHandler implements CommandShellHandler { +// private static final Logger LOGGER = Logger +// .getLogger(CommandShellHandler.class.getName()); + + private final LineBuffer stderr = new LineBuffer(100); + private final LineBuffer stdout = new LineBuffer(100); + + public void handleStderr(InputStream in) throws IOException { + DviUtils.accumulateToLineBuffer(in, stderr); + } + + public void handleStdin(OutputStream out) throws IOException { + out.close(); + } + + public void handleStdout(InputStream in) throws IOException { + DviUtils.accumulateToLineBuffer(in, stdout); + } + + public List getStderr() { + return stderr.toList(); + } + + public List getStdout() { + return stdout.toList(); + } + + +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/DumpCommandShellHandler.java b/src/jp/sourceforge/dvibrowser/dvicore/util/DumpCommandShellHandler.java new file mode 100644 index 0000000..edb0fee --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/DumpCommandShellHandler.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintStream; +public class DumpCommandShellHandler +implements CommandShellHandler +{ + private final PrintStream out; + + public DumpCommandShellHandler(PrintStream out) + { + this.out = out; + } + + public void handleStdout(InputStream in) throws IOException + { + dumpStream("stdout", in); + } + public void handleStderr(InputStream in) throws IOException + { + dumpStream("stderr", in); + } + + private void dumpStream(String prefix, InputStream in) + throws IOException + { + BufferedReader r = new BufferedReader + (new InputStreamReader(in)); + String line; + while (null != (line = r.readLine())) { + out.println("[" + prefix + "] " + line); + } + } + + public void handleStdin(OutputStream out) throws IOException { + out.close(); + } +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/DviCache.java b/src/jp/sourceforge/dvibrowser/dvicore/util/DviCache.java new file mode 100644 index 0000000..a003d19 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/DviCache.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.logging.Logger; + +public class DviCache +extends LinkedHashMap +{ + private static final Logger LOGGER = Logger.getLogger(DviCache.class.getName()); + private static final long serialVersionUID = -2767494208998923925L; + + private int cacheSize; + + public DviCache(int cacheSize) { + this.cacheSize = cacheSize; + } + + public DviCache() { this(128); } + + @Override + protected boolean removeEldestEntry(Map.Entry entry) + { + if (size() > cacheSize) { + LOGGER.finer("purge: key=" + entry.getKey() + " value=" + entry.getValue()); + return true; + } + return false; + } + + public int getCacheSize() + { + return cacheSize; + } + + public void setCacheSize(int cacheSize) + { + this.cacheSize = cacheSize; + } +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/DviDesktop.java b/src/jp/sourceforge/dvibrowser/dvicore/util/DviDesktop.java new file mode 100644 index 0000000..4f23541 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/DviDesktop.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URI; +import java.util.logging.Logger; + +public class DviDesktop { + private static final Logger LOGGER = Logger.getLogger(DviDesktop.class + .getName()); + + private static final DviDesktop instance = new DviDesktop(); + + private DviDesktop() + { + } + + public static DviDesktop getDesktop() + { + return instance; + } + + public static boolean isDesktopSupported() + { + if (DviUtils.isMacOSX()) { + return true; + } else if (DviUtils.isWindows()) { + return true; + } else { + return false; + } + } + + public void browse(URI uri) + throws IOException + { + throw new UnsupportedOperationException(); + } + + public void open(File file) + throws IOException + { + if (DviUtils.isMacOSX()) { + try { + Class cls = Class.forName("com.apple.eio.FileManager"); + Method openURL = cls.getDeclaredMethod("openURL", + new Class[] { String.class }); + openURL.invoke(null, new Object[] { file.toURL().toExternalForm() }); + } catch (SecurityException e) { + LOGGER.warning(e.toString()); + } catch (IllegalArgumentException e) { + LOGGER.warning(e.toString()); + } catch (ClassNotFoundException e) { + LOGGER.warning(e.toString()); + } catch (NoSuchMethodException e) { + LOGGER.warning(e.toString()); + } catch (IllegalAccessException e) { + LOGGER.warning(e.toString()); + } catch (InvocationTargetException e) { + LOGGER.warning(e.toString()); + } + } else if (DviUtils.isWindows()) { + String[] commandLine = { "cmd.exe", "/c", "start", file.getAbsolutePath() }; + try { + Process p = Runtime.getRuntime().exec(commandLine, null, null); + int ret = p.waitFor(); + LOGGER.fine("Process exit with retcode: " + ret); + } catch (InterruptedException e) { + LOGGER.warning(e.toString()); + } + } else { + LOGGER.severe("This platform does not support file association."); + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/DviInfoDumper.java b/src/jp/sourceforge/dvibrowser/dvicore/util/DviInfoDumper.java new file mode 100644 index 0000000..471fdd6 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/DviInfoDumper.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jp.sourceforge.dvibrowser.dvicore.DviException; + + +// TODO: Find out what the purpose of this class is. +public class DviInfoDumper +{ + private final Config conf; + + public DviInfoDumper(Config conf) + { + this.conf = conf; + } + + public void execute() + throws DviException + { + try { + System.out.printf("mode=%s\n", this.conf.mode); + for (String a : this.conf.plainArgs) { + System.out.printf("arg: %s\n", a); + } +// } catch (DviException ex) { +// throw ex; + } catch (Exception ex) { + throw new DviException(ex); + } + } + + public static class ArgumentList + extends LinkedList + { + private static final long serialVersionUID = -9222800531977990881L; + + public ArgumentList(String [] args) + { + for (String a : args) add(a); + } + + public String next() + { + if (size() == 0) return null; + + return removeFirst(); + } + } + + @SuppressWarnings("unused") + public static class Option + { + private final String longOpt; + private final String shortOpt; + private final int numArgs; + private final String var; + private final String description; + + public Option(String longOpt, String shortOpt, + String var, String description) + { + this.longOpt = longOpt; + this.shortOpt = shortOpt; + this.var = var; + this.numArgs = (var != null) ? 1 : 0; + this.description = description; + } + } + + public static class Config + { + private String mode = "help"; + private ArrayList plainArgs + = new ArrayList(); + + private static Option [] options = { + new Option("--help", "-h", null, "Show this help"), + new Option("--mode", "-m", "mode", "Set mode to ") + }; + + public Config() + { + } + + public void setMode(String mode) + { + this.mode = mode.toLowerCase(); + } + + public void addPlainArgument(String a) + { + plainArgs.add(a); + } + + private static final Pattern patShortOption + = Pattern.compile("^(-[0-9a-zA-Z])(.*)$"); + private static final Pattern patLongOption + = Pattern.compile("^(--[a-zA-Z][a-zA-Z0-9]*)(=(.*))?$"); + + public static Config parseCommandLine(String [] args) + throws DviException + { + ArgumentList al = new ArgumentList(args); + Config conf = new Config(); + String a; + while (null != (a = al.next())) { + if (a.startsWith("-")) { + Matcher mat; + boolean handled = false; + + if ((mat = patLongOption.matcher(a)).find()) { + String a2 = mat.group(1); + String v = mat.group(3); + System.out.println("found long option: " + a2 + "=>" + v); + for (Option opt : options) { + if (a2.equals(opt.longOpt)) { + handled = true; + if (opt.numArgs > 0) { + if (v == null) + throw new DviException + ("no value for option `" + a2 + "'"); + } else { + if (v != null) + throw new DviException + ("option `" + a2 + "' does not take argument"); + } + break; + } + } + } else if ((mat = patShortOption.matcher(a)).find()) { + String a2 = mat.group(1); + String v = mat.group(3); + System.out.println("found short option: " + a2 + "=>" + v); + for (Option opt : options) { + if (a.equals(opt.shortOpt)) { + handled = true; + break; + } + } + } + + if (!handled) { + throw new DviException + ("unrecognized option: " + a); + } + } else { + conf.addPlainArgument(a); + } + } + return conf; + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/DviUtils.java b/src/jp/sourceforge/dvibrowser/dvicore/util/DviUtils.java new file mode 100644 index 0000000..b5266df --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/DviUtils.java @@ -0,0 +1,557 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util; +import java.io.Closeable; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.URL; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Scanner; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.zip.CRC32; + +import jp.sourceforge.dvibrowser.dvicore.DviException; + + +public class DviUtils { + private static final Logger LOGGER = Logger.getLogger(DviUtils.class + .getName()); + private static final String OS_NAME = System.getProperty("os.name"); + + private static final UUID applicationInstanceUUID = UUID.randomUUID(); + private static final AtomicLong serializer = new AtomicLong(); + + public static long generateSerialNumber() + { + return serializer.incrementAndGet(); + } + + public static UUID getApplicationInstanceUUID() + { + return applicationInstanceUUID; + } + + public static String generateUniqueId() + { + String uniqueId = getApplicationInstanceUUID().toString() + "--" + generateSerialNumber(); + return uniqueId; + } + + private DviUtils() {} + + public static boolean isFile(URL url) + { + if (url == null) return false; + return "file".equals(url.getProtocol()); + } + + public static void writeStringToFile(File file, String data) + throws IOException + { + FileOutputStream fos = null; + try { + fos = new FileOutputStream(file); + // TODO: support encodings + byte[] buf = data.getBytes(); + fos.write(buf); + } finally { + if (fos != null) { + fos.flush(); + silentClose(fos); + } + } + } + + public static File toLocalFile(URL url) + throws DviException + { + if (url == null) return null; + if ("file".equals(url.getProtocol())) { + return new File(url.getPath()); + } else { + throw new DviException("URL does not point to a local file. " + url); + } + } + + public static String md5Hex(String ps) + { + if (ps == null) return null; + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + // TODO: support character encodings. + byte[] digest = md.digest(ps.getBytes()); + StringBuilder sb = new StringBuilder(); + for (byte b : digest) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return "0"; + } + + private static final Pattern patEnv = Pattern.compile("^([^=]*)=(.*)$"); + + public static Map getLoginShellEnvPosix() throws IOException, InterruptedException + { + return getLoginShellEnvPosix(null); + } + + public static Map getLoginShellEnvPosix(String shell) + throws IOException, InterruptedException { + String[] cmds = new String[] { "printenv" }; + if (shell != null) { + cmds = new String[] { shell, "-l", "-c", "printenv" }; + } + + final Process proc = Runtime.getRuntime().exec(cmds); + final Map map = new HashMap(); + final InputStream is = proc.getInputStream(); + proc.getOutputStream().close(); + proc.getErrorStream().close(); + { + Scanner s = new Scanner(proc.getInputStream()); + try { + while (s.hasNext()) { + String line = s.nextLine(); + Matcher mat = patEnv.matcher(line); + if (mat.matches()) { + String key = mat.group(1); + String value = mat.group(2); + LOGGER.finest("key=" + key + " value=" + value); + map.put(key, value); + } + } + } finally { + DviUtils.silentClose(is); + } + } + proc.waitFor(); + return map; + } + + public static String getPathByLoginShellPosix() throws IOException, InterruptedException + { + String path = null; + + // We first determine the user's shell. + Map env0 = getLoginShellEnvPosix(null); + String shell = env0.get("SHELL"); + if (shell != null) { + // We then read the PATH environment variable through the login shell. + Map env1 = getLoginShellEnvPosix(shell); + path = env1.get("PATH"); + } + + return path; + } + + public static String join(String left, String mid, String right, Object [] arg) + { + if (arg == null) return null; + StringBuilder sb = new StringBuilder(); + left = wrapNull(left, ""); + mid = wrapNull(mid, ""); + right = wrapNull(right, ""); + String sep = left; + for (Object o : arg) { + sb.append(sep + String.valueOf(o)); + sep = mid; + } + sb.append(right); + return sb.toString(); + } + + public static String join(String sep, Object [] args) + { + return join(null, sep, null, args); + } + + public static T wrapNull(T value, T defaultValue) { + if (value == null) return defaultValue; + return value; + } + + // This method is unsafe because we don't escape the command line arguments. Use it with care. + public static Process unsafeRunCommandByShell(String[] cmds, String[] envp, File workDir) + throws IOException + { + Process p = null; + if (!isWindows()) { + try { + Map env = getLoginShellEnvPosix(); + String shell = env.get("SHELL"); + if (shell != null) { + p = unsafeRunCommandByShellPosix(shell, true, cmds, envp, workDir); + } + } catch (InterruptedException e) { + LOGGER.warning(e.toString()); + } + } + if (p == null) { + p = Runtime.getRuntime().exec(cmds, envp, workDir); + } + return p; + } + + // This method is unsafe because we don't escape the command line arguments. Use it with care. + public static Process unsafeRunCommandByShellPosix(String shell, + boolean useLoginShell, String[] cmds, String[] envp, File workDir) + throws IOException + { + ArrayList list = new ArrayList(); + list.add(shell); + if (useLoginShell) { + list.add("-l"); + } + + String[] cmdLine = list.toArray(new String[list.size()]); + + StringBuilder subCommand = new StringBuilder(); + for (String cmd : cmds) { + subCommand.append(cmd + " "); + } + + LOGGER.fine("running shell: " + join(" ", cmdLine)); + LOGGER.fine("running command: " + subCommand.toString()); + + Process proc = Runtime.getRuntime().exec(cmdLine, envp, workDir); + + PrintWriter out = new PrintWriter(proc.getOutputStream()); + out.println(subCommand.toString()); + out.close(); + + return proc; + } + + public static Thread dumpStreamAsync(final String name, final InputStream is, + final PrintStream out) { + Thread t = new Thread(new Runnable() { + public void run() { + Scanner s = new Scanner(is); + try { + while (s.hasNext()) { + String line = s.nextLine(); + if (out != null) { + out.println("[" + name + "] " + line); + } + if (LOGGER.isLoggable(Level.FINER)) { + LOGGER.finer("[" + name + "] " + line); + } + } + } finally { + try { + s.close(); + } catch (Exception e) { + } + } + + } + }); + t.start(); + return t; + } + + public static T head(T[] array) { + if (array == null || array.length == 0) return null; + return array[0]; + } + + public static void logLinesFromStream(final String name, final InputStream is, + final Logger logger, final Level level) { + if (logger == null || !logger.isLoggable(level)) + return; + Scanner s = new Scanner(is); + while (s.hasNext()) { + String line = s.nextLine(); + LOGGER.log(level, "[" + name + "] " + line); + } + } + + public static void addLinesFromStream(final List output, final InputStream is) { + addLinesFromStream(output, is, null, Level.SEVERE, null); + } + + public static void addLinesFromStream(final List output, final InputStream is, final Logger logger, final Level level, final PrintStream out) { + if (output == null) return; + Scanner s = new Scanner(is); + while (s.hasNext()) { + String line = s.nextLine(); + output.add(line); + if (logger != null && logger.isLoggable(level)) { + logger.log(level, line); + } + if (out != null) { + out.println(line); + out.flush(); + } + } + } + + + public static Thread dumpStreamAsync(final String name, final InputStream is, + final Logger logger, final Level level) { + Thread t = new Thread(new Runnable() { + public void run() { + try { + logLinesFromStream(name, is, logger, level); + } finally { + silentClose(is); + } + } + }); + t.start(); + return t; + } + + + public static boolean isMacOSX() { + return OS_NAME.startsWith("Mac OS X"); + } + + public static boolean isWindows() { + return OS_NAME.startsWith("Windows"); + } + + public static void silentClose(Closeable s) { + if (s == null) return; + try { + s.close(); + } catch (Exception ex) { + logStackTrace(LOGGER, Level.WARNING, ex); + } + } + + public static byte[] readFileToByteArray(File file) throws IOException { + if (file == null) + return null; + int len = (int) file.length(); + FileInputStream is = new FileInputStream(file); + try { + byte[] buf = new byte[len]; + if (len != is.read(buf)) { + throw new IOException("Failed to read file content"); + } + return buf; + } finally { + silentClose(is); + } + } + + public static String readFileToString(File file, String encoding) + throws IOException { + byte[] buf = readFileToByteArray(file); + if (buf != null) { + return new String(buf, encoding); + } + + return null; + } + + public static String readFileToString(File file) throws IOException { + byte[] buf = readFileToByteArray(file); + if (buf != null) { + return new String(buf); + } + + return null; + } + + public static String [] readLinesFromFile(File file) + throws IOException + { + FileInputStream is = new FileInputStream(file); + return readLinesFromStream(is); + } + + public static String [] readLinesFromStream(InputStream is) + throws IOException + { + ArrayList list = new ArrayList(); + Scanner s = new Scanner(is); + try { + while (s.hasNext()) { + String line = s.nextLine(); + list.add(line); + } + return list.toArray(new String[list.size()]); + } finally { + silentClose(is); + } + } + + + public static String [] removeComments(String [] list, String lineCommentStart) + { + if (list == null) return list; + + ArrayList out = new ArrayList(); + for (String item : list) { + int pos = item.indexOf(lineCommentStart); + String line = item; + if (pos != -1) { + line = line.substring(0, pos); + } + line = line.trim(); + if (line.length() > 0) { + out.add(line); + } + } + return out.toArray(new String[out.size()]); + } + + public static String joinPath(String [] args) { + if (args == null) return null; + return join(File.pathSeparator, args); + } + + public static void logStackTrace(Logger logger, Level level, Throwable t) + { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + pw.println(t.toString()); + for (StackTraceElement e : t.getStackTrace()) { + pw.println + ( "at " + e.getClassName() + + "." + e.getMethodName() + + "(" + e.getFileName() + + ":" + e.getLineNumber() + + ")" + ); + } + logger.log(level, sw.toString()); + } + + public static File toFile(URL url) { + if (url == null) return null; + if (!isFile(url)) { + throw new IllegalArgumentException("URL does not point to a local file: " + url); + } + return new File(url.getPath()); + } + + public static boolean nullSafeEquals(Object o1, Object o2) + { + if (o1 == null) return o2 == null; + return o1.equals(o2); + } + + public static String join(String sep, Collection list) { + if (list == null) return null; + return join(sep, list.toArray(new String[list.size()])); + } + + public static void accumulateToLineBuffer(InputStream in, + LineBuffer out) { + try { + Scanner s = new Scanner(in); + while (s.hasNext()) { + String line = s.nextLine(); + out.append(line); + } + } finally { + DviUtils.silentClose(in); + } + } + + public static String getTimeId() { + Calendar cal = Calendar.getInstance(); + SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd-HHmmss"); + return df.format(cal.getTime()); + } + + public static CRC32 getCRC32(InputStream is) throws IOException + { + try { + byte [] buf = new byte [1024]; + int len; + CRC32 crc = new CRC32(); + while (-1 != (len = is.read(buf))) { + crc.update(buf, 0, len); + } + return crc; + } finally { + DviUtils.silentClose(is); + } + } + + public static void copyStream(InputStream is, OutputStream os) throws IOException + { + try { + byte [] buf = new byte [1024]; + int len; + while (-1 != (len = is.read(buf))) { + os.write(buf, 0, len); + } + } finally { + // We don't close os. This is intended for use with ZipOutputStream. + DviUtils.silentClose(is); + } + } + + public String getZipPath(File file) + { + if (file == null) return null; + return file.getPath().replace('\\', '/'); + } + + public static String hexDump(String unicode) { + byte [] bytes = unicode.getBytes(); + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/LineBuffer.java b/src/jp/sourceforge/dvibrowser/dvicore/util/LineBuffer.java new file mode 100644 index 0000000..e0cb144 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/LineBuffer.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +public class LineBuffer { + public static final int BUFFER_UNLIMITED = -1; + private int maxLineNumbers; + private final ArrayList list = new ArrayList(); + + public LineBuffer() + { + this(BUFFER_UNLIMITED); + } + + public LineBuffer(int maxLineNumbers) + { + this.setMaxLineNumbers(maxLineNumbers); + } + + public void append(T line) + { + list.add(line); + if (isBufferLimited()) { + while (list.size() > maxLineNumbers) { + list.remove(0); + } + } + } + + private boolean isBufferLimited() { + return !(maxLineNumbers == BUFFER_UNLIMITED); + } + + public List toList() { + return Collections.unmodifiableList(list); + } + + public int getMaxLineNumbers() { + return maxLineNumbers; + } + + public void setMaxLineNumbers(int maxLineNumbers) { + if (maxLineNumbers < 0) { + this.maxLineNumbers = BUFFER_UNLIMITED; + } else { + this.maxLineNumbers = maxLineNumbers; + } + } + + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getName() + + "[" + + "maxLineNumbers=" + maxLineNumbers + + "numLines=" + list.size() + + "lines=" + DviUtils.join("[", ",", "]", list.toArray()) + + "]" + ); + return sb.toString(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/SimpleCanonicalizer.java b/src/jp/sourceforge/dvibrowser/dvicore/util/SimpleCanonicalizer.java new file mode 100644 index 0000000..be6ff05 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/SimpleCanonicalizer.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util; + +import java.util.Map; +import java.util.HashMap; + +public class SimpleCanonicalizer +implements Canonicalizer +{ + private final Map cache = new HashMap(); + + public T canonicalize(T obj) + { + if (cache.containsKey(obj)) { + return cache.get(obj); + } else { + cache.put(obj, obj); + return obj; + } + } + + public int cacheSize() + { + return cache.size(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/TeXMessageParser.java b/src/jp/sourceforge/dvibrowser/dvicore/util/TeXMessageParser.java new file mode 100644 index 0000000..3abe1c8 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/TeXMessageParser.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.io.Reader; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jp.sourceforge.dvibrowser.dvicore.DviException; + + + +// TODO: support logging +// TODO: remove this class +@Deprecated +public class TeXMessageParser +{ + public static final String STATE_INITIAL = "INITIAL"; + + public void parse(Reader r, Handler handler) + throws DviException, IOException + { + if (handler == null) + throw new NullPointerException + ("handler can't be null"); + + Env env = new Env(); + +// env.parser = this; + env.reader = new BufferedReader(r); + env.handler = handler; + env.state = STATE_INITIAL; + env.stop = false; + + env.firstLine = env.reader.readLine(); + if (env.firstLine == null) + throw new EOFException + ("input stream ended while reading the first line."); + env.handler.begin(env); + + while (!env.stop) { + String line = env.reader.readLine(); + parseLine(env, line); + } + } + + protected void parseLine(Env env, String line) + throws DviException, IOException + { + if (line == null) { + if (!env.stop) { + env.handler.end(env); + } + env.stop = true; + return; + } + + env.handler.onEachLine(env, line); + + if (STATE_INITIAL.equals(env.state)) { + parseLineInitial(env, line); + } else { + throw new IllegalStateException(); + } + } + + protected void parseLineInitial(Env env, String line) + throws DviException, IOException + { + env.unrecognized = ""; + int pos = 0; + while (pos < line.length()) { + int next = -1; + if (line.charAt(pos) == '(') { + int p = -1; + int p1 = line.indexOf("(", pos+1); + int p2 = line.indexOf(")", pos+1); + if (p1 == -1) p = p2; + else if (p2 == -1) p = p1; + else p = Math.min(p1, p2); + if (p == -1) p = line.length(); + + String filename = line.substring(pos+1, p); + + boolean success = env.handler.isSupportedFileName(env, filename); +// System.out.println("file: " + filename + ": exists=" + success); + if (success) { + env.handler.beginInput(env, filename); + next = p; + } + } else if (line.charAt(pos) == ')') { + flushUnrecognized(env); + env.handler.endInput(env); + next = pos+1; + } else if (line.charAt(pos) == '[') { + String a = line.substring(pos+1); + Matcher mat = Pattern.compile("^(\\d+)").matcher(a); + if (mat.find()) { + int count = -1; + try { + count = Integer.parseInt(mat.group(1)); + } catch (NumberFormatException e) { + } + flushUnrecognized(env); + env.handler.setCounter(env, count); + next = pos + 1 + mat.group(1).length(); + } + } else if (line.charAt(pos) == ']') { + next = pos+1; + } + + if (next == -1) { + env.unrecognized += line.charAt(pos); + pos++; + } else { + pos = next; + } + } + flushUnrecognized(env); + } + + protected void flushUnrecognized(Env env) + { + String str = env.unrecognized.trim(); + env.unrecognized = ""; + if (str != null && str.length() > 0) { + env.handler.handleUnrecognized(env, str); + } + } + + public static class Env + { +// private TeXMessageParser parser; + private boolean stop; + private String state; + private String unrecognized; + private BufferedReader reader; + private Handler handler; + private String firstLine; + } + + public static interface Handler + { + public boolean isSupportedFileName(Env env, String str); + public void begin(Env env); + public void end(Env env); + public void beginInput(Env env, String filename); + public void endInput(Env env); + public void setCounter(Env env, int count); + public void onEachLine(Env env, String line); + public void handleUnrecognized(Env env, String line); + } + + public static abstract class Adaptor + implements Handler + { + public boolean isSupportedFileName(Env env, String str) { + return false; + } + public void begin(Env env) {} + public void end(Env env) {} + public void beginInput(Env env, String filename) {} + public void endInput(Env env) {} + public void setCounter(Env env, int count) {} + public void onEachLine(Env env, String line) {} + public void handleUnrecognized(Env env, String line) {} + } + + public static class Dumper + extends Adaptor + { + protected final PrintStream out; + public Dumper(PrintStream out) { + this.out = out; + } + public boolean isSupportedFileName(Env env, String str) { + return new File(str).exists(); + } + public void onEachLine(Env env, String line) { + out.println("############" + line + "########"); + } + public void beginInput(Env env, String filename) { + out.println(""); + } + public void endInput(Env env) { + out.println(""); + } + public void handleUnrecognized(Env env, String str) { + out.println("" + str + ""); + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/ZipBuilder.java b/src/jp/sourceforge/dvibrowser/dvicore/util/ZipBuilder.java new file mode 100644 index 0000000..a34b414 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/ZipBuilder.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ +package jp.sourceforge.dvibrowser.dvicore.util; + +import java.io.Closeable; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.logging.Logger; +import java.util.zip.CRC32; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + + +public class ZipBuilder +implements Closeable +{ + private static final Logger LOGGER = Logger.getLogger(ZipBuilder.class.getName()); + + private final ZipOutputStream output; + private final int method; + + public ZipBuilder(OutputStream out, int method) + { + if (!isValidMethod(method)) { + throw new IllegalArgumentException("Unknown ZIP method: " + method); + } + this.method = method; + this.output = createZipOutputStream(out, method); + } + + public ZipBuilder(OutputStream os) + { + this(os, ZipOutputStream.DEFLATED); + } + + protected ZipOutputStream createZipOutputStream(OutputStream out, int method) + { + ZipOutputStream zos = new ZipOutputStream(out); + zos.setMethod(method); + return zos; + } + + protected ZipEntry createZipEntryFromFile(String entryName, File file) throws FileNotFoundException, IOException + { + ZipEntry ze = new ZipEntry(entryName); + switch (getMethod()) { + case ZipOutputStream.STORED: + ze.setSize(file.length()); + CRC32 crc = DviUtils.getCRC32(new FileInputStream(file)); + ze.setCrc(crc.getValue()); + break; + case ZipOutputStream.DEFLATED: + break; + default: + // We have no chance to reach here since the constructor throws + // exception when method is not any one of above. + throw new IllegalStateException("Unknown ZIP method: " + getMethod()); + } + return ze; + } + + protected File createTempFile() throws IOException + { + // TODO: Let a manager to control the temporary file. + File tmpFile = File.createTempFile("zip-builder", null); + tmpFile.deleteOnExit(); + return tmpFile; + } + + public void write(String entryName, InputStream is) throws IOException + { + File tmpFile = createTempFile(); + try { + FileOutputStream fos = new FileOutputStream(tmpFile); + DviUtils.copyStream(is, fos); + fos.flush(); + fos.close(); + is.close(); + write(entryName, tmpFile); + } finally { + tmpFile.delete(); + } + } + + public void write(String entryName, File file) throws IOException + { + ZipEntry ze = createZipEntryFromFile(entryName, file); + output.putNextEntry(ze); + DviUtils.copyStream(new FileInputStream(file), output); + } + + public OutputStream openOutputStream(final String entryName) throws IOException + { + final File tmpFile = createTempFile(); + try { + final boolean [] done = new boolean[1]; + done[0] = false; + FileOutputStream fos = new FileOutputStream(tmpFile); + FilterOutputStream os = new FilterOutputStream(fos) { + public synchronized void close() throws IOException { + // Note that this method might be called multiple times. + // So we return quickly when called twice. + if (done[0]) { + return; + } + done[0] = true; + super.close(); + try { + ZipBuilder.this.write(entryName, tmpFile); + } finally { + tmpFile.delete(); + } + } + }; + return os; + } catch (IOException ex) { + tmpFile.delete(); + throw ex; + } catch (RuntimeException ex) { + tmpFile.delete(); + throw ex; + } catch (Error ex) { + tmpFile.delete(); + throw ex; + } + } + + public static boolean isValidMethod(int method) { + if (method == ZipOutputStream.DEFLATED || method == ZipOutputStream.STORED) { + return true; + } + return false; + } + + public ZipOutputStream getOutputStream() { + return output; + } + + public int getMethod() { + return method; + } + + public void close() throws IOException { + output.close(); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/AbstractComputer.java b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/AbstractComputer.java new file mode 100644 index 0000000..9db28ad --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/AbstractComputer.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.concurrent; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.logging.Logger; + +public abstract class AbstractComputer implements Computer { + private static final Logger LOGGER = Logger.getLogger(AbstractComputer.class + .getName()); + + public abstract ExecutorService getExecutorService(Computation computable); + + public Future compute(Computation computable) + { + ExecutorService exe = getExecutorService(computable); + final Future future = exe.submit(computable); + LOGGER.finer("Scheduled computation " + computable + " to executor service " + exe + " with future object " + future); + return future; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/BasicComputer.java b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/BasicComputer.java new file mode 100644 index 0000000..82616ff --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/BasicComputer.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.concurrent; +import java.util.concurrent.ExecutorService; + +public class BasicComputer extends AbstractComputer { +// private static final Logger LOGGER = Logger.getLogger(BasicComputer.class +// .getName()); + private final ExecutorService executorService; + + public BasicComputer(ExecutorService executorService) + { + this.executorService = executorService; + } + + public ExecutorService getExecutorService() + { + return executorService; + } + + @Override + public ExecutorService getExecutorService(Computation computable) + { + return executorService; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/CacheEntry.java b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/CacheEntry.java new file mode 100644 index 0000000..8c56039 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/CacheEntry.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.concurrent; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicLong; + +public class CacheEntry { +// private static final Logger LOGGER = Logger.getLogger(CachedItem.class +// .getName()); + private final Computer cachedComputer; + private final Computation computable; + private final Future future; + private final long serialNumber; + private static final AtomicLong serializer = new AtomicLong(); + + public CacheEntry(Computer cachedComputer, Computation computable, Future future) + { + this.cachedComputer = cachedComputer; + this.computable = computable; + this.future = future; + this.serialNumber = serializer.incrementAndGet(); + } + + public Computer getCachedComputer() + { + return cachedComputer; + } + + public Computation getComputable() + { + return computable; + } + + public Future getFuture() + { + return future; + } + + public long getSerialNumber() + { + return serialNumber; + } + + public String toString() + { + return getClass().getName() + + "[" + + "serialNumber=" + serialNumber + + ",key=" + computable.getCacheKey() + + ",future=" + future + + "]"; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/Cacheable.java b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/Cacheable.java new file mode 100644 index 0000000..9024537 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/Cacheable.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.concurrent; + +public interface Cacheable { + K getCacheKey(); +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/CachedComputer.java b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/CachedComputer.java new file mode 100644 index 0000000..9923d28 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/CachedComputer.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.concurrent; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.Future; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + + + +public class CachedComputer implements Computer +{ + private final class LinkedHashMapExtension extends + LinkedHashMap> { + private static final long serialVersionUID = 1L; + + @Override + protected boolean removeEldestEntry(Map.Entry> eldest) + { + boolean doRemove = CachedComputer.this.removeEldestEntry(eldest); + LOGGER.finer("doRemove = " + doRemove); + return doRemove; + } + } + + private static final Logger LOGGER = Logger.getLogger(CachedComputer.class.getName()); + private final Map> map; + private final Computer computer; + + public CachedComputer(final Computer computer) + { + this.computer = computer; + map = Collections.synchronizedMap(createCache()); + } + + protected Map> createCache() + { + return new LinkedHashMapExtension(); + } + + protected boolean removeEldestEntry(Map.Entry> entry) + { + return false; + } + + protected synchronized Future startComputation(final Computation computable) + { + final Future future = computer.compute(new Computation() { + public V call() throws Exception { + try { + return computable.call(); + } catch (Throwable e) { + // We would like to associate any exception with the return value of null. + DviUtils.logStackTrace(LOGGER, Level.SEVERE, e); + return null; + } + } + + public K getCacheKey() { + return computable.getCacheKey(); + } + + }); + return future; + } + + /* (non-Javadoc) + * @see Computer#compute(Computation, java.util.concurrent.ExecutorService) + */ + public synchronized Future compute(Computation computable) + { + K key = computable.getCacheKey(); + if (key == null) { + LOGGER.finer("Key is null: " + computable); + final Future future = startComputation(computable); + return future; + } + CacheEntry cacheEntry = map.get(key); + if (cacheEntry == null) { + LOGGER.finer("Cache miss: " + key); + final Future future = startComputation(computable); + cacheEntry = new CacheEntry(this, computable, future); + getCache().put(key, cacheEntry); + LOGGER.finer("Wrote cache: key=" + key + " value=" + future); + } else { + LOGGER.finest("Cache hit: " + key); + } + return cacheEntry.getFuture(); + } + + public synchronized Future getCachedResult(Computation computable) + { + K key = computable.getCacheKey(); + if (key == null) { + return null; + } + CacheEntry cacheEntry = map.get(key); + if (cacheEntry == null) { + return null; + } else { + return cacheEntry.getFuture(); + } + } + + public Map> getCache() + { + return map; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/Computation.java b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/Computation.java new file mode 100644 index 0000000..68855fc --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/Computation.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.concurrent; +import java.util.concurrent.Callable; + + +public interface Computation extends Callable, Cacheable +{ +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/Computer.java b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/Computer.java new file mode 100644 index 0000000..14171e1 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/Computer.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.concurrent; +import java.util.concurrent.Future; + +public interface Computer { + Future compute(Computation computable); +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/ComputerProgressMonitor.java b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/ComputerProgressMonitor.java new file mode 100644 index 0000000..94e4d4b --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/ComputerProgressMonitor.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.concurrent; +import java.util.concurrent.Future; +import java.util.logging.Logger; + +public class ComputerProgressMonitor implements Computer { + private static final Logger LOGGER = Logger.getLogger(ComputerProgressMonitor.class.getName()); + private final Computer computer; + + public ComputerProgressMonitor(Computer computer) + { + this.computer = computer; + } + + public Future compute(final Computation computation) + { + final Computation wrapper = new Computation() { + public V call() throws Exception + { + fireComputationBeginEvent(computation); + try { + V v = computation.call(); + return v; + } catch (Exception e) { + throw e; + } finally { + fireComputationEndEvent(computation); + } + } + + public K getCacheKey() + { + return computation.getCacheKey(); + } + + }; + return computer.compute(wrapper); + } + + protected void fireComputationEndEvent(Computation computation) + { + LOGGER.finer("computation ended: " + computation); + } + + protected void fireComputationBeginEvent(Computation computation) + { + LOGGER.finer("computation started: " + computation); + } + + public Computer getComputer() + { + return computer; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/ThreadedComputer.java b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/ThreadedComputer.java new file mode 100644 index 0000000..8c9c9a5 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/concurrent/ThreadedComputer.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.concurrent; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; + +import jp.sourceforge.dvibrowser.dvicore.util.DaemonThreadFactory; + + +public class ThreadedComputer extends AbstractComputer { +// private static final Logger LOGGER = Logger.getLogger(BasicComputer.class +// .getName()); + private final ExecutorService executorService; + + public ThreadedComputer(int nThreads, ThreadFactory threadFactory) + { + if (threadFactory == null) { + threadFactory = createThreadFactory(); + } + executorService = createExecutorService(nThreads, threadFactory); + } + + public ThreadedComputer(int nThreads) + { + this(nThreads, null); + } + + protected ThreadFactory createThreadFactory() + { + return new DaemonThreadFactory(Thread.MIN_PRIORITY); + } + + protected ExecutorService createExecutorService(int nThreads, ThreadFactory threadFactory) + { + return Executors.newFixedThreadPool(nThreads, threadFactory); + } + + public ExecutorService getExecutorService() + { + return executorService; + } + + @Override + public ExecutorService getExecutorService(Computation computable) + { + return executorService; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvCellCodec.java b/src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvCellCodec.java new file mode 100644 index 0000000..4a5268d --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvCellCodec.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.csv; +public interface CsvCellCodec +{ + public String encodeKey(K key); + public String encodeValue(K key, V value); + public K decodeKey(String s); + public V decodeValue(K key, String s); +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvData.java b/src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvData.java new file mode 100644 index 0000000..f3d9f9c --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvData.java @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.csv; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jp.sourceforge.dvibrowser.dvicore.util.DviUtils; + +public class CsvData { + private static final Logger LOGGER = Logger.getLogger(CsvData.class + .getName()); + private static final String DEFAULT_QUOTE_CHAR = "\""; + private static final String DEFAULT_SEPARATOR = ","; + + private final List> lines = new ArrayList>(); + private final List defaultKeys = new ArrayList(); + private final CsvCellCodec codec; + + public CsvData(CsvCellCodec codec) + { + if (codec == null) + throw new IllegalArgumentException("CSV cell codec can't be null"); + this.codec = codec; + } + + private Map line; + + public void beginLine() + { + if (line != null) { + throw new IllegalStateException("line is not null: last line is not closed."); + } + + line = newLine(); + } + + protected Map newLine() { + return new HashMap(); + } + + public void endLine() + { + lines.add(line); + line = null; + } + + public void put(K key, V value) + { + if (line == null) { + throw new IllegalStateException("line is null: put() method is called before beginLine() is invoked."); + } + line.put(key, value); + if (!defaultKeys.contains(key)) { + defaultKeys.add(key); + } + } + + public V get(Object key) + { + if (line == null) { + throw new IllegalStateException("line is null: get() method is called before beginLine() is invoked."); + } + return line.get(key); + } + + public String [] getLines() + { + return encodeToCsv(null); + } + + public int getRowCount() { + return lines.size(); + } + + public int getColumnCount() { + return defaultKeys.size(); + } + + public V get(int row, Object key) { + Map map = getRow(row); + if (map == null) return null; + return map.get(key); + } + + public Map getRow(int row) { + if (row < 0 || getRowCount() <= row) { + throw new IllegalArgumentException("Row index out of bounds: " + row); + } + + Map map = lines.get(row); + return map; + } + + + public String [] encodeToCsv() + { + return encodeToCsv(null); + } + + public String [] encodeToCsv(Collection keys) + { + List csvEncodedLines = new ArrayList(); + + if (keys == null) { + keys = getDefaultKeys(); + } + + String q = getQuoteChar(); + String s = getSeparatorChar(); + + { + List items = new ArrayList(); + for (K key : keys) { + String k = codec.encodeKey(key); + k = escapeItem(k, q, s); + items.add(k); + } + csvEncodedLines.add(DviUtils.join(s, items)); + } + + for (Map csvLine : lines) { + List items = new ArrayList(); + for (K key : keys) { + V value = csvLine.get(key); + String x = codec.encodeValue(key, value); + x = escapeItem(x, q, s); + items.add(x); + } + csvEncodedLines.add(DviUtils.join(s, items)); + } + + return csvEncodedLines.toArray(new String[csvEncodedLines.size()]); + } + + protected String escapeItem(String x, final String quoteMark, final String separator) + { + final String q = quoteMark; + + if (x == null) { + x = ""; + } else if (needEscape(x)) { + x = q + x.replaceAll(q, q + q) + q; + } + return x; + } + + private static final Pattern patNeedEscape = Pattern.compile("[\\r\\n,\"]"); + protected boolean needEscape(String x) { + if (x == null) { + return false; + } else { + Matcher mat = patNeedEscape.matcher(x); + return mat.find(); + } + } + + public void writeToFile(File file) + throws IOException + { + LOGGER.fine("Writing CSV data to file: " + file); + if (file == null) throw new IllegalArgumentException("file can't be null"); + FileOutputStream fos = new FileOutputStream(file); + try { + writeToStream(fos); + } finally { + fos.flush(); + DviUtils.silentClose(fos); + } + } + + public void writeToStream(OutputStream os) + throws IOException + { + if (os == null) throw new IllegalArgumentException("output stream can't be null"); + try { + PrintWriter pw = new PrintWriter(os); + for (String line : getLines()) { + pw.println(line); + } + pw.flush(); + pw.close(); + } finally { + os.flush(); + DviUtils.silentClose(os); + } + } + + public void readFromFile(File file) throws IOException, CsvException + { + LOGGER.fine("Reading CSV data from file: " + file); + if (file == null) throw new IllegalArgumentException("file can't be null"); + FileInputStream fis = new FileInputStream(file); + try { + readFromStream(fis); + } finally { + DviUtils.silentClose(fis); + } + } + + public void readFromStream(InputStream is) throws IOException, CsvException + { + CsvParser parser = new CsvParser(codec, this); + + String [] lines = DviUtils.readLinesFromStream(is); + for (String line : lines) { + LOGGER.fine("sending line to parser: " + line); + parser.feed(line); + } + parser.close(); + } + + private String getSeparatorChar() { + return DEFAULT_SEPARATOR; + } + + private String getQuoteChar() { + return DEFAULT_QUOTE_CHAR; + } + + protected Collection getDefaultKeys() { + return Collections.unmodifiableList(defaultKeys); + } + + public void putAll(Map map) { + for (Map.Entry entry : map.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + + public int hashCode() + { + int hashCode = 0; + + final int rows = getRowCount(); + for (int i=0; i map = getRow(i); + hashCode = map.hashCode() + 33 * hashCode; + } + return hashCode; + } + + public boolean equals(Object o) { + if (!(o instanceof CsvData)) { + return false; + } + CsvData cd = (CsvData) o; + final int rows = getRowCount(); + final int cols = getColumnCount(); + if (cd.getColumnCount() != cols) return false; + if (cd.getRowCount() != rows) return false; + for (int i=0; i map1 = cd.getRow(i); + Map map2 = getRow(i); + if (map1.equals(map2)) { + return false; + } + } + return true; + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvException.java b/src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvException.java new file mode 100644 index 0000000..dd3c622 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvException.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.csv; +public class CsvException extends Exception { + private static final long serialVersionUID = 5941058193971803624L; + + public CsvException() { + } + + public CsvException(String message) { + super(message); + } + + public CsvException(Throwable cause) { + super(cause); + } + + public CsvException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvLineParser.java b/src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvLineParser.java new file mode 100644 index 0000000..8cd964f --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvLineParser.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.csv; +import java.util.ArrayList; +import java.util.List; +public class CsvLineParser { + private int state = 0; + private StringBuilder sb = null; + private List line = null; + private List> lines = new ArrayList>(); + + public String [][] getData() + { + int cols=0, rows=lines.size(); + for (List line : lines) { + cols = Math.max(cols, line.size()); + } + String [] [] ret = new String[rows][cols]; + int i=0; + for (List line : lines) { + int j=0; + for (String s : line) { + ret[i][j] = s; + j++; + } + i++; + } + return ret; + } + + public void feed(char c) + throws CsvException + { + if (state == 0 || state == 1) { + // Not inside a quotation. + if (state == 0) { + // Begin of Line + openLine(); + } else { + if (sb == null) { + openItem(); + } + } + if (isQuoteChar(c)) { + state = 2; + } else if (isSeparator(c)) { + closeItem(); + state = 1; + } else if (isNewLine(c)) { + closeLine(); + state = 0; + } else { + shipout(c); + state = 1; + } + } else if (state == 2) { + // Inside a quotation. Last char is not a quotation. + if (isQuoteChar(c)) { + state = 3; + } else { + shipout(c); + } + } else if (state == 3) { + // Inside a quotation. Last char is a quotation. + if (isQuoteChar(c)) { + shipout(c); + state = 2; + } else if (isSeparator(c)) { + closeItem(); + state = 1; + } else if (isNewLine(c)) { + closeLine(); + state = 0; + } else { + throw new CsvException("Illegal character: " + c); + } + } else if (state == 4) { + throw new IllegalStateException("Parser is already closed"); + } else { + throw new IllegalStateException("state=" + state); + } + } + + public void close() + throws CsvException + { + if (state == 2) { + throw new CsvException("Input ended while parsing quotation."); + } else if (state == 3) { + closeLine(); + } + state = 4; + } + + protected void openLine() { + line = new ArrayList(); + openItem(); + } + + protected void closeLine() { + closeItem(); + lines.add(line); + } + + protected void openItem() { + sb = new StringBuilder(); + } + + protected void closeItem() { + line.add(sb.toString()); + sb = null; + } + + private boolean isNewLine(char c) { + return c == '\n' || c == '\r'; + } + + private void shipout(char c) { + sb.append(c); + } + + // TODO: outsource the quote char. + private boolean isQuoteChar(char c) { + return (c == '"'); + } + + private boolean isSeparator(char c) { + return (c == ','); + } +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvParser.java b/src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvParser.java new file mode 100644 index 0000000..1c9ed7d --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/csv/CsvParser.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.csv; +import java.util.ArrayList; +import java.util.logging.Logger; +public class CsvParser { + private static final Logger LOGGER = Logger.getLogger(CsvParser.class + .getName()); + private final CsvCellCodec codec; + private CsvLineParser lineParser; + private final CsvData csvData; + + public CsvParser(CsvCellCodec codec, CsvData csvData) { + this.codec = codec; + this.csvData = csvData; + this.lineParser = new CsvLineParser(); + } + + public void feed(String s) + throws CsvException + { + LOGGER.fine("parsing line: " + s); + for (char c : s.toCharArray()) { + lineParser.feed(c); + } + lineParser.feed('\n'); + } + + public void close() throws CsvException + { + lineParser.close(); + + String [] [] data = lineParser.getData(); + final int rows = data.length; + + if (rows > 0) { + LOGGER.fine("ship out rows: " + rows); + final int cols = data[0].length; + + ArrayList keys = new ArrayList(); + for (int j = 0; j < data[0].length; j++) { + keys.add(codec.decodeKey(data[0][j])); + } + + for (int i = 1; i < rows; i++) { + csvData.beginLine(); + for (int j = 0; j < cols; j++) { + K key = keys.get(j); + V value = codec.decodeValue(key, data[i][j]); + csvData.put(key, value); + LOGGER.finer("key=" + key + " value=" + value); + } + csvData.endLine(); + } + } else { + LOGGER.fine("no data to ship out"); + } + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/csv/StringCsvCellCodec.java b/src/jp/sourceforge/dvibrowser/dvicore/util/csv/StringCsvCellCodec.java new file mode 100644 index 0000000..bb10f58 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/csv/StringCsvCellCodec.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.csv; +public final class StringCsvCellCodec +implements CsvCellCodec +{ + public String encodeKey(String key) { + return (key == null) ? "" : key; + } + + public String encodeValue(String key, String value) { + return (value == null) ? "" : value; + } + + public String decodeKey(String s) { + return s; + } + + public String decodeValue(String key, String s) { + return s; + } +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/csv/StringCsvData.java b/src/jp/sourceforge/dvibrowser/dvicore/util/csv/StringCsvData.java new file mode 100644 index 0000000..c1a2709 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/csv/StringCsvData.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.csv; +public class StringCsvData +extends CsvData +{ + public StringCsvData() + { + super(new StringCsvCellCodec()); + } + + public StringCsvData(CsvCellCodec codec) + { + super(codec); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/progress/AbstractProgressModel.java b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/AbstractProgressModel.java new file mode 100644 index 0000000..7ae84e6 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/AbstractProgressModel.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.progress; + +import javax.swing.event.EventListenerList; + +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; + + +public abstract class AbstractProgressModel extends DviObject { + + protected EventListenerList listenerList = new EventListenerList(); + + public AbstractProgressModel(DviContextSupport dcs) { + super(dcs); + } + + public void addProgressListener(ProgressListener l) + { + listenerList.add(ProgressListener.class, l); + } + + public void removeProgressListener(ProgressListener l) + { + listenerList.remove(ProgressListener.class, l); + } + + protected void fireProgressOpenEvent(ManagedProgressItem item) + { + ProgressEvent event = null; + + Object[] listeners = listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i] == ProgressListener.class) { + if (event == null) + event = new ProgressEvent(this, item); + ((ProgressListener)listeners[i+1]).progressOpen(event); + } + } + } + + protected void fireProgressCloseEvent(ManagedProgressItem item) + { + ProgressEvent event = null; + + Object[] listeners = listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i] == ProgressListener.class) { + if (event == null) + event = new ProgressEvent(this, item); + ((ProgressListener)listeners[i+1]).progressClose(event); + } + } + } + + protected void fireProgressUpdateEvent(ManagedProgressItem item) + { + ProgressEvent event = null; + + Object[] listeners = listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i] == ProgressListener.class) { + if (event == null) + event = new ProgressEvent(this, item); + ((ProgressListener)listeners[i+1]).progressUpdate(event); + } + } + } + + public abstract ProgressItem getMostRecentItem(); + +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ManagedProgressItem.java b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ManagedProgressItem.java new file mode 100644 index 0000000..7a16710 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ManagedProgressItem.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.progress; + +import java.util.logging.Logger; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviObject; + + +public class ManagedProgressItem +extends DviObject +implements ProgressItem +{ + private static final Logger LOGGER = Logger.getLogger(ManagedProgressItem.class.getName()); + + public static final int STATE_INIT = 0; + public static final int STATE_OPEN = 1; + public static final int STATE_CLOSED = 2; + private final AbstractProgressModel recorder; + private final ProgressItem item; + private int start, end, current; + private int state = 0; + public ManagedProgressItem(AbstractProgressModel recorder, ProgressItem item) + { + super(recorder); + this.recorder = recorder; + this.item = item; + } + + public boolean isOpen() { + return state == STATE_OPEN; + } + + public boolean isClosed() { + return state == STATE_CLOSED; + } + + public AbstractProgressModel getProgressRecorder() + { + return recorder; + } + + public ProgressItem getOriginalItem() + { + return item; + } + + public void close() throws DviException + { + if (state == STATE_INIT) + throw new IllegalStateException("Item is never opened."); + if (state == STATE_CLOSED) return; + state = STATE_CLOSED; + this.current = this.end; + item.close(); + LOGGER.fine("close: " + item); + recorder.fireProgressCloseEvent(this); + } + + public void open(int start, int end) throws DviException + { + if (state != STATE_INIT) + throw new IllegalStateException("Item is not open or closed."); + state = STATE_OPEN; + this.start = start; + this.current = start; + this.end = end; + item.open(start, end); + LOGGER.fine("opened: " + item); + recorder.fireProgressOpenEvent(this); + } + + public void update(int current) throws DviException + { + if (state != STATE_OPEN) + throw new IllegalStateException("Item is not open or closed."); + this.current = current; + item.update(current); + LOGGER.fine("update: " + item); + recorder.fireProgressUpdateEvent(this); + } + + public String toString() + { + return getClass().getName() + "[" + item.toString() + "]"; + } + + protected void finalize() + { + try { + close(); + } catch (DviException e) { + e.printStackTrace(); + } + } + + public int getStart() + { + return start; + } + + public int getEnd() + { + return end; + } + + public int getCurrent() + { + return current; + } + + public int getState() + { + return state; + } +} \ No newline at end of file diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressBlock.java b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressBlock.java new file mode 100644 index 0000000..48d17cf --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressBlock.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.progress; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; + +public class ProgressBlock +extends DviObject +implements ProgressItem +{ + private final String msg; + private boolean closed = false; + public ProgressBlock(DviContextSupport dcs, String msg) + { + super(dcs); + this.msg = msg; + } + + public void close() throws DviException + { + closed = true; + } + + public void open(int start, int end) throws DviException + { + } + + public void update(int current) throws DviException + { + } + + public String getMessage() + { + return msg; + } + + public String toString() + { + if (closed) { + return "Finished " + msg; + } else { + return "Now " + msg; + } + } + +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressEvent.java b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressEvent.java new file mode 100644 index 0000000..0e589cb --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressEvent.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.progress; + +import java.awt.Event; + + +public class ProgressEvent extends Event { + private static final long serialVersionUID = 1L; + + private final ManagedProgressItem item; + + public ProgressEvent(Object target, ManagedProgressItem item) { + super(target, item.getCurrent(), item); + this.item = item; + } + + public ProgressItem getItem() + { + return item.getOriginalItem(); + } + + public ManagedProgressItem getManagedItem() + { + return item; + } + + public int getStartValue() { return item.getStart(); } + public int getEndValue() { return item.getEnd(); } + public int getCurrentValue() { return item.getCurrent(); } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressItem.java b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressItem.java new file mode 100644 index 0000000..a95b320 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressItem.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.progress; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviSerialized; + +public interface ProgressItem +extends DviSerialized +{ + public void open(int start, int end) throws DviException; + public void update(int current) throws DviException; + public void close() throws DviException; +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressListener.java b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressListener.java new file mode 100644 index 0000000..ab4555a --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressListener.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.progress; + +import java.util.EventListener; + +public interface ProgressListener +extends EventListener +{ + void progressOpen(ProgressEvent e); + void progressUpdate(ProgressEvent e); + void progressClose(ProgressEvent e); +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressLogger.java b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressLogger.java new file mode 100644 index 0000000..d74afe8 --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressLogger.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.progress; + +import java.io.PrintStream; + +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; + + +public class ProgressLogger +extends DviObject implements ProgressListener +{ + private final PrintStream out; + private ProgressRecorder recorder; +// private static ExecutorService exe = Executors.newFixedThreadPool(1, new DaemonThreadFactory()); + + public ProgressLogger(DviContextSupport dcs, PrintStream out, ProgressRecorder recorder) + { + super(dcs); + this.out = out; + setProgressRecorder(recorder); + } + + public void setProgressRecorder(ProgressRecorder recorder) + { + if (this.recorder != null) + this.recorder.removeProgressListener(this); + this.recorder = recorder; + if (this.recorder != null) + this.recorder.addProgressListener(this); + } + + public ProgressRecorder getProgressRecorder() + { + return recorder; + } + + public void progressClose(ProgressEvent e) + { + out.println("[END] " + e.getItem()); + } + + public void progressOpen(ProgressEvent e) + { + out.println("[BEGIN] " + e.getItem()); + } + + public void progressUpdate(ProgressEvent e) + { + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressMessage.java b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressMessage.java new file mode 100644 index 0000000..55697dc --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressMessage.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.progress; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; + +public class ProgressMessage +extends DviObject +implements ProgressItem +{ + private final String msg; + public ProgressMessage(DviContextSupport dcs, String msg) + { + super(dcs); + this.msg = msg; + } + + public void close() throws DviException + { + } + + public void open(int start, int end) throws DviException + { + } + + public void update(int current) throws DviException + { + } + + public String getMessage() + { + return msg; + } + + public String toString() + { + return msg; + } + +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressRecorder.java b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressRecorder.java new file mode 100644 index 0000000..735cb7b --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressRecorder.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.progress; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; + + +public class ProgressRecorder +extends AbstractProgressModel +{ + private final ArrayList list = new ArrayList(); + public ProgressRecorder(DviContextSupport dcs) + { + super(dcs); + } + + protected void addInternal(ManagedProgressItem newWrappedItem) + { + if (newWrappedItem == null) return; + synchronized(list) { + list.add(newWrappedItem); + while (list.size() > 0) { + ManagedProgressItem wrappedItem = list.get(0); + boolean remove = removeEldestElement(wrappedItem); + if (!remove) break; + list.remove(0); + } + } + } + + protected List getProgressItems() { return Collections.unmodifiableList(list); } + + protected boolean removeEldestElement(ManagedProgressItem item) + { + return false; + } + + public void append(ProgressItem item) + throws DviException + { + if (item == null) return; + ManagedProgressItem wrappedItem = (ManagedProgressItem) open(item, 0, 0); + wrappedItem.close(); + } + + public void append(String msg) + throws DviException + { + append(new ProgressMessage(this, msg)); + } + + public ProgressItem open(String msg, int start, int end) + throws DviException + { + ProgressItem item = new ProgressBlock(this, msg); + return open(item, start, end); + } + + public ProgressItem open(String msg) + throws DviException + { + return open(msg, 0, 1); + } + + protected ProgressItem open(ProgressItem item, int start, int end) + throws DviException + { + if (start > end) + throw new IllegalArgumentException + ("Invalid value range: start=" + start + " end=" + end); + ManagedProgressItem wrappedItem = new ManagedProgressItem(this, item); + wrappedItem.open(start, end); + addInternal(wrappedItem); + return wrappedItem; + } + + public ProgressItem getMostRecentItem() + { + ManagedProgressItem managedItem = null; + synchronized(list) { + int size = list.size(); + if (size != 0) + managedItem = list.get(size - 1); + } + if (managedItem != null) { + return managedItem.getOriginalItem(); + } + return null; + } + + public ProgressItem [] getOpenItems() + { + ArrayList items = new ArrayList(); + synchronized(list) { + for (ManagedProgressItem wrappedItem : list) { + if (wrappedItem.isOpen()) + items.add(wrappedItem.getOriginalItem()); + } + } + return items.toArray(new ProgressItem[items.size()]); + } + + public ProgressItem [] getItems() + { + ArrayList items = new ArrayList(); + synchronized(list) { + for (ManagedProgressItem wrappedItem : list) { + items.add(wrappedItem.getOriginalItem()); + } + } + return items.toArray(new ProgressItem[items.size()]); + } +} diff --git a/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressReporter.java b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressReporter.java new file mode 100644 index 0000000..9d07f3f --- /dev/null +++ b/src/jp/sourceforge/dvibrowser/dvicore/util/progress/ProgressReporter.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.util.progress; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; + + +public class ProgressReporter +extends AbstractProgressModel +implements ProgressListener +{ + private final List recorders = new ArrayList(); + + public ProgressReporter(DviContextSupport dcs) + { + super(dcs); + } + + public AbstractProgressModel [] getProgressRecorders() + { + return recorders.toArray(new ProgressRecorder[recorders.size()]); + } + + public void addProgressRecorder(ProgressRecorder recorder) + { + if (recorder == null) return; + if (recorders.contains(recorder)) return; + recorder.addProgressListener(this); + recorders.add(recorder); + } + + public void removeProgressRecorder(AbstractProgressModel recorder) + { + if (recorder == null) return; + if (!recorders.contains(recorder)) return; + recorders.remove(recorder); + recorder.removeProgressListener(this); + } + + private volatile ProgressItem item; + public ProgressItem getMostRecentItem() + { + return item; + } + + protected void update() + { + ArrayList list = new ArrayList(); + for (ProgressRecorder recorder : recorders) { + ProgressItem[] items = recorder.getItems(); + if (items.length != 0) { + ProgressItem item = items[items.length - 1]; + list.add(item); + } + } + Collections.sort(list, new Comparator() { + public int compare(ProgressItem o1, ProgressItem o2) + { + long s1 = o1.getSerialNumber(); + long s2 = o2.getSerialNumber(); + if (s1 < s2) { + return -1; + } else if (s1 > s2) { + return 1; + } else { + return 0; + } + } + }); + if (list.size() > 0) { + item = list.get(list.size() - 1); + } + } + + public void progressClose(ProgressEvent e) + { + update(); + fireProgressCloseEvent(e.getManagedItem()); + } + + public void progressOpen(ProgressEvent e) + { + update(); + fireProgressOpenEvent(e.getManagedItem()); + } + + public void progressUpdate(ProgressEvent e) + { + update(); + fireProgressUpdateEvent(e.getManagedItem()); + } +} -- 2.11.0