--- /dev/null
+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);
+ }
+}
--- /dev/null
+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.");
+ }
+ }
+
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+ }
+
+}
--- /dev/null
+package jp.sourceforge.dvibrowser.dvi2epub.cmd;
+
+public interface CommandLine {
+ boolean hasOption(String name);
+}
--- /dev/null
+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;
+}
--- /dev/null
+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> T unescapeNull(T value)
+ {
+ if (value instanceof String && Command.NULL.equals(value))
+ return null;
+ return value;
+ }
+}
--- /dev/null
+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<Class<?>> 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<Class<?>>();
+ 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
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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<Class<?>> 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<Class<?>>();
+ 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
--- /dev/null
+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;
+}
--- /dev/null
+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<Object[]> d = new Dispatcher<Object []>(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
--- /dev/null
+package jp.sourceforge.dvibrowser.dvi2epub.cmd;
+
+public interface OptionMapper {
+ ParserState getState();
+}
--- /dev/null
+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<String> list = new ArrayList<String>();
+ 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<String> 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;
+ }
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+package jp.sourceforge.dvibrowser.dvi2epub.reflect;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+
+public class Dispatcher<T>
+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;
+ }
+}
--- /dev/null
+/*
+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;
+
+/**
+ * <p>
+ * \8ew\92è\83I\83u\83W\83F\83N\83g\82Ì\82·\82×\82Ä\82Ì\83\81\83\93\83o\81i\83t\83B\81[\83\8b\83h\8by\82Ñ\83\81\83\\83b\83h\81j\82ð\8f\84\89ñ\82µ\82Ä\81C \8cÂ\81X\82Ì\83\81\83\93\83o\82É\91Î\82µ\82Ä\93Á\92è\82Ì\8f\88\97\9d\82ð\8ds\82¤\82½\82ß\82Ì\83N\83\89\83X\81D \8bï\91Ì\93I\82È\8f\88\97\9d\82Ì\93à\97e\82Í
+ * {@link MemberWalkerHandler} \83C\83\93\83^\81[\83t\83F\83C\83X\82Ì\8eÀ\91\95\83N\83\89\83X\82É\8bL\8fq\82µ\82Ä\81C\83R\83\93\83X\83g\83\89\83N\83^\88ø\90\94\82Å\82»\82Ì\83C\83\93\83X\83^\83\93\83X\82ð\8ew\92è\82·\82é\81D
+ * </p>
+ * <p>
+ * \97\98\97p\97á\82ð\8b\93\82°\82é\81D <code><pre>
+ MyBean bean = new MyBean(); // \83\86\81[\83U\92è\8b`\83N\83\89\83X
+ bean.setField1("hogehoge");
+ bean.setField2(314);
+
+ MemberWalker walker = new MemberWalker(new MemberWalkerAdapter() {
+ public void processField(Object o, Field field)
+ {
+ System.out.println("\83t\83B\81[\83\8b\83h: " + field.getName());
+ }
+ });
+ walker.walk(bean);
+ * </pre></code>
+ * </p>
+ *
+ * @author nagaotakeyuki@gmail.com
+ */
+
+public class MemberWalker {
+ private final MemberWalkerHandler handler;
+
+ /**
+ * <p>
+ * \8ew\92è\82³\82ê\82½\83n\83\93\83h\83\89\82ð\8e\9d\82Á\82½\83C\83\93\83X\83^\83\93\83X\82ð\90¶\90¬\82·\82é\81D
+ * </p>
+ *
+ * @param handler
+ * \83\81\83\93\83o\82ð\8c©\82Â\82¯\82½\82Æ\82«\82É\8cÄ\82Ñ\8fo\82³\82ê\82é\83n\83\93\83h\83\89
+ */
+ 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);
+ }
+
+ /**
+ * \8ew\92è\82³\82ê\82½\83I\83u\83W\83F\83N\83g\82Ì\82·\82×\82Ä\82Ì\83\81\83\93\83o\81i\83t\83B\81[\83\8b\83h\82Æ\83\81\83\\83b\83h\81j\82É\91Î\82µ\82Ä\83n\83\93\83h\83\89\82ð\8cÄ\82Ñ\8fo\82·\81D <code>public</code>
+ * \82Å\82È\82¢\83\81\83\93\83o\82à\8f\88\97\9d\82Ì\91Î\8fÛ\82Æ\82È\82é\81D
+ *
+ * @param t
+ * \91Î\8fÛ\82Æ\82È\82é\83I\83u\83W\83F\83N\83g
+ * @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() \82Å\82Í public \83t\83B\81[\83\8b\83h\82µ\82©\8eQ\8fÆ\82Å\82«\82È\82¢\82Ì\82Å
+ // \83N\83\89\83X\82Ì\8aK\91w\82ð Object \83N\83\89\83X\82Ü\82Å\82½\82Ç\82Á\82Ä\83t\83B\81[\83\8b\83h\82Ì\83G\83\93\83R\81[\83h\8f\88\97\9d\82ð\8ds\82¤\81D
+ for (Class<?> cls = t.getClass();; cls = cls.getSuperclass()) {
+ for (Method method : cls.getDeclaredMethods()) {
+ if (!wantMember(t, method))
+ continue;
+ method.setAccessible(true); // public \88È\8aO\82Ì\83\81\83\\83b\83h\82É\82à\83A\83N\83Z\83X\8fo\97\88\82é\82æ\82¤\82É\82·\82é\81D
+ handler.processMethod(t, method);
+ }
+ for (Field field : cls.getDeclaredFields()) {
+ if (!wantMember(t, field))
+ continue;
+ field.setAccessible(true); // public \88È\8aO\82Ì\83t\83B\81[\83\8b\83h\82É\82à\83A\83N\83Z\83X\8fo\97\88\82é\82æ\82¤\82É\82·\82é\81D
+ handler.processField(t, field);
+ }
+ if (cls == Object.class)
+ break;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+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} \82Ì\82½\82ß\82Ì\83A\83_\83v\83^\83N\83\89\83X\81D
+ * @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 {}
+}
--- /dev/null
+/*
+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} \83C\83\93\83^\81[\83t\83F\83C\83X\82Å\97á\8aO\82ð\83\89\83b\83v\82·\82é\82½\82ß\82Ì\97á\8aO\83N\83\89\83X\81D
+ * @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);
+ }
+}
--- /dev/null
+/*
+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} \83N\83\89\83X\82ª\8cÂ\81X\82Ì\83\81\83\93\83o\82É\91Î\82µ\82Ä\8ds\82¤
+ * \8f\88\97\9d\93à\97e\82ð\8bL\8fq\82·\82é\82½\82ß\82Ì\83C\83\93\83^\81[\83t\83F\83C\83X\81D
+ *
+ * @author nagaotakeyuki@gmail.com
+ *
+ */
+public interface MemberWalkerHandler {
+ /**
+ * \93Á\92è\82Ì\83\81\83\93\83o\82ð {@link #processField(Object, Field)} \8by\82Ñ {@link #processMethod(Object, Method)}
+ * \82Ì\8cÄ\82Ñ\8fo\82µ\91Î\8fÛ\82Æ\82·\82é\82©\82Ç\82¤\82©\82ð\8c\88\92è\82·\82é\83\81\83\\83b\83h
+ * @param t \91Î\8fÛ\83I\83u\83W\83F\83N\83g
+ * @param member \91Î\8fÛ\83I\83u\83W\83F\83N\83g\82Ì\83\81\83\93\83o\81i\83t\83B\81[\83\8b\83h\82à\82µ\82\82Í\83\81\83\\83b\83h\81j
+ * @return <code>member</code> \82Å\8ew\92è\82³\82ê\82½\83\81\83\93\83o\82ð\8cÄ\82Ñ\8fo\82µ\91Î\8fÛ\82Æ\82·\82é\8fê\8d\87\82É <code>true</code>\81D
+ * \82»\82ê\88È\8aO\82Í <code>false</code>
+ * @throws MemberWalkerException
+ */
+ boolean wantMember(Object t, Member member) throws MemberWalkerException;
+
+ /**
+ * \83t\83B\81[\83\8b\83h\82ª\8c©\82Â\82©\82Á\82½\8fê\8d\87\82É\8cÄ\82Ñ\8fo\82³\82ê\82é\83\81\83\\83b\83h\81D
+ * @param t \91Î\8fÛ\83I\83u\83W\83F\83N\83g
+ * @param field \8c©\82Â\82©\82Á\82½\83t\83B\81[\83\8b\83h
+ * @throws MemberWalkerException
+ */
+ void processField(Object t, Field field) throws MemberWalkerException;
+
+ /**
+ * \83\81\83\\83b\83h\82ª\8c©\82Â\82©\82Á\82½\8fê\8d\87\82É\8cÄ\82Ñ\8fo\82³\82ê\82é\83\81\83\\83b\83h\81D
+ * @param t \91Î\8fÛ\83I\83u\83W\83F\83N\83g
+ * @param method \8c©\82Â\82©\82Á\82½\83\81\83\\83b\83h
+ * @throws MemberWalkerException
+ */
+ void processMethod(Object t, Method method) throws MemberWalkerException;
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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<String, DviColor> aliases
+ = new HashMap<String, DviColor>();
+
+ 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);
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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<DviFontName> canonicalizer
+ = new SimpleCanonicalizer<DviFontName>();
+
+ 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;
+ }
+}
--- /dev/null
+/*
+ * 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<DviFontSpec> canonicalizer
+ = new SimpleCanonicalizer<DviFontSpec>();
+ 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)
+ );
+ }
+}
--- /dev/null
+/*
+ * 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<Integer, DviFontSpec>
+{
+ 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<Integer>(keySet())) {
+ DviFontSpec fs = (DviFontSpec) get(fn);
+ sb.append("fn[" + fn + "]=" + ((fs != null) ? fs.toString() : "null"));
+ }
+ return sb.toString();
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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));
+ }
+}
--- /dev/null
+/*
+ * 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 + ")";
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+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<rows; i++) {
+ for (int j=0; j<cols; j++) {
+ rects[i][j] = getRectAt(i, j);
+ }
+ }
+ return rects;
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+// mutable.
+
+public final class DviRegister
+implements Cloneable, java.io.Serializable
+{
+ private static final long serialVersionUID = 7923032642831406085L;
+ private int h, v, w, x, y, z;
+
+ public DviRegister() {
+ }
+
+ public DviRegister(DviRegister reg) {
+ this.h = reg.h;
+ this.v = reg.v;
+ this.w = reg.w;
+ this.x = reg.x;
+ this.y = reg.y;
+ this.z = reg.z;
+ }
+
+ public void copy(DviRegister reg) {
+ this.h = reg.h;
+ this.v = reg.v;
+ this.w = reg.w;
+ this.x = reg.x;
+ this.y = reg.y;
+ this.z = reg.z;
+ }
+
+ public int getH() { return h; }
+ public int getV() { return v; }
+ public int getW() { return w; }
+ public int getX() { return x; }
+ public int getY() { return y; }
+ public int getZ() { return z; }
+
+ public void setH(int h) { this.h = h; }
+ public void setV(int v) { this.v = v; }
+ public void setW(int w) { this.w = w; }
+ public void setX(int x) { this.x = x; }
+ public void setY(int y) { this.y = y; }
+ public void setZ(int z) { this.z = z; }
+
+ public void addH(int d) { h += d; }
+ public void addV(int d) { v += d; }
+ public void addW(int d) { w += d; }
+ public void addX(int d) { x += d; }
+ public void addY(int d) { y += d; }
+ public void addZ(int d) { z += d; }
+
+ public void reset() {
+ h = v = w = x = y = z = 0;
+ }
+
+ public String toString() {
+ return getClass().getName() + "[h=" + h +
+ " v=" + v +
+ " w=" + w +
+ " x=" + x +
+ " y=" + y +
+ " z=" + z + "]";
+ }
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException ex) {
+ throw new InternalError();
+ }
+ }
+ public boolean equals(Object obj) {
+ if (obj instanceof DviRegister) {
+ DviRegister a = (DviRegister) obj;
+ return a.h == h && a.v == v && a.w == w &&
+ a.x == x && a.y == y && a.z == z;
+ }
+ return false;
+ }
+ public int hashCode() {
+ return h + 33*(v + 33*(w + 33*(x + 33*(y + 33*z))));
+ }
+}
--- /dev/null
+/*
+ * 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 final class DviResolution
+implements java.io.Serializable
+{
+ private static final long serialVersionUID = -8353020586758660972L;
+ public static final int MAX_SHRINK_FACTOR = 1024;
+
+ private final int dpi;
+ private final int shrinkFactor;
+ private final double actualDpi;
+
+ public DviResolution(int dpi, int shrinkFactor) {
+ this.dpi = dpi;
+ this.shrinkFactor = shrinkFactor;
+ checkVars();
+ actualDpi = (double) dpi / shrinkFactor;
+ }
+
+ private void checkVars() {
+ if (shrinkFactor <= 0 || MAX_SHRINK_FACTOR < shrinkFactor)
+ throw new IllegalArgumentException
+ ("Illegal value of shrinkFactor: " + shrinkFactor);
+ }
+
+ public double actualDpi() {
+ return actualDpi;
+ }
+ public int dpi() { return dpi; }
+ public int shrinkFactor() { return shrinkFactor; }
+
+ public DviResolution approximate(double approximateDpi) {
+ int sf = (int) Math.floor(dpi / approximateDpi);
+ sf = Math.min(sf, MAX_SHRINK_FACTOR);
+ sf = Math.max(sf, 1);
+ return new DviResolution(dpi, sf);
+ }
+
+ public String toString() {
+ return String.format(getClass().getName() + "[dpi=%d,shrinkFactor=%d,actualDpi=%.1f]", dpi, shrinkFactor, actualDpi());
+ }
+ public boolean equals(Object obj) {
+ if (obj instanceof DviResolution) {
+ DviResolution a = (DviResolution) obj;
+ return a.dpi == dpi && a.shrinkFactor == shrinkFactor;
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ return dpi + 33*shrinkFactor;
+ }
+}
--- /dev/null
+/*
+ * 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 interface DviSerialized {
+ long getSerialNumber();
+}
--- /dev/null
+/*
+ * 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 DviSize
+implements java.io.Serializable
+{
+ private static final long serialVersionUID = 2774228595468843394L;
+ public final int width;
+ public final int height;
+
+ public DviSize(int width, int height)
+ {
+ this.width = width;
+ this.height = height;
+ }
+
+ public int width() { return width; }
+ public int height() { return height; }
+
+ public String toString() {
+ return getClass().getName() + "[width=" + width + ",height=" + height + "]";
+ }
+
+ public int hashCode() {
+ return width + 33*height;
+ }
+
+ public boolean equals(Object obj) {
+ if (obj instanceof DviSize) {
+ DviSize a = (DviSize) obj;
+ return a.width == width && a.height == height;
+ }
+ return false;
+ }
+
+ public DviSize magnify(double scale) {
+ return new DviSize((int)(width * scale + 0.5), (int)(height * scale + 0.5));
+ }
+
+ public DviSize magnify(double hScale, double vScale) {
+ return new DviSize((int) (width * hScale + 0.5), (int) (height * vScale + 0.5));
+ }
+}
--- /dev/null
+/*
+ * 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.UUID;
+
+import jp.sourceforge.dvibrowser.dvicore.util.DviUtils;
+
+public final class DviUniqueId {
+ private final long serial;
+
+ private DviUniqueId()
+ {
+ serial = DviUtils.generateSerialNumber();
+ }
+
+ public static DviUniqueId newInstance()
+ {
+ return new DviUniqueId();
+ }
+
+ public String toString() {
+ return DviUtils.getApplicationInstanceUUID() + "--" + serial;
+ }
+
+ public long getSerialNumber() {
+ return serial;
+ }
+
+ public UUID getApplicationInstanceUUID() {
+ return DviUtils.getApplicationInstanceUUID();
+ }
+}
--- /dev/null
+/*
+ * 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 DviUnit
+implements java.io.Serializable
+{
+ private static final long serialVersionUID = -3040236351321035760L;
+
+ public static final DviUnit DEFAULT;
+
+ private static final Canonicalizer<DviUnit> canonicalizer;
+ static {
+ canonicalizer = new SimpleCanonicalizer<DviUnit>();
+ 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;
+ }
+}
--- /dev/null
+/*
+ * 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 + "]";
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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<String, Glyph> 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();
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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<File> inputs = new ArrayList<File>();
+ 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<File> getInputs() {
+ return inputs;
+ }
+
+ public void parseArguments(String [] args) throws DviException
+ {
+ final DviContext ctx = getDviContext();
+ for (int i=0; i<args.length; i++) {
+ String a = args[i];
+ if (a.startsWith(OPT_DPI)) {
+ int dpi = Integer.parseInt(a.substring(OPT_DPI.length()));
+ setShrinkFactor(dpi);
+ } else if (a.startsWith(OPT_SHRINK_FACTOR)) {
+ int sf = Integer.parseInt(a.substring(OPT_SHRINK_FACTOR.length()));
+ setShrinkFactor(sf);
+ } else if (a.startsWith(OPT_PADDING)) {
+ int padding = Integer.parseInt(a.substring(OPT_PADDING.length()));
+ setPaddingSize(padding);
+ } else if (a.startsWith(OPT_PAPER_SIZE)) {
+ String s = a.substring(OPT_PAPER_SIZE.length());
+ DviPaperSize paperSize = ctx.findPaperSizeByName(s);
+ if (paperSize == null) {
+ throw new DviException("Unrecognized papersize: " + s);
+ }
+ } else if (a.startsWith(OPT_RESOURCES_FILE)) {
+ String s = a.substring(OPT_RESOURCES_FILE.length()).trim();
+ if (!"".equals(s)) {
+ setResourcesFile(new File(s));
+ } else {
+ throw new DviException("Output filename is empty.");
+ }
+ } else if (a.startsWith(OPT_OUTPUT_FILE)) {
+ String s = a.substring(OPT_OUTPUT_FILE.length()).trim();
+ if (!"".equals(s)) {
+ setOutputFile(new File(s));
+ } else {
+ throw new DviException("Output filename is empty.");
+ }
+ } else if (a.startsWith(OPT_USE_BBOX)) {
+ String s = a.substring(OPT_USE_BBOX.length()).trim();
+ if ("yes".equalsIgnoreCase(s)) {
+ setUseBoundingBox(true);
+ } else if ("no".equalsIgnoreCase(s)) {
+ setUseBoundingBox(false);
+ } else {
+ throw new DviException("Invalid parameter value: " + a);
+ }
+ } else if (a.startsWith("-")) {
+ throw new DviException("Unrecognized commandline option: " + a);
+ } else {
+ for (; i<args.length; i++) {
+ a = args[i];
+ addInputFile(new File(a));
+ }
+ }
+ }
+ }
+
+ private void setResourcesFile(File file) {
+ this.resourcesFile = file;
+ }
+
+ public File getResourcesFile() {
+ return resourcesFile;
+ }
+
+ private void setPaddingSize(int padding) {
+ this.setPadding(padding);
+ }
+
+ public void setPaperSize(DviPaperSize paperSize) {
+ this.paperSize = paperSize;
+ }
+
+ public ImageFileConfig getImageFileConfig()
+ {
+ return imageFileConfig;
+ }
+
+ public void setImageFileConfig(ImageFileConfig imageFileConfig) {
+ this.imageFileConfig = imageFileConfig;
+ }
+
+ public static String getUsage()
+ {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ pw.println("usage: java " + ConvertToImage.class.getName() + " [options] <input-files>");
+ 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<doc.getTotalPages(); i++) {
+ DviPage page = doc.getPage(i);
+ LOGGER.info("Processing page " + (i + 1) + "/" + doc.getTotalPages());
+ DviRect bbox;
+ if (config.useBoundingBox()) {
+ bbox =
+ ctx.getDviToolkit().computeBoundingBox(page, res);
+ } else {
+ bbox = config.getPaperSize().toBoundingBox(res);
+ }
+ bbox = bbox.addPadding(config.getPadding());
+
+ BufferedImage img = ctx.getDviToolkit().renderToBufferedImage(page, bbox, vs);
+ if (img == null) {
+ throw new DviException("Failed to render page " + (i + 1));
+ }
+
+ OutputStream imageOut = zb.openOutputStream
+ (String.format("%04d%s", i+1, config.getImageFileConfig().getImageExtension()));
+ try {
+ ImageIO.write(img, config.getImageFileConfig().getImageType(), imageOut);
+ } finally {
+ DviUtils.silentClose(imageOut);
+ }
+ }
+ } catch (DviException e) {
+ DviUtils.logStackTrace(LOGGER, Level.SEVERE, e);
+ throw e;
+ }
+ }
+ } finally {
+ DviUtils.silentClose(zb);
+ }
+ return 0;
+ }
+
+ public static void main(String[] args)
+ {
+ try {
+ DefaultDviContext ctx = new DefaultDviContext();
+
+ Config config = new Config(ctx);
+ config.parseArguments(args);
+
+ if (!config.isValid()) {
+ config.showUsage();
+ throw new DviException
+ ("Unrecognized command line: " + DviUtils.join(" ", args));
+ }
+
+ File resourcesFile = config.getResourcesFile();
+
+ if (resourcesFile != null) {
+ ctx.setRecordResources(true);
+ }
+
+ Benchmark benchmark = new Benchmark();
+ benchmark.begin("dvi rendering");
+ benchmark.addSample();
+ ConvertToImage app = new ConvertToImage(ctx);
+ int retcode = app.convert(config);
+ benchmark.end();
+
+ if (resourcesFile != null) {
+ Set<URL> 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);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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];
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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
+ ))))
+ ;
+ }
+}
--- /dev/null
+/*
+ * 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())
+ ;
+ }
+}
--- /dev/null
+/*
+ * 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<S, T>
+extends DviObject
+implements Computation<String, Collection<T>>
+{
+ private final S spec;
+ public AbstractDviResourceResolver(DviContextSupport dcs, S spec) {
+ super(dcs);
+ this.spec = spec;
+ }
+
+ public Collection<T> call() throws Exception
+ {
+ List<T> list = new ArrayList<T>();
+ 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
--- /dev/null
+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<String, Collection<URL>> dviResourceComputer;
+ private final CachedComputer<String, Collection<DviFont>> dviFontComputer;
+ private final CachedComputer<String, Collection<FullMetrics>> fullMetricsComputer;
+ private final CachedComputer<String, DviRect> boundingBoxComputer;
+
+ protected final Properties properties;
+
+ public AsyncComputers(Properties prop) {
+ this.properties = prop;
+ this.dviResourceComputer = new CachedComputer<String, Collection<URL>>(
+ new ThreadedComputer<String, Collection<URL>>(1));
+ this.dviFontComputer = new CachedComputer<String, Collection<DviFont>>(
+ new ThreadedComputer<String, Collection<DviFont>>(1)) {
+ @Override
+ protected boolean removeEldestEntry(
+ Map.Entry<String, CacheEntry<String, Collection<DviFont>>> entry) {
+ boolean remove = getCache().size() > 64;
+ return remove;
+ }
+ };
+
+ fullMetricsComputer = new CachedComputer<String, Collection<FullMetrics>>(
+ new ThreadedComputer<String, Collection<FullMetrics>>(1));
+
+ boundingBoxComputer = new CachedComputer<String, DviRect>(
+ new ThreadedComputer<String, DviRect>(1)) {
+ @Override
+ protected boolean removeEldestEntry(
+ Map.Entry<String, CacheEntry<String, DviRect>> entry) {
+ return getCache().size() > 1024;
+ }
+ };
+
+ }
+
+ public CachedComputer<String, Collection<URL>> getDviResourceComputer() {
+ return dviResourceComputer;
+ }
+
+ public CachedComputer<String, Collection<DviFont>> getDviFontComputer() {
+ return dviFontComputer;
+ }
+
+ public CachedComputer<String, Collection<FullMetrics>> getFullMetricsComputer() {
+ return fullMetricsComputer;
+ }
+
+ public CachedComputer<String, DviRect> getBoundingBoxComputer() {
+ return boundingBoxComputer;
+ }
+}
--- /dev/null
+/*
+ * 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));
+ }
+ }
+}
--- /dev/null
+/*
+ * 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<String, Glyph> glyphCache = new DviCache<String, Glyph>(16384);
+ private final CharacterCodeMapper characterCodeMapper
+ = new SimpleJisToUnicodeMapper();
+
+ private boolean recordResources = false;
+ private final Set<URL> resources = new TreeSet<URL>(new Comparator<URL>() {
+ 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<ManagedProgressItem> 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<String, Collection<DviFont>> dviFontComputer
+// = new CachedComputer<String, Collection<DviFont>>
+// (new ThreadedComputer<String, Collection<DviFont>>(1)) {
+// @Override
+// protected boolean removeEldestEntry(Map.Entry<String, CacheEntry<String, Collection<DviFont>>> entry)
+// {
+// boolean remove = getCache().size() > 64;
+// return remove;
+// }
+// };
+
+ public DviFont findDviFont(LogicalFont logicalFont) throws DviException
+ {
+ Computation<String, Collection<DviFont>> computation
+ = new DviFontResolver(this, logicalFont);
+ try {
+ Collection<DviFont> 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<String, Collection<FullMetrics>> fullMetricsComputer
+// = new CachedComputer<String, Collection<FullMetrics>>
+// (new ThreadedComputer<String, Collection<FullMetrics>>(1));
+
+ public FullMetrics findDviFullMetrics(DviFontSpec fs) throws DviException
+ {
+ Computation<String, Collection<FullMetrics>> computation = new FullMetricsResolver(
+ this, fs);
+ try {
+ Collection<FullMetrics> 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<String, Glyph> 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<String, DviPaperSize> paperSizes = new TreeMap<String, DviPaperSize>();
+
+ 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<String, Collection<URL>> dviResourceComputer
+// = new CachedComputer<String, Collection<URL>>
+// (new ThreadedComputer<String, Collection<URL>>(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<String, Collection<URL>> c
+ = new FileLocationResolver(this, "/dvi/builtin", filename);
+ final Future<Collection<URL>> future
+ = getAsyncComputers().getDviResourceComputer().compute(c);
+ try {
+ final Collection<URL> 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<URL> getRecordedResources() {
+ return resources;
+ }
+
+ protected void setAsyncComputers(AsyncComputers asyncComputers) {
+ this.asyncComputers = asyncComputers;
+ }
+
+ public AsyncComputers getAsyncComputers() {
+ return asyncComputers;
+ }
+}
--- /dev/null
+/*
+ * 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<String, AnchorSet> anchorSetCache = Collections
+ .synchronizedMap(new LinkedHashMap<String, AnchorSet>() {
+ private static final long serialVersionUID = 3603340224879882990L;
+
+ protected boolean removeEldestEntry(Map.Entry<String, AnchorSet> 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<String, DviRect> computation
+ = new DviBoundingBoxPreparator(this, page, res);
+
+ Future<DviRect> 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<DviRect> bbox = new ArrayList<DviRect>();
+
+ 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<ret.length; i++) {
+ ret[i] = raw[i].shrink(res.shrinkFactor());
+ }
+ return ret;
+ }
+
+ private void drawNamedFrame(Graphics gg, String string, Color color, int x, int y, int width, int height)
+ {
+ gg.setColor(color);
+ gg.drawString(string, x, y + 32);
+ gg.drawRect(x, y, width-1, height-1);
+ }
+
+ private static final boolean renderDebugInfo = false;
+
+ /**
+ * Render the specified page to a BufferedImage.
+ * @param page page to render
+ * @param viewSpec used to specify the view configuration.
+ * @param rect the bounding box in the paper coordinate with resolution specified by viewSpec.
+ * @return BufferedImage INT_RGB image
+ * @throws DviException
+ */
+ public BufferedImage renderToBufferedImage(BufferedImage img, int x, int y, DviPage page, DviRect rect,
+ ViewSpec viewSpec) throws DviException
+ {
+ if (img == null)
+ throw new NullPointerException("img");
+ if (page == null)
+ throw new NullPointerException("page");
+ if (viewSpec == null)
+ throw new NullPointerException("view spec");
+
+ final DviResolution res = viewSpec.getResolution();
+
+ DviRect paper = computePageBoundingBox(viewSpec.getPaperSize(), res);
+
+ if (rect == null) {
+ rect = paper;
+ }
+
+ // A point (bbox.x + a, bbox.y + b) in the paper coordinate corresponds to
+ // (x + a, y + b) == (paper2dispX + a, paper2dispY + b) in the image coordinate.
+ final int paper2dispX = x - rect.x();
+ final int paper2dispY = y - rect.y();
+
+ WritableRaster raster = img.getRaster();
+ DataBufferInt data = (DataBufferInt) (raster.getDataBuffer());
+
+ IntRGBImage rgbImage = new IntRGBImage(data.getData(), raster.getWidth(),
+ raster.getHeight());
+ rgbImage.fill(viewSpec.getBackgroundColor().toIntRGB());
+
+ if (viewSpec.isPostScriptEnabled()) {
+ try {
+ SplitImage dviImage = getEmbeddedPostScriptAsSplitImage(page, viewSpec);
+ if (dviImage != null) {
+ Graphics2D gg = img.createGraphics();
+ try {
+ gg.setClip(x, y, rect.width(), rect.height());
+ double factor = res.actualDpi() / dviImage.getResolution().actualDpi();
+ DviRect r0 = dviImage.getRect();
+ DviRect r = r0.magnify(factor);
+ DviRect psRect = r
+ .moveTo(paper.bottomLeft().translate(0, - r.bottom()))
+ .translate(paper2dispX, paper2dispY);
+ SplitImageUtils.renderToGraphics(gg, dviImage, psRect.x(), psRect.y(), factor);
+ if (renderDebugInfo) {
+ drawNamedFrame(gg, "PS", Color.black, psRect.x(), psRect.y(), psRect.width(), psRect.height());
+ }
+ } finally {
+ gg.dispose();
+ }
+ }
+ } catch (OutOfMemoryError e) {
+ DviUtils.logStackTrace(LOGGER, Level.SEVERE, e);
+ }
+ }
+ if (renderDebugInfo) {
+ Graphics gg = img.getGraphics();
+ try {
+ int a = (int) res.actualDpi();
+ DviRect inchBox = paper.crop(a, a, a, a);
+ drawNamedFrame(gg, "Paper", Color.blue, paper2dispX + paper.x(),
+ paper2dispY + paper.y(), paper.width(), paper.height());
+ drawNamedFrame(gg, "InchBox", Color.red, paper2dispX + inchBox.x(),
+ paper2dispY + inchBox.y(), inchBox.width(), inchBox.height());
+ DviRect bbox = computeBoundingBox(page, res);
+ drawNamedFrame(gg, "BBOX", Color.cyan, paper2dispX + bbox.x(),
+ paper2dispY + bbox.y(), bbox.width(), bbox.height());
+ } finally {
+ gg.dispose();
+ }
+ }
+
+ ImageDevice out = rgbImage
+ .getImageDevice(res, viewSpec.getGammaCorrector());
+ out.setColor(viewSpec.getForegroundColor());
+ out.translate(paper2dispX, paper2dispY);
+ DevicePainter dp = getDviContext().newDevicePainter();
+ dp.setOutput(new RunLengthSampler(out));
+ Geometer geometer = new BasicGeometer(this);
+ geometer.setPainter(dp);
+ getDviContext().execute(page, geometer);
+
+ return img;
+ }
+
+ public BufferedImage createCompatibleBufferedImage(int width, int height)
+ {
+ final BufferedImage img = new BufferedImage
+ (width, height, BufferedImage.TYPE_INT_RGB);
+ return img;
+ }
+
+ public BufferedImage renderToBufferedImage(DviPage page, DviRect bbox,
+ ViewSpec viewSpec) throws DviException
+ {
+ final DviResolution res = viewSpec.getResolution();
+
+ DviRect paper = computePageBoundingBox(viewSpec.getPaperSize(), res);
+
+ if (bbox == null) {
+ bbox = paper;
+ }
+
+ final BufferedImage img = createCompatibleBufferedImage(bbox.width(), bbox.height());
+ return renderToBufferedImage(img, 0, 0, page, bbox, viewSpec);
+ }
+
+ public void prepareForRendering(DviDocument doc, ViewSpec viewSpec)
+ throws DviException
+ {
+ if (doc == null) return;
+ if (doc.getTotalPages() > 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<String, Long> 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<String, Long> computation = new DviPagePreparator(this, page, viewSpec);
+ Future<Long> future = computerForPreparator.getCachedResult(computation);
+ return future != null && future.isDone();
+ }
+
+
+
+ public EmbeddedPostScript getEmbeddedPostScript(DviDocument doc, ViewSpec viewSpec)
+ throws DviException
+ {
+ Computation<String, EmbeddedPostScript> computation
+ = new EmbeddedPostScriptPreparator(this, doc, viewSpec);
+ Future<EmbeddedPostScript> 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<String, DviImage> computation = new EPS2ImagePreparator(this,
+ page, viewSpec);
+ Future<DviImage> 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<String, Long> computerForPreparator = new CachedComputer<String, Long>(
+ new ThreadedComputer<String, Long>(1)) {
+ @Override
+ protected boolean removeEldestEntry(
+ Map.Entry<String, CacheEntry<String, Long>> entry) {
+ return getCache().size() > 1024;
+ }
+ };
+
+ private static final CachedComputer<String, EmbeddedPostScript> computerForEmbeddedPostScriptPreparator = new CachedComputer<String, EmbeddedPostScript>(
+ new ThreadedComputer<String, EmbeddedPostScript>(1)) {
+ @Override
+ protected boolean removeEldestEntry(
+ Map.Entry<String, CacheEntry<String, EmbeddedPostScript>> entry) {
+ return getCache().size() > 1024;
+ }
+ };
+
+ private static final CachedComputer<String, DviImage> computerForEPS2Image = new CachedComputer<String, DviImage>(
+ new ThreadedComputer<String, DviImage>(1)) {
+ @Override
+ protected boolean removeEldestEntry(
+ Map.Entry<String, CacheEntry<String, DviImage>> entry) {
+ return getCache().size() > 10;
+ }
+ };
+
+ private static final CachedComputer<String, SplitImage> computerForEPS2SplitImage = new CachedComputer<String, SplitImage>(
+ new ThreadedComputer<String, SplitImage>(1)) {
+ @Override
+ protected boolean removeEldestEntry(
+ Map.Entry<String, CacheEntry<String, SplitImage>> entry) {
+ return getCache().size() > 10;
+ }
+ };
+
+ private static final CachedComputer<String, DviRect> computerForBoundingBoxPreparator = new CachedComputer<String, DviRect>(
+ new ThreadedComputer<String, DviRect>(1)) {
+ @Override
+ protected boolean removeEldestEntry(
+ Map.Entry<String, CacheEntry<String, DviRect>> entry) {
+ return getCache().size() > 1024;
+ }
+ };
+
+
+ public SplitImage getEmbeddedPostScriptAsSplitImage(DviPage page, ViewSpec viewSpec)
+ throws DviException
+ {
+ Computation<String, SplitImage> computation = new EPS2SplitImagePreparator(this,
+ page, viewSpec);
+ Future<SplitImage> 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;
+ }
+
+
+}
--- /dev/null
+/*
+ * 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<String, Collection<URL>> {
+ 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<URL> call() throws Exception
+ {
+ ProgressItem progress = getDviContext().getProgressRecorder().open("preparing " + filename);
+ List<URL> list = new ArrayList<URL>();
+ 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;
+ }
+}
--- /dev/null
+/*
+ * 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<String> cmdLine = new Vector<String>();
+ 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<String> stderrData = new ArrayList<String>();
+ final ArrayList<String> stdoutData = new ArrayList<String>();
+ 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 <path-output-by-kpsewhich>
+
+ 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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<String, Integer> data = new CsvData<String, Integer>(new CsvCellCodec<String, Integer>() {
+ 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<data.getRowCount(); i++) {
+ int texchar = data.get(i, "texchar");
+ int pfbchar = data.get(i, "pfbchar");
+ if (0 <= texchar && texchar < table.length) {
+ table[texchar] = pfbchar;
+ LOGGER.fine(String.format("MAP: %02x=>%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;
+ }
+}
--- /dev/null
+/*
+ * 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));
+ }
+ }
+}
--- /dev/null
+texchar,pfbchar\r0x00,0x2212\r0x01,0x00b7\r0x02,0x00d7\r0x03,0x2217\r0x04,0x00f7\r0x05,0x0000\r0x06,0x00b1\r0x07,0x0000\r0x08,0x2295\r0x09,0x0000\r0x0a,0x2297\r0x0b,0x0000\r0x0c,0x0000\r0x0d,0x0000\r0x0e,0x0000\r0x0f,0x2022\r0x10,0x0000\r0x11,0x2261\r0x12,0x2286\r0x13,0x2287\r0x14,0x2264\r0x15,0x2265\r0x16,0x0000\r0x17,0x0000\r0x18,0x223c\r0x19,0x2248\r0x1a,0x2282\r0x1b,0x2283\r0x1c,0x0000\r0x1d,0x0000\r0x1e,0x0000\r0x1f,0x0000\r0x20,0x2190\r0x21,0x2192\r0x22,0x2191\r0x23,0x2193\r0x24,0x2194\r0x25,0x0000\r0x26,0x0000\r0x27,0x0000\r0x28,0x21d0\r0x29,0x21d2\r0x2a,0x21d1\r0x2b,0x21d3\r0x2c,0x21d4\r0x2d,0x0000\r0x2e,0x0000\r0x2f,0x221d\r0x30,0x0000\r0x31,0x221e\r0x32,0x2208\r0x33,0x0000\r0x34,0x0000\r0x35,0x0000\r0x36,0x0000\r0x37,0x0000\r0x38,0x2200\r0x39,0x2203\r0x3a,0x00ac\r0x3b,0x2205\r0x3c,0x0000\r0x3d,0x0000\r0x3e,0x0000\r0x3f,0x22a5\r0x40,0x2135\r0x41,0x0041\r0x42,0x0042\r0x43,0x0043\r0x44,0x0044\r0x45,0x0045\r0x46,0x0046\r0x47,0x0047\r0x48,0x0048\r0x49,0x0049\r0x4a,0x004a\r0x4b,0x004b\r0x4c,0x004c\r0x4d,0x004d\r0x4e,0x004e\r0x4f,0x004f\r0x50,0x0050\r0x51,0x0051\r0x52,0x0052\r0x53,0x0053\r0x54,0x0054\r0x55,0x0055\r0x56,0x0056\r0x57,0x0057\r0x58,0x0058\r0x59,0x0059\r0x5a,0x005a\r0x5b,0x222a\r0x5c,0x2229\r0x5d,0x0000\r0x5e,0x2227\r0x5f,0x2228\r0x60,0x0000\r0x61,0x0000\r0x62,0x0000\r0x63,0x0000\r0x64,0x0000\r0x65,0x0000\r0x66,0x007b\r0x67,0x007d\r0x68,0x0000\r0x69,0x0000\r0x6a,0x007c\r0x6b,0x0000\r0x6c,0x0000\r0x6d,0x0000\r0x6e,0x005c\r0x6f,0x0000\r0x70,0x221a\r0x71,0x0000\r0x72,0x0000\r0x73,0x222b\r0x74,0x0000\r0x75,0x0000\r0x76,0x0000\r0x77,0x0000\r0x78,0x00a7\r0x79,0x2020\r0x7a,0x2021\r0x7b,0x00b6\r0x7c,0x2663\r0x7d,0x2666\r0x7e,0x2665\r0x7f,0x2660
\ No newline at end of file
--- /dev/null
+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
--- /dev/null
+texchar,pfbchar\r0x00,0x0393\r0x01,0x0394\r0x02,0x0398\r0x03,0x039b\r0x04,0x039e\r0x05,0x03a0\r0x06,0x03a3\r0x07,0x03a5\r0x08,0x03a6\r0x09,0x03a8\r0x0a,0x03a9\r0x0b,0xfb00\r0x0c,0xfb01\r0x0d,0xfb02\r0x0e,0xfb03\r0x0f,0xfb04\r0x10,0x200d\r0x11,0x0237\r0x12,0x0060\r0x13,0x00b4\r0x14,0x02c7\r0x15,0x02d8\r0x16,0x00af\r0x17,0x02da\r0x18,0x00b8\r0x19,0x00df\r0x1a,0x00e6\r0x1b,0x0153\r0x1c,0x00f8\r0x1d,0x00c6\r0x1e,0x0152\r0x1f,0x00d8\r0x20,0x0020\r0x21,0x0021\r0x22,0x201d\r0x23,0x0023\r0x24,0x0024\r0x25,0x0025\r0x26,0x0026\r0x27,0x2019\r0x28,0x0028\r0x29,0x0029\r0x2a,0x002a\r0x2b,0x002b\r0x2c,0x002c\r0x2d,0x002d\r0x2e,0x002e\r0x2f,0x002f\r0x30,0x0030\r0x31,0x0031\r0x32,0x0032\r0x33,0x0033\r0x34,0x0034\r0x35,0x0035\r0x36,0x0036\r0x37,0x0037\r0x38,0x0038\r0x39,0x0039\r0x3a,0x003a\r0x3b,0x003b\r0x3c,0x00a1\r0x3d,0x003d\r0x3e,0x00bf\r0x3f,0x003f\r0x40,0x0040\r0x41,0x0041\r0x42,0x0042\r0x43,0x0043\r0x44,0x0044\r0x45,0x0045\r0x46,0x0046\r0x47,0x0047\r0x48,0x0048\r0x49,0x0049\r0x4a,0x004a\r0x4b,0x004b\r0x4c,0x004c\r0x4d,0x004d\r0x4e,0x004e\r0x4f,0x004f\r0x50,0x0050\r0x51,0x0051\r0x52,0x0052\r0x53,0x0053\r0x54,0x0054\r0x55,0x0055\r0x56,0x0056\r0x57,0x0057\r0x58,0x0058\r0x59,0x0059\r0x5a,0x005a\r0x5b,0x005b\r0x5c,0x201c\r0x5d,0x005d\r0x5e,0x02c6\r0x5f,0x02d9\r0x60,0x2018\r0x61,0x0061\r0x62,0x0062\r0x63,0x0063\r0x64,0x0064\r0x65,0x0065\r0x66,0x0066\r0x67,0x0067\r0x68,0x0068\r0x69,0x0069\r0x6a,0x006a\r0x6b,0x006b\r0x6c,0x006c\r0x6d,0x006d\r0x6e,0x006e\r0x6f,0x006f\r0x70,0x0070\r0x71,0x0071\r0x72,0x0072\r0x73,0x0073\r0x74,0x0074\r0x75,0x0075\r0x76,0x0076\r0x77,0x0077\r0x78,0x0078\r0x79,0x0079\r0x7a,0x007a\r0x7b,0x2013\r0x7c,0x2014\r0x7d,0x02dd\r0x7e,0x02dc\r0x7f,0x00a8
\ No newline at end of file
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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<DviPage> pages = new ArrayList<DviPage>();
+
+ 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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<DviPage> pages = new ArrayList<DviPage>();
+
+ 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()]);
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+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);
+ }
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+package jp.sourceforge.dvibrowser.dvicore.event;
+
+public interface TEventListener
+//extends java.util.EventListener
+{
+ public void handleEvent(TEvent e);
+}
--- /dev/null
+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);
+}
--- /dev/null
+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);
+ }
+}
--- /dev/null
+package jp.sourceforge.dvibrowser.dvicore.event;
+
+public interface TEventProcessor
+{
+ public TEventModel getEventModel();
+}
--- /dev/null
+package jp.sourceforge.dvibrowser.dvicore.event;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+public class TEventQueue
+extends LinkedBlockingQueue<TEvent>
+{
+ private static final long serialVersionUID = -2631304249462595119L;
+
+ public TEvent poll(long timeout)
+ throws InterruptedException
+ {
+ return poll(timeout, TimeUnit.MILLISECONDS);
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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<DviFont> call() throws Exception
+ {
+ Font rawFont = mapToRawAWTFont(getLogicalFont());
+ List<DviFont> list = new ArrayList<DviFont>();
+ 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();
+ }
+}
--- /dev/null
+/*
+ * 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<LogicalFont, DviFont>
+{
+ public AbstractDviFontResolver(DviContextSupport dcs, LogicalFont logicalFont) {
+ super(dcs, logicalFont);
+ }
+
+ public LogicalFont getLogicalFont()
+ {
+ return getSpec();
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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<String, Glyph> 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();
+ }
+}
--- /dev/null
+/*
+ * 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<T>
+extends AbstractDviResourceResolver<DviFontSpec, T>
+{
+// private static final Logger LOGGER = Logger
+// .getLogger(AbstractMetricsResolver.class.getName());
+//
+ public AbstractMetricsResolver(DviContextSupport dcs, DviFontSpec fontSpec) {
+ super(dcs, fontSpec);
+ }
+
+ public DviFontSpec getFontSpec()
+ {
+ return getSpec();
+ }
+}
--- /dev/null
+/*
+ * 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<String, Collection<DviFont>> dviFontComputer
+ = new CachedComputer<String, Collection<DviFont>>
+ (new ThreadedComputer<String, Collection<DviFont>>(3)) {
+ @Override
+ protected boolean removeEldestEntry(Map.Entry<String, CacheEntry<String, Collection<DviFont>>> 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<DviFont> 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<DviFont> list = new ArrayList<DviFont>();
+ {
+ // Note: We have to use the original logical font to find a virtual font.
+ {
+ Future<Collection<DviFont>> 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<Collection<DviFont>> future = dviFontComputer.compute(resolver);
+ Collection<DviFont> fonts = future.get();
+ list.addAll(fonts);
+ }
+ if (list.size() == 0 && type1Enabled) {
+ Future<Collection<DviFont>> future = dviFontComputer
+ .compute(new Type1FontResolver(this, mappedLogicalFont));
+ Collection<DviFont> fonts = future.get();
+ for (DviFont font : fonts) {
+ if (font instanceof AWTDynamicPkFont) {
+ ((AWTDynamicPkFont) font).setCharacterCodeMapper
+ (defaultType1Mapper);
+ }
+ list.add(font);
+ }
+ }
+ if (list.size() == 0 && trueTypeEnabled) {
+ Future<Collection<DviFont>> future = dviFontComputer
+ .compute(new TrueTypeFontResolver(this, mappedLogicalFont));
+ Collection<DviFont> fonts = future.get();
+ for (DviFont font : fonts) {
+ if (font instanceof AWTDynamicPkFont) {
+ ((AWTDynamicPkFont) font).setCharacterCodeMapper
+ (defaultTrueTypeMapper);
+ }
+ list.add(font);
+ }
+ }
+
+ if (list.size() == 0 && pkEnabled() ) {
+ Future<Collection<DviFont>> future = dviFontComputer
+ .compute(new PkFontResolver(this, mappedLogicalFont));
+ list.addAll(future.get());
+ }
+
+ if (list.size() == 0) {
+ Future<Collection<DviFont>> 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;
+ }
+}
--- /dev/null
+/*
+ * 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<FullMetrics> {
+// 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);
+ }
+}
--- /dev/null
+/*
+ * 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<LogicalFont> canonicalizer
+ = new SimpleCanonicalizer<LogicalFont>();
+
+ 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());
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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 + "]";
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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<Integer, Glyph> glyphs
+ = new HashMap<Integer, Glyph>();
+
+ 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * 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"
+ )
+ + "]"
+ ;
+
+ }
+}
--- /dev/null
+/*
+ * 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<RunLengthEncodedLine> 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<RunLengthEncodedLine>(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<height; i++) {
+ RunLengthEncodedLine line = new RunLengthEncodedLine();
+ line.append(buf, bitOffset, width);
+ if (line.equals(prev)) {
+ rlg.lines.add(prev);
+ } else {
+ rlg.lines.add(line);
+ prev = line;
+ }
+ bitOffset += pitch;
+ }
+
+ rlg.compact();
+
+ return rlg;
+ }
+
+ public static RunLengthEncodedGlyph readRasterByBits(
+ byte [] buf, int width, int height,
+ int xOffset, int yOffset)
+ {
+ RunLengthEncodedGlyph rlg = new RunLengthEncodedGlyph(width, height, xOffset, yOffset);
+
+ int bitOffset = 0;
+ RunLengthEncodedLine prev = null;
+ for (int i=0; i<height; i++) {
+ RunLengthEncodedLine line = new RunLengthEncodedLine();
+ line.append(buf, bitOffset, width);
+ bitOffset += width;
+ if (line.equals(prev)) {
+ rlg.lines.add(prev);
+ } else {
+ rlg.lines.add(line);
+ prev = line;
+ }
+ }
+ rlg.compact();
+
+ return rlg;
+ }
+
+ public static RunLengthEncodedGlyph readByteGray(
+ byte [] buf, int width, int height,
+ int xOffset, int yOffset)
+ {
+ RunLengthEncodedGlyph rlg = new RunLengthEncodedGlyph(width, height, xOffset, yOffset);
+
+ int ptr = 0;
+ RunLengthEncodedLine prev = null;
+ for (int i=0; i<height; i++) {
+ final RunLengthEncodedLine line = new RunLengthEncodedLine();
+
+ int last = 314; // A MAGIC value to denote the begin of line.
+ int count = 0;
+ for (int j=0; j<width; j++) {
+ final int c = buf[ptr++];
+ if (c == last) {
+ count++;
+ } else {
+ if (last != 314)
+ line.append(count, (0 != last));
+ count = 1;
+ last = c;
+ }
+ }
+ if (count > 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<height; i++) {
+ RunLengthEncodedLine line = lines.get(i);
+ out.beginLine();
+ line.rasterizeTo(out);
+ out.endLine(0);
+ }
+ }
+ out.endRaster();
+ } finally {
+ out.restore();
+ }
+ }
+
+ public void compact()
+ {
+ int lskip = Integer.MAX_VALUE;
+ int rskip = Integer.MAX_VALUE;
+
+ RunLengthEncodedLine prev = null;
+ for (int i=0; i<height; i++) {
+ RunLengthEncodedLine line = lines.get(i);
+ if (prev == line) continue;
+ if (lskip > 0) {
+ if (line.headOn()) {
+ lskip = 0;
+ } else {
+ lskip = Math.min(lskip, line.head());
+ }
+ }
+ }
+
+ prev = null;
+ for (int i=0; i<height; i++) {
+ RunLengthEncodedLine line = lines.get(i);
+ if (prev == line) continue;
+ line.cropHead(lskip);
+ prev = line;
+ }
+ width -= lskip;
+ xOffset -= lskip;
+
+ if (width <= 0) {
+ width = height = 0;
+ lines.clear();
+ xOffset = yOffset = 0;
+ return;
+ }
+
+ prev = null;
+ for (int i=0; i<height; i++) {
+ RunLengthEncodedLine line = lines.get(i);
+ if (prev == line) continue;
+ if (rskip > 0) {
+ if (line.tailOn()) {
+ rskip = 0;
+ } else {
+ rskip = Math.min(rskip, line.tail());
+ }
+ }
+ prev = line;
+ }
+
+ prev = null;
+ for (int i=0; i<height; i++) {
+ RunLengthEncodedLine line = lines.get(i);
+ if (prev == line) continue;
+ line.cropTail(rskip);
+ prev = line;
+ }
+ width -= rskip;
+
+ if (width <= 0) {
+ width = height = 0;
+ lines.clear();
+ xOffset = yOffset = 0;
+ return;
+ }
+
+ int tskip = 0;
+ int bskip = 0;
+
+ while (height > 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<height; i++) {
+ RunLengthEncodedLine line = lines.get(i);
+ if (line.isEmpty()) {
+ throw new IllegalStateException
+ ("width=" + width + " height=" + height);
+ }
+ }
+ if (width <= 0 || height <= 0) {
+ throw new IllegalStateException
+ ("width=" + width + " height=" + height);
+ }
+ }
+
+ public String dump()
+ {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ for (int i=0; i<height; i++) {
+ RunLengthEncodedLine line = lines.get(i);
+ boolean duplicate = (
+ (i > 0) && lines.get(i-1) == line
+ );
+ pw.println((duplicate ? "+ " : " " ) + line.dump());
+ }
+ return sw.toString();
+ }
+
+ public String toString()
+ {
+ return getClass().getName()
+ + "[width=" + width
+ + " height=" +height
+ + "]";
+ }
+
+ public PkGlyph toPkGlyph()
+ {
+ if (isEmpty())
+ return PkGlyph.EMPTY;
+
+ ArrayList<Integer> counts = new ArrayList<Integer>(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<Integer> data = line.getData();
+ final int ds = data.size();
+ for (int j=0; j<ds; j++) {
+ int c = data.get(j);
+ boolean needFlush = true;
+ if (j == ds - 1) {
+ // at the end of the line.
+ int r = 0;
+ RunLengthEncodedLine next = null;
+ while (++i < height) {
+ next = lines.get(i);
+ if (next != line)
+ break;
+ r++;
+ }
+ needFlush = (
+ next == null ||
+ next.headOn() != line.tailOn()
+ );
+ line = next;
+ if (count > 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<RunLengthEncodedLine> newLines
+ = new ArrayList<RunLengthEncodedLine>(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<Integer> counts, boolean flag)
+// {
+// String str = "";
+//
+// for (int k=0; k<counts.size(); k++) {
+// int c = counts.get(k);
+//
+// if (c < 0) {
+// str += "[" + (-c) + "]";
+// } else if (flag) {
+// str += String.valueOf(c);
+// flag = !flag;
+// } else {
+// str += "(" + c + ")";
+// flag = !flag;
+// }
+// }
+//
+// return str;
+// }
+
+ private class BinaryDeviceImpl
+ extends AbstractDevice
+ implements BinaryDevice
+ {
+ private BinaryDeviceImpl(DviResolution res)
+ {
+ super(res);
+ }
+
+ public void begin()
+ throws DviException
+ {
+ }
+
+ public void end()
+ throws DviException
+ {
+ }
+
+ private RunLengthEncodedGlyph rlg = null;
+ public boolean beginRaster(int w, int h)
+ throws DviException
+ {
+ rlg = new RunLengthEncodedGlyph();
+ rlg.width = w;
+ rlg.height = h;
+ return true;
+ }
+
+ public void endRaster()
+ throws DviException
+ {
+ DviPoint p = getReferencePoint();
+ // The reference point of rlg is at the origin of this device.
+ rlg.xOffset = -p.x;
+ rlg.yOffset = -p.y;
+ rlg.compact();
+
+ unite(rlg);
+ rlg = null;
+ }
+
+ private RunLengthEncodedLine line = null;
+ public void beginLine()
+ throws DviException
+ {
+ line = new RunLengthEncodedLine();
+ }
+
+ public void endLine(int repeat)
+ throws DviException
+ {
+ for (int i=0; i<=repeat; i++) {
+ rlg.lines.add(line);
+ }
+ line = null;
+ }
+
+ public void putBits(int count, boolean paintFlag)
+ {
+ line.append(count, paintFlag);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+import jp.sourceforge.dvibrowser.dvicore.DviException;
+import jp.sourceforge.dvibrowser.dvicore.api.BinaryDevice;
+
+
+// mutable
+
+public final class RunLengthEncodedLine
+implements Cloneable
+{
+ private int hash = 0;
+ private int width = 0;
+ private boolean headOn = false;
+ private boolean tailOn = false;
+ private ArrayList<Integer> data
+ = new ArrayList<Integer>();
+
+ // TODO: Make the return value unmodifiable.
+ public ArrayList<Integer> 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<ds; i++) {
+ out.putBits(data.get(i), flag);
+ flag = !flag;
+ }
+ }
+
+ ///////////////
+
+ public void prepend(int count, boolean isOn)
+ {
+ if (count <= 0) return;
+ if (width == 0) {
+ headOn = tailOn = isOn;
+ data.add(count);
+ width = count;
+ } else {
+ if (headOn == isOn) {
+ data.set(0, data.get(0) + count);
+ } else {
+ data.add(0, count);
+ headOn = isOn;
+ }
+ width += count;
+ }
+ hash += isOn ? count : -count;
+ }
+
+ public void append(int count, boolean isOn)
+ {
+ if (count <= 0) return;
+ if (width == 0) {
+ headOn = tailOn = isOn;
+ data.add(count);
+ width = count;
+ } else {
+ int last = data.size() - 1;
+ if (tailOn == isOn) {
+ data.set(last, data.get(last) + count);
+ } else {
+ data.add(count);
+ tailOn = isOn;
+ }
+ width += count;
+ }
+ hash += isOn ? count : -count;
+ }
+
+ public void cropHead(int count) {
+ if (width == 0) return;
+ while (count > 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<ds; i++) {
+ append(rll.data.get(i), flag);
+ flag = !flag;
+ }
+ }
+
+ ///////////////
+
+ public void prepend(byte [] buf) {
+ prepend(buf, 0, buf.length * 8, false);
+ }
+ public void append(byte [] buf) {
+ append(buf, 0, buf.length * 8, false);
+ }
+ public void prepend(byte [] buf, int bitOffset, int bitLen) {
+ prepend(buf, bitOffset, bitLen, false);
+ }
+ public void append(byte [] buf, int bitOffset, int bitLen) {
+ append(buf, bitOffset, bitLen, false);
+ }
+ public void prepend(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=bitOffset+bitLen-1; 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<bitLen; i++) {
+ final int p = i + bitOffset;
+ boolean flag = (0 != (buf[p >>> 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<Integer>) 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<s; i++) {
+ int count = data.get(i);
+ if (flag)
+ sb.append(String.valueOf(count));
+ else
+ sb.append("(" + String.valueOf(count) + ")");
+ flag = !flag;
+ }
+ return getClass().getName()
+ + "[width=" + width
+ + " hash=" + hash
+ + " headOn=" + headOn
+ + " tailOn=" + tailOn
+ + " dataSize=" + data.size()
+ + " data=[" + sb.toString() + "]"
+ ;
+ }
+
+ public String dump()
+ {
+ StringBuilder sb = new StringBuilder();
+ boolean flag = headOn;
+ int s = data.size();
+ for (int i=0; i<s; i++) {
+ int count = data.get(i);
+ if (flag)
+ while (count-- > 0)
+ sb.append("*");
+ else
+ while (count-- > 0)
+ sb.append("-");
+ flag = !flag;
+ }
+ return sb.toString();
+ }
+}
--- /dev/null
+/*
+ * 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<Integer> data; // We don't modify its content.
+
+ public SequencePacker(ArrayList<Integer> 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<ds; i++) {
+ int c = data.get(i);
+ if (c == 0) continue; // ignored.
+
+ if (c == -1) {
+ writeNyb(15);
+ continue;
+ } else if (c < 0) {
+ writeNyb(14);
+ c = -c;
+ }
+
+ if (c <= dynF) {
+ writeNyb(c);
+ } else if (c < dynG) {
+ final int cc = c + dynH;
+ writeNyb(cc >>> 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<Integer> 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<ds; i++) {
+ int c = data.get(i);
+ if (c == 0) continue; // ignored.
+ if (c == -1) {
+ len++;
+ continue;
+ } else if (c < 0) {
+ len++;
+ c = -c;
+ }
+
+ if (c < (1 << 4) - 2) {
+ diff[c-1] -= 1;
+ len += 2;
+ } else if (c < (1 << 4) - 2 + 195) {
+ final int cc = c - ((1 << 4) - 2);
+ diff[cc2diffPos[cc]] += 1;
+ len += 2;
+ } else if (c < (1 << 8) - 2) {
+ len += 3;
+ } else if (c < (1 << 8) - 2 + 195) {
+ final int cc = c - ((1 << 8) - 2);
+ diff[cc2diffPos[cc]] += 2;
+ len += 3;
+ } else if (c < (1 << 12) - 2) {
+ len += 5;
+ } else if (c < (1 << 12) - 2 + 195) {
+ final int cc = c - ((1 << 12) - 2);
+ diff[cc2diffPos[cc]] += 2;
+ len += 5;
+ } else if (c < (1 << 16) - 2) {
+ len += 7;
+ } else if (c < (1 << 16) - 2 + 195) {
+ final int cc = c - ((1 << 16) - 2);
+ diff[cc2diffPos[cc]] += 2;
+ len += 7;
+ } else if (c < (1 << 20) - 2) {
+ len += 9;
+ } else if (c < (1 << 20) - 2 + 195) {
+ final int cc = c - ((1 << 20) - 2);
+ diff[cc2diffPos[cc]] += 2;
+ len += 9;
+ } else if (c < (1 << 24) - 2) {
+ len += 11;
+ } else if (c < (1 << 24) - 2 + 195) {
+ final int cc = c - ((1 << 24) - 2);
+ diff[cc2diffPos[cc]] += 2;
+ len += 11;
+ } else if (c < (1 << 28) - 2) {
+ len += 13;
+ } else if (c < (1 << 28) - 2 + 195) {
+ final int cc = c - ((1 << 28) - 2);
+ diff[cc2diffPos[cc]] += 2;
+ len += 13;
+ } else {
+ len += 15;
+ }
+ }
+
+ int bestDynF = -1;
+ int bestSize = Integer.MAX_VALUE;
+ int dynF = 0;
+ for (;;) {
+ if (len < bestSize) {
+ bestDynF = dynF;
+ bestSize = len;
+ }
+ if (dynF >= 13)
+ break;
+
+ len += diff[dynF];
+ dynF++;
+ }
+
+ Config cfg = new Config(bestDynF, bestSize);
+ return cfg;
+ }
+}
--- /dev/null
+/*
+ * 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<Integer, Record> ct2rec
+ = new HashMap<Integer, Record>();
+ private HashMap<Integer, Integer> 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<Integer, Integer>();
+ for (int i=0; i<nt; i++) {
+ final int from = in.readU2();
+ final int to = in.readU2();
+ code2ct.put(from, to);
+ }
+ } else {
+ code2ct = null;
+ }
+
+ int [] char_info_t = readBuffer(in, numChars);
+ int [] width_t = readBuffer(in, nw);
+ int [] height_t = readBuffer(in, nh);
+ int [] depth_t = readBuffer(in, nd);
+ int [] italic_t = readBuffer(in, ni);
+ int [] lig_kern_t = readBuffer(in, nl);
+ int [] kern_t = readBuffer(in, nk);
+ int [] exten_t = readBuffer(in, ne);
+ int [] param_t = readBuffer(in, np);
+
+ long size = in.getOffset() - start;
+ if (lf * 4 != size ||
+ lf != (isJFM ? 7 : 6) +
+ lh +
+ nt +
+ numChars +
+ nw +
+ nh +
+ nd +
+ ni +
+ nl +
+ nk +
+ ne +
+ np)
+ throw new DviException
+ ("Length mismatch in TFM data");
+
+ if (isJFM && bc != 0)
+ throw new DviException
+ ("bc must be 0 in JFM data.");
+
+ for (int i=0; i<numChars; i++) {
+ final int ct = i + bc;
+ final int ci = char_info_t[i];
+ final int wi = (ci >>> 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<length; i++)
+ buf[i] = in.readU4();
+ return buf;
+ }
+
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public int getCheckSum() {
+ return checkSum;
+ }
+
+ public int getDesignSize() {
+ return designSize;
+ }
+
+ public boolean isJFM() {
+ return isJFM;
+ }
+
+ public boolean hasChar(int code)
+ {
+ return isJFM ? true : ct2rec.containsKey(code);
+ }
+
+ private int codeToCt(int code)
+ {
+ return (code2ct == null) ? code :
+ code2ct.containsKey(code) ? code2ct.get(code) : 0;
+ }
+ private Record getRecord(int code)
+ {
+ return ct2rec.get(codeToCt(code));
+ }
+
+ public int getTfmWidth(int code)
+ {
+ Record rec = getRecord(code);
+ return (rec != null) ? rec.width : 0;
+ }
+ public int getTfmHeight(int code)
+ {
+ Record rec = getRecord(code);
+ return (rec != null) ? rec.height : 0;
+ }
+ public int getTfmDepth(int code)
+ {
+ Record rec = getRecord(code);
+ return (rec != null) ? rec.depth : 0;
+ }
+ public int getTfmItalic(int code)
+ {
+ Record rec = getRecord(code);
+ return (rec != null) ? rec.italic : 0;
+ }
+
+ public static String getTfmFilename(DviFontSpec spec)
+ {
+ String tfm = spec.name() + ".tfm";
+ return tfm;
+ }
+
+ private static class Record implements java.io.Serializable {
+ private static final long serialVersionUID = 1638947545775532119L;
+ private final int width;
+ private final int height;
+ private final int depth;
+ private final int italic;
+
+ private Record(int width, int height, int depth, int italic) {
+ this.width = width;
+ this.height = height;
+ this.depth = depth;
+ this.italic = italic;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.FontFormatException;
+import java.io.IOException;
+import java.io.InputStream;
+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.api.DviContextSupport;
+import jp.sourceforge.dvibrowser.dvicore.api.DviFont;
+import jp.sourceforge.dvibrowser.dvicore.ctx.UnicodeCharacterCodeMapper;
+import jp.sourceforge.dvibrowser.dvicore.util.DviUtils;
+
+
+// TODO: merge this class with Type1FontResolver
+public class TrueTypeFontResolver
+extends AbstractDviFontResolver
+{
+ private static final Logger LOGGER = Logger.getLogger(DviFontResolver.class
+ .getName());
+
+ private static final CharacterCodeMapper mapper = new UnicodeCharacterCodeMapper();
+
+ private String fileExtension = ".ttf";
+
+ public TrueTypeFontResolver(DviContextSupport dcs, LogicalFont logicalFont)
+ {
+ super(dcs, logicalFont);
+ }
+
+ @Override
+ protected DviFont createInstanceFromStream(InputStream is) throws DviException
+ {
+ try {
+ Font font = Font.createFont(Font.TRUETYPE_FONT, is);
+ return new AWTDynamicPkFont(this, font, mapper);
+ } catch (IOException e) {
+ DviUtils.logStackTrace(LOGGER, Level.WARNING, e);
+ throw new DviException(e);
+ } catch (FontFormatException e) {
+ DviUtils.logStackTrace(LOGGER, Level.WARNING, e);
+ throw new DviException(e);
+ }
+ }
+
+ @Override
+ protected String mapToDviResourceName(LogicalFont logicalFont)
+ {
+ String name = logicalFont.fontSpec().name();
+ return name + fileExtension;
+ }
+
+ public void setFileExtension(String fileExtension) {
+ this.fileExtension = fileExtension;
+ }
+
+ public String getFileExtension() {
+ return fileExtension;
+ }
+
+}
--- /dev/null
+/*
+ * 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.FontFormatException;
+import java.io.IOException;
+import java.io.InputStream;
+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.api.DviContextSupport;
+import jp.sourceforge.dvibrowser.dvicore.api.DviFont;
+import jp.sourceforge.dvibrowser.dvicore.ctx.UnicodeCharacterCodeMapper;
+import jp.sourceforge.dvibrowser.dvicore.util.DviUtils;
+
+
+public class Type1FontResolver
+extends AbstractDviFontResolver
+{
+ private static final Logger LOGGER = Logger.getLogger(DviFontResolver.class
+ .getName());
+
+ private static final CharacterCodeMapper mapper = new UnicodeCharacterCodeMapper();
+
+ public Type1FontResolver(DviContextSupport dcs, LogicalFont logicalFont)
+ {
+ super(dcs, logicalFont);
+ }
+
+ @Override
+ protected DviFont createInstanceFromStream(InputStream is) throws DviException
+ {
+ try {
+ Font font = Font.createFont(Font.TYPE1_FONT, is);
+ return new AWTDynamicPkFont(this, font, mapper);
+ } catch (IOException e) {
+ DviUtils.logStackTrace(LOGGER, Level.WARNING, e);
+ throw new DviException(e);
+ } catch (FontFormatException e) {
+ DviUtils.logStackTrace(LOGGER, Level.WARNING, e);
+ throw new DviException(e);
+ }
+ }
+
+ @Override
+ protected String mapToDviResourceName(LogicalFont logicalFont)
+ {
+ String name = logicalFont.fontSpec().name();
+ return name + ".pfb";
+ }
+
+}
--- /dev/null
+/*
+ * 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.EOFException;
+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.DviFontTable;
+import jp.sourceforge.dvibrowser.dvicore.DviResolution;
+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.DviExecutor;
+import jp.sourceforge.dvibrowser.dvicore.api.Geometer;
+import jp.sourceforge.dvibrowser.dvicore.cmd.DviCommand;
+import jp.sourceforge.dvibrowser.dvicore.io.ByteArrayDviData;
+import jp.sourceforge.dvibrowser.dvicore.io.DviInputStreamReader;
+import jp.sourceforge.dvibrowser.dvicore.render.VirtualFontGeometer;
+import jp.sourceforge.dvibrowser.dvicore.util.DviUtils;
+
+
+public class VirtualFont
+extends AbstractDynamicPkFont
+{
+ private static final long serialVersionUID = -4723597208297552498L;
+
+ private final HashMap<Integer, GlyphInfo> glyphInfos
+ = new HashMap<Integer, GlyphInfo>();
+
+ 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";
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * 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<DviRect> list = new ArrayList<DviRect>();
+
+ 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();
+ }
+}
--- /dev/null
+/*
+ * 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<String> buildCommandLine()
+ throws DviException
+ {
+ ArrayList<String> cl = new ArrayList<String>();
+ 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<String> 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;
+ }
+}
--- /dev/null
+/*
+ * 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<String> list;
+ private final String path;
+ public CommandShellHandlerImpl(String path, ArrayList<String> 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<DviRect> list = new ArrayList<DviRect>();
+
+ 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<String> list = new ArrayList<String>();
+ final ArrayList<String> candidates = new ArrayList<String>();
+
+ 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()]);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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<cs.length; i++) {
+ add(cs[i]);
+ }
+ }
+ }
+
+ private void addComponent(Component c) {
+ c.addMouseMotionListener(this);
+ c.addMouseListener(this);
+ }
+
+ public void remove(Component c) {
+ if (c == null) return;
+ if (c instanceof Container) {
+ Component [] cs = ((Container) c).getComponents();
+ for (int i=0; i<cs.length; i++) {
+ remove(cs[i]);
+ }
+ }
+ removeComponent(c);
+ }
+
+ private void removeComponent(Component c) {
+ if (c == null) return;
+ c.removeMouseMotionListener(this);
+ c.removeMouseListener(this);
+ }
+
+ public void mouseClicked(MouseEvent e)
+ {
+ debug("mouseClicked");
+ }
+
+ public void mouseEntered(MouseEvent e)
+ {
+ debug("mouseEntered");
+ }
+ public void mouseExited(MouseEvent e)
+ {
+ debug("mouseExited");
+ }
+ private int saveX, saveY;
+ private void savePoint(int x, int y) {
+ saveX = x;
+ saveY = y;
+ }
+
+ public void mousePressed(MouseEvent e)
+ {
+ debug("mousePressed");
+ Cursor cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
+ Component c = (Component) e.getSource();
+ c.setCursor(cursor);
+
+ if (!e.isPopupTrigger()) {
+ Point p = e.getPoint();
+ SwingUtilities.convertPointToScreen(p, e.getComponent());
+ savePoint(p.x, p.y);
+ }
+ }
+ public void mouseReleased(MouseEvent e)
+ {
+ debug("mouseReleased");
+ Component c = (Component) e.getSource();
+ c.setCursor(null);
+ }
+
+ public void mouseDragged(MouseEvent e)
+ {
+ if (!e.isPopupTrigger()) {
+ Component c = e.getComponent();
+ debug(e.getSource() + ": mouseDragged");
+ Point p = e.getPoint();
+ SwingUtilities.convertPointToScreen(p, c);
+ int dx = p.x - saveX;
+ int dy = p.y - saveY;
+
+ debug("(dx,dy)=(" + dx + "," + dy + ")");
+
+ savePoint(p.x, p.y);
+
+ if (dy == 0) {
+ hsb.setValue(hsb.getValue() - dx);
+ } else if (dx == 0) {
+ vsb.setValue(vsb.getValue() - dy);
+ } else {
+ JViewport jv = jsp.getViewport();
+ jv.scrollRectToVisible(
+ new Rectangle(-dx, -dy, jv.getWidth(), jv.getHeight())
+ );
+ }
+ }
+ }
+
+ public void mouseMoved(MouseEvent e)
+ {
+ debug("mouseMoved");
+ }
+
+ private static void debug(String str) {
+// System.out.println(str);
+ }
+}
--- /dev/null
+/*
+ * 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.LayoutManager;
+
+import jp.sourceforge.dvibrowser.dvicore.DviException;
+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;
+
+
+public interface DviLayoutManager
+extends DviContextSupport
+{
+ LayoutManager createLayout(DviDocument doc, DviResolution res) throws DviException;
+ DviRect getBoundingBox(DviDocument doc, DviResolution res) throws DviException;
+ DviRect getPageBoundingBox(DviDocument doc, DviResolution res) throws DviException;
+ boolean getEnableDelayedRendering(TDviPage dp) throws DviException;
+ void decoratePage(TDviDocument tdd, TDviPage dp) throws DviException;
+ DviRect determinePageSize(TDviPage dp) throws DviException;
+}
--- /dev/null
+/*
+ * 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.FlowLayout;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.util.ArrayList;
+import java.util.logging.Logger;
+
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import jp.sourceforge.dvibrowser.dvicore.DviException;
+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;
+
+
+public class TDviDocument
+extends JPanel
+implements DviContextSupport, ChangeListener
+{
+ private static final Logger LOGGER = Logger.getLogger(TDviDocument.class.getName());
+ private static final long serialVersionUID = -8289664311728401054L;
+
+ private JPanel panel = new JPanel();
+
+ private final ArrayList<TDviPage> pageList
+ = new ArrayList<TDviPage>();
+
+ 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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; }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+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);
+ }
+}
--- /dev/null
+/*
+ * 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<rows; row++) {
+ final BufferedImage [] imgs = new BufferedImage[cols];
+ final DataBufferByte [] buffers = new DataBufferByte[cols];
+ int h = 0;
+ LOGGER.fine("Reading row=" + row + "/" + rows);
+ for (int col =0; col < cols; col++) {
+ final DviRect box = samplingRects[row][col];
+ imgs[col] = createBufferedImage(box);
+ h = box.height();
+ buffers[col] = (DataBufferByte) imgs[col].getRaster().getDataBuffer();
+ }
+ for (int i=0; i<h; i++) {
+ readFully(buf);
+ int x = 0;
+ for (int col =0; col < cols; col++) {
+ final DviRect box = samplingRects[row][col];
+ final int uw = copyLineToDataBuffer(buf, x, box, i, buffers[col]);
+ x += uw;
+ }
+ }
+ for (int col = 0; col < cols; col++) {
+ if (sf == 1) {
+ final BufferedImage img = imgs[col];
+ imageWriter.writeImagePiece(img, row, col);
+ } else {
+ final DviRect box = rects[row][col];
+ final BufferedImage img = imgs[col];
+ final BufferedImage img2 = new BufferedImage(box.width(), box.height(), BufferedImage.TYPE_INT_RGB);
+ Graphics2D g = img2.createGraphics();
+ g.drawImage(img.getScaledInstance(box.width(), box.height(), Image.SCALE_AREA_AVERAGING), 0, 0, null);
+ g.dispose();
+ imageWriter.writeImagePiece(img2, row, col);
+ }
+ }
+ }
+ } finally {
+ imageWriter.endSplitImage();
+ }
+ } finally {
+ endSplitInternal();
+ }
+ } finally {
+ LOGGER.fine("Closing the stream");
+ DviUtils.silentClose(input);
+ }
+ }
+
+ public SplitImageWriter getSplitImageWriter() {
+ return imageWriter;
+ }
+
+ public DviSize getUnitSize() {
+ return unitSize;
+ }
+
+ public void setShrinkFactor(int shrinkFactor) {
+ if (0 >= shrinkFactor)
+ throw new IllegalArgumentException("shrinkFactor is non-positive.");
+ this.shrinkFactor = shrinkFactor;
+ }
+
+ public int getShrinkFactor() {
+ return shrinkFactor;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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<w; j++) {
+ dst[j + i * uw] = (byte) table[byteToInt(buf[x + j])];
+ }
+ return uw;
+ }
+
+ private int byteToInt(byte b) {
+ if (b >= 0) return b;
+ return 256 + b;
+ }
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+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
--- /dev/null
+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);
+ }
+}
--- /dev/null
+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<w; j++) {
+ dst[j * 3 + i * uw + 0] = (byte) table[byteToInt(buf[x + j * 3 + 2])]; // B
+ dst[j * 3 + i * uw + 1] = (byte) table[byteToInt(buf[x + j * 3 + 1])]; // G
+ dst[j * 3 + i * uw + 2] = (byte) table[byteToInt(buf[x + j * 3 + 0])]; // R
+ }
+ return uw;
+ }
+
+ private int byteToInt(byte b) {
+ if (b >= 0) return b;
+ return 256 + b;
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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<SplitPiece> imagePieces = new ArrayList<SplitPiece>();
+ private final DviResolution res;
+
+ public SplitImageImpl(DviResolution res, DviRectSplitter rectSplitter) {
+ this.res = res;
+ this.rectSplitter = rectSplitter;
+ }
+
+ public Collection<SplitPiece> getPieces() throws DviException {
+ return Collections.unmodifiableCollection(imagePieces);
+ }
+
+ public DviRectSplitter getRectSplitter() throws DviException {
+ return rectSplitter;
+ }
+
+ public Iterator<SplitPiece> 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;
+ }
+}
--- /dev/null
+/*
+ * 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<SplitPiece> pieces = new ArrayList<SplitPiece>();
+
+ 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<SplitPiece> 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<SplitPiece> 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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<SplitPiece>
+{
+ public DviResolution getResolution();
+ public DviRect getRect() throws DviException;
+ public DviRectSplitter getRectSplitter() throws DviException;
+ public Collection<SplitPiece> getPieces() throws DviException;
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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<SplitPiece> pieces = new ArrayList<SplitPiece>();
+ 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<SplitPiece> getPieces() throws DviException {
+ return Collections.unmodifiableCollection(pieces);
+ }
+
+ public DviRectSplitter getRectSplitter() throws DviException {
+ return rectSplitter;
+ }
+
+ public Iterator<SplitPiece> 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<rows; i++) {
+ for (int j=0; j<cols; j++) {
+ String entryName = props.getProperty("image.piece." + i + "." + j + ".file");
+ ZipImagePiece piece = new ZipImagePiece(splitImage, file, entryName, res, rectSplitter, i, j);
+ splitImage.pieces.add(piece);
+ }
+ }
+ }
+ return splitImage;
+ } else {
+ throw new DviException("Unrecognized format " + fmt + " in index file: " + indexEntryName + " of " + file.getAbsolutePath());
+ }
+ } finally {
+ zipFile.close();
+ }
+ } catch (MalformedURLException e) {
+ DviUtils.logStackTrace(LOGGER, Level.WARNING, e);
+ throw new DviException(e);
+ } catch (IOException e) {
+ DviUtils.logStackTrace(LOGGER, Level.WARNING, e);
+ throw new DviException(e);
+ }
+ }
+
+ public File getFile() {
+ return file;
+ }
+}
--- /dev/null
+/*
+ * 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.awt.image.RenderedImage;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+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 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;
+import jp.sourceforge.dvibrowser.dvicore.util.DviUtils;
+import jp.sourceforge.dvibrowser.dvicore.util.ZipBuilder;
+
+
+public class ZipSplitImageWriter implements SplitImageWriter {
+ private static final Logger LOGGER = Logger
+ .getLogger(ZipSplitImageWriter.class.getName());
+
+ private static class SplitImageImpl implements SplitImage {
+ private final DviRectSplitter rectSplitter;
+ private final DviResolution res;
+ private final ArrayList<SplitPiece> imagePieces = new ArrayList<SplitPiece>();
+
+ public SplitImageImpl(DviResolution res, DviRectSplitter rectSplitter) {
+ this.res = res;
+ this.rectSplitter = rectSplitter;
+ }
+
+ public DviResolution getResolution()
+ {
+ return res;
+ }
+
+ public Collection<SplitPiece> getPieces() throws DviException {
+ return Collections.unmodifiableCollection(imagePieces);
+ }
+
+ public DviRectSplitter getRectSplitter() throws DviException {
+ return rectSplitter;
+ }
+
+ public Iterator<SplitPiece> 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("<html><body><table cellpadding='0' cellspacing='0' border='0'>");
+ 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("<tr>");
+ closingTag = "</tr>";
+ }
+ pw.printf("<td>", scale);
+ pw.printf("<img src='%s' alt='' galleryimg='no' style='width: %dpx; height: %dpx;' /></span>", filename, w, h);
+ pw.printf("</td>");
+ }
+ }
+ pw.print(closingTag);
+ pw.print("</table></body></html>");
+ 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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--;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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<String> list = new ArrayList<String>();
+ list.add("cygpath");
+ list.add("-w");
+ list.add(posixPath);
+ cs.setCommandLine(list);
+ final ArrayList<String> outputs = new ArrayList<String>();
+ 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;
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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<StackItem> stack = new Stack<StackItem>();
+
+ 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;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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<DviRegister> stack = new Stack<DviRegister>();
+ 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);
+ }
+}
--- /dev/null
+/*
+ * 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<buf.length; i++)
+ buf[i] = (byte) c;
+ }
+
+ public int getPixel(int x, int y)
+ {
+ 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 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<height; i++) {
+ StringBuilder sb = new StringBuilder();
+ for (int j=0; j<width; j++) {
+ if (0 != getPixel(j, i))
+ sb.append("*");
+ else
+ sb.append(".");
+ }
+ System.out.println(sb.toString());
+ }
+ }
+
+
+
+ public BinaryDevice getBinaryDevice(DviResolution res)
+ {
+ return new BinaryDeviceImpl(res);
+ }
+
+ // TDOO: make this a static class
+ public final class BinaryDeviceImpl
+ extends AbstractDevice
+ implements BinaryDevice
+ {
+ private BinaryDeviceImpl(DviResolution res) {
+ super(res);
+ }
+
+ public DviRect getBounds() {
+ return new DviRect(-point.x, -point.y, width, height);
+ }
+
+ public void begin() {
+ }
+ public void end() {
+ }
+
+ private int w;
+// private int h;
+ private int y;
+ private byte [] l_buf;
+ private int xx;
+ public boolean beginRaster(int w, int h) {
+ this.w = w;
+// this.h = h;
+ l_buf = new byte [(w + 7) >>> 3];
+ y = 0;
+ return true;
+ }
+ public void endRaster() {
+ }
+
+ public void beginLine() {
+ for (int i=0; i<l_buf.length; i++) l_buf[i] = 0;
+ xx = 0;
+ }
+ public void endLine(int repeat) {
+ for (int i=0; i<=repeat; i++) {
+ for (int j=0; j<w; j++) {
+ int bit = l_buf[(j >>> 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;
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.
+ }
+}
--- /dev/null
+/*
+ * 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<height; i++) {
+ int p = p0;
+ for (int j=0; j<width; j++) {
+ buf[p++] = r;
+ buf[p++] = g;
+ buf[p++] = b;
+ }
+ p0 += pitch;
+ }
+ }
+
+ public ImageDevice getImageDevice(DviResolution res)
+ {
+ return new ImageDeviceImpl(res);
+ }
+
+ // TODO: make this static
+ private class ImageDeviceImpl
+ extends AbstractDevice
+ implements ImageDevice
+ {
+ protected ImageDeviceImpl(DviResolution res) {
+ super(res);
+ }
+
+ public DviRect getBounds() {
+ return new DviRect(-point.x, -point.y, width, height);
+ }
+
+ private final AlphaCache alphaCache = new AlphaCache();
+ public void begin(int maxval) {
+ alphaCache.setMaxValue(maxval);
+ }
+ public void end() {
+ }
+
+ private int ptr = 0;
+// private int gw;
+// private int gh;
+ public boolean beginImage(int w, int h)
+ throws DviException
+ {
+// gw = w;
+// gh = h;
+ ptr = 3 * point.x + point.y * pitch;
+ return true;
+ }
+ public void endImage() {
+ }
+
+ public void putLine(int [] l_buf, int off, int len)
+ throws DviException
+ {
+ final int color = getColor().toIntRGB();
+ final byte r = (byte) (color >>> 16);
+ final byte g = (byte) (color >>> 8);
+ final byte b = (byte) (color >>> 0);
+ int p = ptr;
+ for (int i=0; i<len; i++) {
+ final int alpha10 = alphaCache.get(l_buf[off + i]);
+ if (alpha10 != 0) {
+ buf[p+0] = blend(buf[p+0], r, alpha10);
+ buf[p+1] = blend(buf[p+1], g, alpha10);
+ buf[p+2] = blend(buf[p+2], b, alpha10);
+ }
+ p += 3;
+ }
+ ptr += pitch;
+ }
+ }
+
+ private static class AlphaCache
+ {
+ private final int [] table = new int[1024];
+ private int maxval;
+ private boolean canLookUp;
+ private double gamma = 0.90;
+ private AlphaCache() {}
+
+ /*
+ private void setGamma(double gamma) {
+ this.gamma = Math.max(0.0, gamma);
+ }
+ */
+
+ private void setMaxValue(int maxval) {
+ if (this.maxval == maxval) return;
+ this.maxval = maxval;
+ if (maxval < 1024) {
+ for (int i=0; i<=maxval; i++)
+ table[i] = alpha10Internal(i);
+ canLookUp = true;
+ } else {
+ canLookUp = false;
+ }
+ }
+
+ private int get(int c) {
+ if (!canLookUp || c < 0 || maxval < c)
+ return alpha10Internal(c);
+ else
+ return table[c];
+ }
+
+ private int alpha10Internal(int c) {
+ return (int) (1024 * Math.pow((double) c / maxval, gamma) + 0.5);
+ }
+ }
+
+ private static byte blend(final byte _c1, final byte _c2, final int alpha10)
+ {
+ final int c1 = ((int) _c1) & 0xff;
+ final int c2 = ((int) _c2) & 0xff;
+ return (byte) (c1 + ((alpha10 * (c2 - c1)) >>> 10));
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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<DviColor> colorStack
+ = new java.util.Stack<DviColor>();
+ 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;
+ }
+}
--- /dev/null
+/*
+ * 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 + "]";
+ }
+}
--- /dev/null
+/*
+ * 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<count; i++) {
+ if (paintFlag) {
+ buf += "*";
+ } else {
+ buf += ".";
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.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.DviCommand;
+import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostPost;
+import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostamble;
+import jp.sourceforge.dvibrowser.dvicore.cmd.DviPreamble;
+
+
+
+public class DumpHandler
+implements DviExecutorHandler
+{
+ private DviExecutorContext ctx;
+
+ private final PrintStream out;
+ public DumpHandler(PrintStream out)
+ {
+ this.out = out;
+ if (out == null)
+ throw new NullPointerException("output cannot be null");
+ }
+
+ public void begin(DviExecutorContext ctx) throws DviException {
+ this.ctx = ctx;
+ }
+ public void end() throws DviException {
+ ctx = null;
+ }
+
+ public void doSet(int code) throws DviException {
+ dump("code=" + code);
+ }
+ public void doSetRule(int w, int h) throws DviException {
+ dump("set_rule: w=" + w + " h=" + h);
+ }
+ public void doPut(int code) throws DviException {
+ dump("code=" + code);
+ }
+ public void doPutRule(int w, int h) throws DviException {
+ dump("put_rule: w=" + w + " h=" + h);
+ }
+ public void doNop() throws DviException {
+ dump("");
+ }
+
+ public void doSelectFont(int fn) throws DviException {
+ dump(": fn=" + fn);
+ }
+ public void doDefineFont(int fn, DviFontSpec fs) throws DviException {
+ dump(": fn=" + fn + " fs=" + fs);
+ }
+
+ public void doPush() throws DviException {
+ dump("");
+ }
+ public void doPop() throws DviException {
+ dump("");
+ }
+
+ public void doPre(DviPreamble preamble) throws DviException {
+ dump(preamble.toString());
+ }
+ public void doBop(DviBop bop) throws DviException {
+ dump(bop.toString());
+ }
+ public void doEop() throws DviException {
+ dump("");
+ }
+ public void doPost(DviPostamble postamble) throws DviException {
+ dump(postamble.toString());
+ }
+ public void doPostPost(DviPostPost postPost) throws DviException {
+ dump(postPost.toString());
+ }
+
+ public void doRight(int by) throws DviException {
+ dump("dh=" + by);
+ }
+ public void doW(int by) throws DviException {
+ dump("dh=" + by);
+ }
+ public void doW0() throws DviException {
+ dump("");
+ }
+ public void doX(int by) throws DviException {
+ dump("dh=" + by);
+ }
+ public void doX0() throws DviException {}
+
+ public void doDown(int by) throws DviException {
+ dump("dv=" + by);
+ }
+ public void doY(int by) throws DviException {
+ dump("dv=" + by);
+ }
+ public void doY0() throws DviException {
+ dump("");
+ }
+ public void doZ(int by) throws DviException {
+ dump("dv=" + by);
+ }
+ public void doZ0() throws DviException {
+ dump("");
+ }
+
+ public void doSpecial(byte [] xxx) throws DviException {
+ dump(new String(xxx));
+ }
+
+ private void dump(String msg) {
+ out.println(
+ ctx.getCommandRange().toString()
+ + ": " + DviCommand.getName(ctx.getCommand())
+ + ": " + msg
+ );
+ }
+}
--- /dev/null
+/*
+ * 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.DviRect;
+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.api.Geometer;
+import jp.sourceforge.dvibrowser.dvicore.util.concurrent.Computation;
+
+
+public class DviBoundingBoxPreparator
+extends DviObject
+implements Computation<String, DviRect> {
+ 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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<String, Long> {
+ 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;
+ }
+}
--- /dev/null
+/*
+ * 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 {}
+}
--- /dev/null
+/*
+ * 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 {}
+}
--- /dev/null
+/*
+ * 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 {}
+}
--- /dev/null
+/*
+ * 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<String, LookupTable>
+ cache = new DviCache<String, LookupTable>(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;
+ }
+}
--- /dev/null
+/*
+ * 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<buf.length; i++)
+// buf[i] = 0xff000000 | c;
+ buf[i] = c;
+ }
+
+ public ImageDevice getImageDevice(DviResolution res, GammaCorrector gc) {
+ return new ImageDeviceImpl(res, gc);
+ }
+ public ImageDevice getImageDevice(DviResolution res) {
+ return getImageDevice(res, null);
+ }
+
+ private class ImageDeviceImpl
+ extends AbstractDevice
+ implements ImageDevice
+ {
+ private final GammaCorrector originalGammaCorrector;
+ private GammaCorrector gammaCorrector;
+ private int maxval;
+ protected ImageDeviceImpl(DviResolution res, GammaCorrector gammaCorrector) {
+ super(res);
+ this.originalGammaCorrector = (gammaCorrector == null) ? ViewSpec.getDefaultGammaCorrector() : gammaCorrector;
+ if (originalGammaCorrector == null)
+ throw new IllegalStateException("Unable to determine the gamma corrector.");
+ }
+
+ public DviRect getBounds() {
+ return new DviRect(-point.x, -point.y, width, height);
+ }
+
+ public void begin(int maxval) {
+ this.maxval = maxval;
+ gammaCorrector = GammaCorrectorCache.wrap(originalGammaCorrector);
+ }
+
+ public void end() {
+ }
+
+ private int ptr = 0;
+// private int gw;
+// private int gh;
+ public boolean beginImage(int w, int h)
+ throws DviException
+ {
+// gw = w;
+// gh = h;
+ ptr = point.x + point.y * width;
+ return true;
+ }
+ public void endImage() {
+ }
+
+ public void putLine(int [] l_buf, int off, int len)
+ throws DviException
+ {
+ final int color = getColor().toIntRGB();
+ for (int i=0; i<len; i++) {
+ final int alpha10 = gammaCorrector.correctGamma(l_buf[off + i], maxval);
+ if (alpha10 != 0)
+ buf[ptr + i] = blend(buf[ptr + i], color, alpha10);
+ }
+ ptr += width;
+ }
+ }
+
+ private static int blendARGB(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 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.
--- /dev/null
+/*
+ * 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<s_buf.length; j++)
+ s_buf[j] += l_buf[j + s_sx] * left;
+ flushLine();
+ count -= left;
+ if (count >= sf) {
+ for (int j=0; j<s_buf.length; j++)
+ s_buf[j] = l_buf[j + s_sx] * sf;
+ while (count >= 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<s_buf.length; j++)
+ s_buf[j] += l_buf[j + s_sx] * count;
+ }
+ }
+
+ public void putBits(int count, boolean paintFlag)
+ throws DviException
+ {
+ if (paintFlag) {
+ final int left = sf - xx;
+ if (left <= count) {
+ l_buf[x_pos++] += left;
+ count -= left;
+ while (count >= 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;
+ }
+ */
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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));
+ }
+}
--- /dev/null
+/*
+ * 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; }
+}
--- /dev/null
+/*
+ * 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
+ + "]";
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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<DviByteRange>
+{
+ private static final long serialVersionUID = -5733122326062424799L;
+
+ public ByteRangeSet()
+ {
+ super(
+ new Comparator<DviByteRange>() {
+ 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<DviByteRange> intersect(DviByteRange range)
+ {
+ return subSet(
+ new DviByteRange(range.begin(), range.begin()),
+ new DviByteRange(range.end()+1, range.end()+1)
+ );
+ }
+}
--- /dev/null
+/*
+ * 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<String, DviImage> {
+ 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<String> stderr = new LineBuffer<String>(100);
+ final LineBuffer<String> stdout = new LineBuffer<String>(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;
+ }
+}
--- /dev/null
+/*
+ * 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<String, SplitImage> {
+ 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;
+ }
+}
--- /dev/null
+/*
+ * 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<Prologue> prologues = new Vector<Prologue>();
+ private final Vector<Global> globals = new Vector<Global>();
+ private final HashMap<Integer, Vector<Local>> page2locals
+ = new HashMap<Integer, Vector<Local>>();
+
+ private Vector<Local> locals = null;
+
+ public void beginPage(int pageNum)
+ {
+ if (page2locals.containsKey(pageNum)) {
+ locals = page2locals.get(pageNum);
+ } else {
+ locals = new Vector<Local>();
+ 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<? extends Element> 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<Local> 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"
+ );
+ }
+ }
+}
--- /dev/null
+/*
+ * 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<String, EmbeddedPostScript> {
+ 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;
+ }
+}
--- /dev/null
+/*
+ * 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*<a\\s*href\\s*=\\s*\"(.*)\"\\s*>",
+ Pattern.CASE_INSENSITIVE
+ );
+ private static final Pattern namePat
+ = Pattern.compile(
+ "\\s*html:\\s*<a\\s*name\\s*=\\s*\"(.*)\"\\s*>",
+ Pattern.CASE_INSENSITIVE
+ );
+ private static final Pattern endPat
+ = Pattern.compile(
+ "\\s*html:\\s*</a>",
+ Pattern.CASE_INSENSITIVE
+ );
+
+ public void execute(DviDocument doc)
+ throws DviException
+ {
+ for (int p=0; p<doc.getTotalPages(); p++) {
+ exe.execute(doc.getPage(p));
+ }
+ }
+
+ public AnchorSet getAnchorSet()
+ {
+ return anchorSet;
+ }
+
+ private static class PrivateExecuter
+ extends AbstractDviSpecialExecutor
+ {
+ private final AnchorSet anchorSet;
+ public PrivateExecuter(DviContextSupport dcs, AnchorSet anchorSet) {
+ super(dcs);
+ this.anchorSet = anchorSet;
+ }
+
+ private static class StackItem
+ {
+ private final long start;
+ private final String tag;
+ private final String data;
+ public StackItem(long start, String tag, String data) {
+ this.start = start;
+ this.tag = tag;
+ this.data = data;
+ }
+ }
+
+ private final Stack<StackItem> stack
+ = new Stack<StackItem>();
+
+ 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);
+ }
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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<os.length; i++) {
+ Matcher mat2 = Pattern.compile("([a-z]+)=(-?[.0-9]+)").matcher(os[i]);
+ if (mat2.matches()) {
+ try {
+ String var = mat2.group(1);
+ int val = Integer.parseInt(mat2.group(2));
+ if ("llx".equals(var)) llx = val;
+ if ("lly".equals(var)) lly = val;
+ if ("urx".equals(var)) urx = val;
+ if ("ury".equals(var)) ury = val;
+ if ("rwi".equals(var)) rwi = val;
+ if ("rhi".equals(var)) rhi = val;
+ if ("angle".equals(var)) angle = val;
+ } catch (NumberFormatException ex) {
+ // ignored.
+ }
+ }
+ }
+ DviRegister reg = getGeometerContext().getRegister();
+ eps.add(
+ new EmbeddedPostScript.PSFileSpecial(
+ reg.getH(), reg.getV(),
+ getDviUnit(),
+ fileName,
+ llx, lly, urx, ury, rwi, rhi, angle
+ )
+ );
+ }
+ /* Support other types of specials:
+ } else if (xxx.equals("bk")) {
+ } else if (xxx.equals("fp")) {
+ } else if (xxx.startsWith("pn ")) {
+ } else if (xxx.startsWith("ar ")) {
+ } else if (xxx.startsWith("pa ")) {
+ } else if (xxx.startsWith("dt ")) {
+
+ } else if (xxx.startsWith("em:")) {
+ } else if (xxx.startsWith("HP:")) {
+ */
+
+ }
+
+ private static String trimQuotes(String str) {
+ if (str == null) return null;
+ while (str.startsWith("\"")) {
+ str = str.substring(1);
+ }
+ while (str.endsWith("\"")) {
+ str = str.substring(0, str.length()-1);
+ }
+ return str;
+ }
+}
--- /dev/null
+/*
+ * 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.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.api.DviContextSupport;
+import jp.sourceforge.dvibrowser.dvicore.api.DviDocument;
+
+
+public class SourceSpecialParser
+extends DviObject
+{
+ private static final Logger LOGGER = Logger.getLogger(SourceSpecialParser.class.getName());
+ private final AnchorSet anchorSet = new AnchorSet();
+ private final PrivateExecuter exe;
+
+ public SourceSpecialParser(DviContextSupport dcs)
+ {
+ super(dcs);
+ exe = new PrivateExecuter(dcs, anchorSet);
+ }
+
+ private static final Pattern srcPat
+ = Pattern.compile(
+ "\\s*src:\\s*([-0-9]*)\\s\\s*(.*)\\s*",
+ Pattern.CASE_INSENSITIVE
+ );
+
+ public void execute(DviDocument doc)
+ throws DviException
+ {
+ for (int p=0; p<doc.getTotalPages(); p++) {
+ exe.execute(doc.getPage(p));
+ }
+ }
+
+ public AnchorSet getAnchorSet()
+ {
+ return anchorSet;
+ }
+
+ private static class PrivateExecuter
+ extends AbstractDviSpecialExecutor
+ {
+ private final AnchorSet anchorSet;
+ public PrivateExecuter(DviContextSupport dcs, AnchorSet anchorSet) {
+ super(dcs);
+ this.anchorSet = anchorSet;
+ }
+
+ private static class StackItem
+ {
+ private final long start;
+ private final String tag;
+ private final String data;
+ private final int lineNumber;
+ public StackItem(long start, String tag, String data, int lineNumber) {
+ this.start = start;
+ this.tag = tag;
+ this.data = data;
+ this.lineNumber = lineNumber;
+ }
+ }
+
+ private final Stack<StackItem> stack
+ = new Stack<StackItem>();
+
+ @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());
+ }
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+/*
+ * 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<T>
+{
+ public T canonicalize(T obj);
+}
--- /dev/null
+/*
+ * 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<String> commandLine = new ArrayList<String>();
+
+ public void setCommandLine(String ... commandLine)
+ {
+ ArrayList<String> list = new ArrayList<String>();
+ for (String arg : commandLine) {
+ list.add(arg);
+ }
+ this.commandLine = list;
+ }
+
+ public void setCommandLine(Collection<String> cmdLine)
+ {
+ ArrayList<String> list = new ArrayList<String>();
+ list.addAll(cmdLine);
+ this.commandLine = list;
+ }
+
+ public Collection<String> getCommandLine()
+ {
+ return Collections.unmodifiableCollection(commandLine);
+ }
+
+ private ArrayList<String> envs = null;
+ public void setEnvironment(Collection<String> envs)
+ {
+ if (envs == null) {
+ this.envs = null;
+ return;
+ } else {
+ ArrayList<String> list = new ArrayList<String>();
+ list.addAll(envs);
+ this.envs = list;
+ }
+ }
+
+ public void setEnvironment(String ... envs)
+ {
+ ArrayList<String> list = new ArrayList<String>();
+ for (String arg : envs) {
+ list.add(arg);
+ }
+ this.envs = list;
+ }
+
+ public Collection<String> 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());
+ }
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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<String> stderr = new LineBuffer<String>(100);
+ private final LineBuffer<String> stdout = new LineBuffer<String>(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<String> getStderr() {
+ return stderr.toList();
+ }
+
+ public List<String> getStdout() {
+ return stdout.toList();
+ }
+
+
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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<K, V>
+extends LinkedHashMap<K, V>
+{
+ 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<K, V> 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
--- /dev/null
+/*
+ * 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.");
+ }
+ }
+}
--- /dev/null
+/*
+ * 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<String>
+ {
+ 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<String> plainArgs
+ = new ArrayList<String>();
+
+ private static Option [] options = {
+ new Option("--help", "-h", null, "Show this help"),
+ new Option("--mode", "-m", "mode", "Set mode to <mode>")
+ };
+
+ 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;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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<String, String> getLoginShellEnvPosix() throws IOException, InterruptedException
+ {
+ return getLoginShellEnvPosix(null);
+ }
+
+ public static Map<String, String> 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<String, String> map = new HashMap<String, String>();
+ 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<String, String> env0 = getLoginShellEnvPosix(null);
+ String shell = env0.get("SHELL");
+ if (shell != null) {
+ // We then read the PATH environment variable through the login shell.
+ Map<String, String> 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> 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<String, String> 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<String> list = new ArrayList<String>();
+ 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> 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<String> output, final InputStream is) {
+ addLinesFromStream(output, is, null, Level.SEVERE, null);
+ }
+
+ public static void addLinesFromStream(final List<String> 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<String> list = new ArrayList<String>();
+ 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<String> out = new ArrayList<String>();
+ 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<String> list) {
+ if (list == null) return null;
+ return join(sep, list.toArray(new String[list.size()]));
+ }
+
+ public static void accumulateToLineBuffer(InputStream in,
+ LineBuffer<String> 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();
+ }
+}
--- /dev/null
+/*
+ * 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<T> {
+ public static final int BUFFER_UNLIMITED = -1;
+ private int maxLineNumbers;
+ private final ArrayList<T> list = new ArrayList<T>();
+
+ 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<T> 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();
+ }
+}
--- /dev/null
+/*
+ * 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<T>
+implements Canonicalizer<T>
+{
+ private final Map<T,T> cache = new HashMap<T,T>();
+
+ 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();
+ }
+}
--- /dev/null
+/*
+ * 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("<input filename=\"" + filename + "\">");
+ }
+ public void endInput(Env env) {
+ out.println("</input>");
+ }
+ public void handleUnrecognized(Env env, String str) {
+ out.println("<unrecognized>" + str + "</unrecognized>");
+ }
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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<K, V> implements Computer<K, V> {
+ private static final Logger LOGGER = Logger.getLogger(AbstractComputer.class
+ .getName());
+
+ public abstract ExecutorService getExecutorService(Computation<K, V> computable);
+
+ public Future<V> compute(Computation<K, V> computable)
+ {
+ ExecutorService exe = getExecutorService(computable);
+ final Future<V> future = exe.submit(computable);
+ LOGGER.finer("Scheduled computation " + computable + " to executor service " + exe + " with future object " + future);
+ return future;
+ }
+}
--- /dev/null
+/*
+ * 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<K, V> extends AbstractComputer<K, V> {
+// 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<K, V> computable)
+ {
+ return executorService;
+ }
+}
--- /dev/null
+/*
+ * 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<K, V> {
+// private static final Logger LOGGER = Logger.getLogger(CachedItem.class
+// .getName());
+ private final Computer<K, V> cachedComputer;
+ private final Computation<K, V> computable;
+ private final Future<V> future;
+ private final long serialNumber;
+ private static final AtomicLong serializer = new AtomicLong();
+
+ public CacheEntry(Computer<K, V> cachedComputer, Computation<K, V> computable, Future<V> future)
+ {
+ this.cachedComputer = cachedComputer;
+ this.computable = computable;
+ this.future = future;
+ this.serialNumber = serializer.incrementAndGet();
+ }
+
+ public Computer<K, V> getCachedComputer()
+ {
+ return cachedComputer;
+ }
+
+ public Computation<K, V> getComputable()
+ {
+ return computable;
+ }
+
+ public Future<V> getFuture()
+ {
+ return future;
+ }
+
+ public long getSerialNumber()
+ {
+ return serialNumber;
+ }
+
+ public String toString()
+ {
+ return getClass().getName()
+ + "["
+ + "serialNumber=" + serialNumber
+ + ",key=" + computable.getCacheKey()
+ + ",future=" + future
+ + "]";
+ }
+}
--- /dev/null
+/*
+ * 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> {
+ K getCacheKey();
+}
--- /dev/null
+/*
+ * 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<K, V> implements Computer<K, V>
+{
+ private final class LinkedHashMapExtension extends
+ LinkedHashMap<K, CacheEntry<K, V>> {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected boolean removeEldestEntry(Map.Entry<K,CacheEntry<K, V>> 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<K, CacheEntry<K, V>> map;
+ private final Computer<K, V> computer;
+
+ public CachedComputer(final Computer<K, V> computer)
+ {
+ this.computer = computer;
+ map = Collections.synchronizedMap(createCache());
+ }
+
+ protected Map<K, CacheEntry<K, V>> createCache()
+ {
+ return new LinkedHashMapExtension();
+ }
+
+ protected boolean removeEldestEntry(Map.Entry<K, CacheEntry<K, V>> entry)
+ {
+ return false;
+ }
+
+ protected synchronized Future<V> startComputation(final Computation<K, V> computable)
+ {
+ final Future<V> future = computer.compute(new Computation<K, V>() {
+ 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<V> compute(Computation<K, V> computable)
+ {
+ K key = computable.getCacheKey();
+ if (key == null) {
+ LOGGER.finer("Key is null: " + computable);
+ final Future<V> future = startComputation(computable);
+ return future;
+ }
+ CacheEntry<K, V> cacheEntry = map.get(key);
+ if (cacheEntry == null) {
+ LOGGER.finer("Cache miss: " + key);
+ final Future<V> future = startComputation(computable);
+ cacheEntry = new CacheEntry<K, V>(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<V> getCachedResult(Computation<K, V> computable)
+ {
+ K key = computable.getCacheKey();
+ if (key == null) {
+ return null;
+ }
+ CacheEntry<K, V> cacheEntry = map.get(key);
+ if (cacheEntry == null) {
+ return null;
+ } else {
+ return cacheEntry.getFuture();
+ }
+ }
+
+ public Map<K, CacheEntry<K, V>> getCache()
+ {
+ return map;
+ }
+}
--- /dev/null
+/*
+ * 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<K, V> extends Callable<V>, Cacheable<K>
+{
+}
--- /dev/null
+/*
+ * 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<K, V> {
+ Future<V> compute(Computation<K, V> computable);
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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<K, V> implements Computer<K,V> {
+ private static final Logger LOGGER = Logger.getLogger(ComputerProgressMonitor.class.getName());
+ private final Computer<K, V> computer;
+
+ public ComputerProgressMonitor(Computer<K, V> computer)
+ {
+ this.computer = computer;
+ }
+
+ public Future<V> compute(final Computation<K, V> computation)
+ {
+ final Computation<K, V> wrapper = new Computation<K, V>() {
+ 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<K, V> computation)
+ {
+ LOGGER.finer("computation ended: " + computation);
+ }
+
+ protected void fireComputationBeginEvent(Computation<K, V> computation)
+ {
+ LOGGER.finer("computation started: " + computation);
+ }
+
+ public Computer<K, V> getComputer()
+ {
+ return computer;
+ }
+}
--- /dev/null
+/*
+ * 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<K, V> extends AbstractComputer<K, V> {
+// 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<K, V> computable)
+ {
+ return executorService;
+ }
+}
--- /dev/null
+/*
+ * 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<K, V>
+{
+ 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
--- /dev/null
+/*
+ * 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<K, V> {
+ 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<Map<K, V>> lines = new ArrayList<Map<K, V>>();
+ private final List<K> defaultKeys = new ArrayList<K>();
+ private final CsvCellCodec<K, V> codec;
+
+ public CsvData(CsvCellCodec<K, V> codec)
+ {
+ if (codec == null)
+ throw new IllegalArgumentException("CSV cell codec can't be null");
+ this.codec = codec;
+ }
+
+ private Map<K, V> line;
+
+ public void beginLine()
+ {
+ if (line != null) {
+ throw new IllegalStateException("line is not null: last line is not closed.");
+ }
+
+ line = newLine();
+ }
+
+ protected Map<K, V> newLine() {
+ return new HashMap<K, V>();
+ }
+
+ 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<K, V> map = getRow(row);
+ if (map == null) return null;
+ return map.get(key);
+ }
+
+ public Map<K, V> getRow(int row) {
+ if (row < 0 || getRowCount() <= row) {
+ throw new IllegalArgumentException("Row index out of bounds: " + row);
+ }
+
+ Map<K, V> map = lines.get(row);
+ return map;
+ }
+
+
+ public String [] encodeToCsv()
+ {
+ return encodeToCsv(null);
+ }
+
+ public String [] encodeToCsv(Collection<K> keys)
+ {
+ List<String> csvEncodedLines = new ArrayList<String>();
+
+ if (keys == null) {
+ keys = getDefaultKeys();
+ }
+
+ String q = getQuoteChar();
+ String s = getSeparatorChar();
+
+ {
+ List<String> items = new ArrayList<String>();
+ 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<K, V> csvLine : lines) {
+ List<String> items = new ArrayList<String>();
+ 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<K, V> parser = new CsvParser<K, V>(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<K> getDefaultKeys() {
+ return Collections.unmodifiableList(defaultKeys);
+ }
+
+ public void putAll(Map<K, V> map) {
+ for (Map.Entry<K, V> entry : map.entrySet()) {
+ put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ public int hashCode()
+ {
+ int hashCode = 0;
+
+ final int rows = getRowCount();
+ for (int i=0; i<rows; i++) {
+ Map<?, ?> 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<rows; i++) {
+ Map<?, ?> map1 = cd.getRow(i);
+ Map<?, ?> map2 = getRow(i);
+ if (map1.equals(map2)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * 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<K, V> {
+ private int state = 0;
+ private StringBuilder sb = null;
+ private List<String> line = null;
+ private List<List<String>> lines = new ArrayList<List<String>>();
+
+ public String [][] getData()
+ {
+ int cols=0, rows=lines.size();
+ for (List<String> line : lines) {
+ cols = Math.max(cols, line.size());
+ }
+ String [] [] ret = new String[rows][cols];
+ int i=0;
+ for (List<String> 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<String>();
+ 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
--- /dev/null
+/*
+ * 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<K, V> {
+ private static final Logger LOGGER = Logger.getLogger(CsvParser.class
+ .getName());
+ private final CsvCellCodec<K, V> codec;
+ private CsvLineParser<K, V> lineParser;
+ private final CsvData<K, V> csvData;
+
+ public CsvParser(CsvCellCodec<K, V> codec, CsvData<K, V> csvData) {
+ this.codec = codec;
+ this.csvData = csvData;
+ this.lineParser = new CsvLineParser<K, V>();
+ }
+
+ 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<K> keys = new ArrayList<K>();
+ 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");
+ }
+ }
+}
--- /dev/null
+/*
+ * 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<String, String>
+{
+ 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
--- /dev/null
+/*
+ * 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<String, String>
+{
+ public StringCsvData()
+ {
+ super(new StringCsvCellCodec());
+ }
+
+ public StringCsvData(CsvCellCodec<String, String> codec)
+ {
+ super(codec);
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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(); }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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)
+ {
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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<ManagedProgressItem> list = new ArrayList<ManagedProgressItem>();
+ 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<ManagedProgressItem> 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<ProgressItem> items = new ArrayList<ProgressItem>();
+ synchronized(list) {
+ for (ManagedProgressItem wrappedItem : list) {
+ if (wrappedItem.isOpen())
+ items.add(wrappedItem.getOriginalItem());
+ }
+ }
+ return items.toArray(new ProgressItem[items.size()]);
+ }
+
+ public ProgressItem [] getItems()
+ {
+ ArrayList<ProgressItem> items = new ArrayList<ProgressItem>();
+ synchronized(list) {
+ for (ManagedProgressItem wrappedItem : list) {
+ items.add(wrappedItem.getOriginalItem());
+ }
+ }
+ return items.toArray(new ProgressItem[items.size()]);
+ }
+}
--- /dev/null
+/*
+ * 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<ProgressRecorder> recorders = new ArrayList<ProgressRecorder>();
+
+ 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<ProgressItem> list = new ArrayList<ProgressItem>();
+ 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<ProgressItem>() {
+ 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());
+ }
+}