From 72906f5910f552b0d2636c5d4759c36c10f6e6b7 Mon Sep 17 00:00:00 2001 From: parrt Date: Sat, 22 Oct 2011 11:22:22 -0800 Subject: [PATCH] add font metrics to gen PS properly [git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9152] --- .../src/org/antlr/v4/runtime/tree/Trees.java | 4 + .../org/antlr/v4/runtime/tree/gui/Arial.java | 131 ++++++++++++++ .../antlr/v4/runtime/tree/gui/ArialBlack.java | 131 ++++++++++++++ .../antlr/v4/runtime/tree/gui/CourierNew.java | 37 ++++ .../v4/runtime/tree/gui/FontMetrics.java | 89 +++++++++ .../runtime/tree/gui/PostScriptDocument.java | 159 ++++++++++++++++ .../v4/runtime/tree/gui/TimesNewRoman.java | 131 ++++++++++++++ .../tree/gui/TreePostScriptGenerator.java | 169 ++++++++++++++++++ .../antlr/v4/runtime/tree/gui/TreeViewer.java | 9 +- 9 files changed, 854 insertions(+), 6 deletions(-) create mode 100644 runtime/Java/src/org/antlr/v4/runtime/tree/gui/Arial.java create mode 100644 runtime/Java/src/org/antlr/v4/runtime/tree/gui/ArialBlack.java create mode 100644 runtime/Java/src/org/antlr/v4/runtime/tree/gui/CourierNew.java create mode 100644 runtime/Java/src/org/antlr/v4/runtime/tree/gui/FontMetrics.java create mode 100644 runtime/Java/src/org/antlr/v4/runtime/tree/gui/PostScriptDocument.java create mode 100644 runtime/Java/src/org/antlr/v4/runtime/tree/gui/TimesNewRoman.java create mode 100644 runtime/Java/src/org/antlr/v4/runtime/tree/gui/TreePostScriptGenerator.java diff --git a/runtime/Java/src/org/antlr/v4/runtime/tree/Trees.java b/runtime/Java/src/org/antlr/v4/runtime/tree/Trees.java index 90a5b4bd8..23eb75d4f 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/tree/Trees.java +++ b/runtime/Java/src/org/antlr/v4/runtime/tree/Trees.java @@ -68,6 +68,10 @@ public class Trees { return tok.getText(); } } + Object payload = t.getPayload(); + if ( payload instanceof Token ) { + return ((Token)payload).getText(); + } return t.getPayload().toString(); } diff --git a/runtime/Java/src/org/antlr/v4/runtime/tree/gui/Arial.java b/runtime/Java/src/org/antlr/v4/runtime/tree/gui/Arial.java new file mode 100644 index 000000000..0ab876fb9 --- /dev/null +++ b/runtime/Java/src/org/antlr/v4/runtime/tree/gui/Arial.java @@ -0,0 +1,131 @@ +/* + [The "BSD license"] + Copyright (c) 2011 Terence Parr + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.antlr.v4.runtime.tree.gui; + +public class Arial extends FontMetrics { + { + maxCharHeight = 781; + widths[32] = 277; // space + widths[33] = 277; // exclam + widths[34] = 354; // quotedbl + widths[35] = 556; // numbersign + widths[36] = 556; // dollar + widths[37] = 889; // percent + widths[38] = 666; // ampersand + widths[39] = 190; // quotesingle + widths[40] = 333; // parenleft + widths[41] = 333; // parenright + widths[42] = 389; // asterisk + widths[43] = 583; // plus + widths[44] = 277; // comma + widths[45] = 333; // hyphen + widths[46] = 277; // period + widths[47] = 277; // slash + widths[48] = 556; // zero + widths[49] = 556; // one + widths[50] = 556; // two + widths[51] = 556; // three + widths[52] = 556; // four + widths[53] = 556; // five + widths[54] = 556; // six + widths[55] = 556; // seven + widths[56] = 556; // eight + widths[57] = 556; // nine + widths[58] = 277; // colon + widths[59] = 277; // semicolon + widths[60] = 583; // less + widths[61] = 583; // equal + widths[62] = 583; // greater + widths[63] = 556; // question + widths[64] = 1015; // at + widths[65] = 666; // A + widths[66] = 666; // B + widths[67] = 722; // C + widths[68] = 722; // D + widths[69] = 666; // E + widths[70] = 610; // F + widths[71] = 777; // G + widths[72] = 722; // H + widths[73] = 277; // I + widths[74] = 500; // J + widths[75] = 666; // K + widths[76] = 556; // L + widths[77] = 833; // M + widths[78] = 722; // N + widths[79] = 777; // O + widths[80] = 666; // P + widths[81] = 777; // Q + widths[82] = 722; // R + widths[83] = 666; // S + widths[84] = 610; // T + widths[85] = 722; // U + widths[86] = 666; // V + widths[87] = 943; // W + widths[88] = 666; // X + widths[89] = 666; // Y + widths[90] = 610; // Z + widths[91] = 277; // bracketleft + widths[92] = 277; // backslash + widths[93] = 277; // bracketright + widths[94] = 469; // asciicircum + widths[95] = 556; // underscore + widths[96] = 333; // grave + widths[97] = 556; // a + widths[98] = 556; // b + widths[99] = 500; // c + widths[100] = 556; // d + widths[101] = 556; // e + widths[102] = 277; // f + widths[103] = 556; // g + widths[104] = 556; // h + widths[105] = 222; // i + widths[106] = 222; // j + widths[107] = 500; // k + widths[108] = 222; // l + widths[109] = 833; // m + widths[110] = 556; // n + widths[111] = 556; // o + widths[112] = 556; // p + widths[113] = 556; // q + widths[114] = 333; // r + widths[115] = 500; // s + widths[116] = 277; // t + widths[117] = 556; // u + widths[118] = 500; // v + widths[119] = 722; // w + widths[120] = 500; // x + widths[121] = 500; // y + widths[122] = 500; // z + widths[123] = 333; // braceleft + widths[124] = 259; // bar + widths[125] = 333; // braceright + widths[126] = 583; // asciitilde + } +} \ No newline at end of file diff --git a/runtime/Java/src/org/antlr/v4/runtime/tree/gui/ArialBlack.java b/runtime/Java/src/org/antlr/v4/runtime/tree/gui/ArialBlack.java new file mode 100644 index 000000000..d3069ef8b --- /dev/null +++ b/runtime/Java/src/org/antlr/v4/runtime/tree/gui/ArialBlack.java @@ -0,0 +1,131 @@ +/* + [The "BSD license"] + Copyright (c) 2011 Terence Parr + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.antlr.v4.runtime.tree.gui; + +public class ArialBlack extends FontMetrics { + { + maxCharHeight = 770; + widths[32] = 333; // space + widths[33] = 333; // exclam + widths[34] = 500; // quotedbl + widths[35] = 660; // numbersign + widths[36] = 666; // dollar + widths[37] = 1000; // percent + widths[38] = 889; // ampersand + widths[39] = 277; // quotesingle + widths[40] = 389; // parenleft + widths[41] = 389; // parenright + widths[42] = 556; // asterisk + widths[43] = 660; // plus + widths[44] = 333; // comma + widths[45] = 333; // hyphen + widths[46] = 333; // period + widths[47] = 277; // slash + widths[48] = 666; // zero + widths[49] = 666; // one + widths[50] = 666; // two + widths[51] = 666; // three + widths[52] = 666; // four + widths[53] = 666; // five + widths[54] = 666; // six + widths[55] = 666; // seven + widths[56] = 666; // eight + widths[57] = 666; // nine + widths[58] = 333; // colon + widths[59] = 333; // semicolon + widths[60] = 660; // less + widths[61] = 660; // equal + widths[62] = 660; // greater + widths[63] = 610; // question + widths[64] = 740; // at + widths[65] = 777; // A + widths[66] = 777; // B + widths[67] = 777; // C + widths[68] = 777; // D + widths[69] = 722; // E + widths[70] = 666; // F + widths[71] = 833; // G + widths[72] = 833; // H + widths[73] = 389; // I + widths[74] = 666; // J + widths[75] = 833; // K + widths[76] = 666; // L + widths[77] = 943; // M + widths[78] = 833; // N + widths[79] = 833; // O + widths[80] = 722; // P + widths[81] = 833; // Q + widths[82] = 777; // R + widths[83] = 722; // S + widths[84] = 722; // T + widths[85] = 833; // U + widths[86] = 777; // V + widths[87] = 1000; // W + widths[88] = 777; // X + widths[89] = 777; // Y + widths[90] = 722; // Z + widths[91] = 389; // bracketleft + widths[92] = 277; // backslash + widths[93] = 389; // bracketright + widths[94] = 660; // asciicircum + widths[95] = 500; // underscore + widths[96] = 333; // grave + widths[97] = 666; // a + widths[98] = 666; // b + widths[99] = 666; // c + widths[100] = 666; // d + widths[101] = 666; // e + widths[102] = 389; // f + widths[103] = 666; // g + widths[104] = 666; // h + widths[105] = 333; // i + widths[106] = 333; // j + widths[107] = 666; // k + widths[108] = 333; // l + widths[109] = 1000; // m + widths[110] = 666; // n + widths[111] = 666; // o + widths[112] = 666; // p + widths[113] = 666; // q + widths[114] = 443; // r + widths[115] = 610; // s + widths[116] = 443; // t + widths[117] = 666; // u + widths[118] = 610; // v + widths[119] = 943; // w + widths[120] = 666; // x + widths[121] = 610; // y + widths[122] = 556; // z + widths[123] = 389; // braceleft + widths[124] = 277; // bar + widths[125] = 389; // braceright + widths[126] = 660; // asciitilde + } +} \ No newline at end of file diff --git a/runtime/Java/src/org/antlr/v4/runtime/tree/gui/CourierNew.java b/runtime/Java/src/org/antlr/v4/runtime/tree/gui/CourierNew.java new file mode 100644 index 000000000..b4dc5ad14 --- /dev/null +++ b/runtime/Java/src/org/antlr/v4/runtime/tree/gui/CourierNew.java @@ -0,0 +1,37 @@ +/* + [The "BSD license"] + Copyright (c) 2011 Terence Parr + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.antlr.v4.runtime.tree.gui; + +public class CourierNew extends FontMetrics { + { + maxCharHeight = 678; + for (int i=0; i<128; i++) widths[i] = 600; + } +} diff --git a/runtime/Java/src/org/antlr/v4/runtime/tree/gui/FontMetrics.java b/runtime/Java/src/org/antlr/v4/runtime/tree/gui/FontMetrics.java new file mode 100644 index 000000000..054beb162 --- /dev/null +++ b/runtime/Java/src/org/antlr/v4/runtime/tree/gui/FontMetrics.java @@ -0,0 +1,89 @@ +/* + [The "BSD license"] + Copyright (c) 2011 Terence Parr + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.antlr.v4.runtime.tree.gui; + +/** Font metrics. The only way to generate accurate images + * in any format that contain text is to know the font metrics. + * Specifically, we need to know the width of every character and the + * maximum height (since we want all characters to fit within same line height). + * I used ttf2tfm to dump the font metrics from Mac TrueType fonts and + * then converted that to a Java class for use in a PostScript generator + * for trees. Commands: + * + * $ ttf2tfm /Library/Fonts/Arial\ Black.ttf > metrics + * + * Then run metrics into python code after stripping header/footer: + * + # + # Process lines from ttf2tfm that look like this: + # Glyph Code Glyph Name Width llx lly urx ury + # ------------------------------------------------------------------------ + # 3 00020 space 333 0, 0 -- 0, 0 + # + lines = open("metrics").read().split('\n') + print "public class FontName {" + print " public static int[] widths = new int[128];" + print " static {" + maxh = 0; + for line in lines: + all = line.split(' ') + words = [x for x in all if len(x)>0] + ascii = int(words[1], 16) + height = int(words[8]) + if height>maxh: maxh = height + if ascii>=128: break + print " widths[%d] = %s; // %s" % (ascii, words[3], words[2]) + + print " }" + print " public static int MAX_CHAR_HEIGHT = "+str(maxh)+";" + print "}" + + Units are 1000th of an 'em'. + */ +public abstract class FontMetrics { + protected int maxCharHeight; + protected int[] widths = new int[128]; + + public double getWidth(String s, int fontSize) { + double w = 0; + for (char c : s.toCharArray()) { + w += getWidth(c, fontSize); + } + return w; + } + + public double getWidth(char c, int fontSize) { + return widths[c]/1000.0 * fontSize; + } + + public double getLineHeight(int fontSize) { + return maxCharHeight / 1000.0 * fontSize; + } +} diff --git a/runtime/Java/src/org/antlr/v4/runtime/tree/gui/PostScriptDocument.java b/runtime/Java/src/org/antlr/v4/runtime/tree/gui/PostScriptDocument.java new file mode 100644 index 000000000..2d930a9a3 --- /dev/null +++ b/runtime/Java/src/org/antlr/v4/runtime/tree/gui/PostScriptDocument.java @@ -0,0 +1,159 @@ +/* + [The "BSD license"] + Copyright (c) 2011 Terence Parr + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.antlr.v4.runtime.tree.gui; + +public class PostScriptDocument { + protected int boundingBoxWidth; + protected int boundingBoxHeight; + + protected FontMetrics fontMetrics; + protected String fontName; + protected int fontSize = 12; + protected double lineWidth = 0.3; + + protected StringBuilder ps = new StringBuilder(); + protected boolean closed = false; + + public PostScriptDocument() { + this("CourierNew", 12); + } + + public PostScriptDocument(String fontName, int fontSize) { + header(); + setFont(fontName, fontSize); + } + + public String getPS() { close(); return ps.toString(); } + + public void boundingBox(int w, int h) { + boundingBoxWidth = w; + boundingBoxHeight = h; + ps.append(String.format("%%%%BoundingBox: %d %d %d %d\n", 0,0, + boundingBoxWidth,boundingBoxHeight)); + } + + public void close() { + if ( closed ) return; + ps.append("showpage\n"); + ps.append("%%Trailer\n"); + closed = true; + } + + protected void header() { + ps.append("%!PS-Adobe-3.0 EPSF-3.0\n"); + ps.append("%%BoundingBox: (atend)\n"); + lineWidth(0.3); + ps.append("%\n"); + ps.append("% x y rarrow\n"); + ps.append("%\n"); + ps.append("/rarrow {\n"); + ps.append(" moveto\n"); + ps.append(" -3 +2 rlineto\n"); + ps.append(" 0 -4 rlineto\n"); + ps.append(" 3 +2 rlineto\n"); + ps.append(" fill\n"); + ps.append("} def\n"); + ps.append("%\n"); + ps.append("% x y darrow\n"); + ps.append("%\n"); + ps.append("/darrow {\n"); + ps.append(" moveto\n"); + ps.append(" -2 +3 rlineto\n"); + ps.append(" 4 0 rlineto\n"); + ps.append(" -2 -3 rlineto\n"); + ps.append(" fill\n"); + ps.append("} def\n"); + } + + // Courier, Helvetica, Times, ... should be available + public void setFont(String fontName, int fontSize) { + this.fontName = fontName; + this.fontSize = fontSize; + try { + Class c = Class.forName("org.antlr.v4.runtime.tree.gui." + fontName); + this.fontMetrics = (FontMetrics)c.newInstance(); + } + catch (Exception e) { + throw new UnsupportedOperationException("No font metrics for "+fontName); + } + ps.append(String.format("/%s findfont\n%d scalefont setfont\n", fontName, fontSize)); + } + + public void lineWidth(double w) { + lineWidth = w; + ps.append(w+" setlinewidth\n"); + } + + public void move(double x, double y) { + ps.append(String.format("%1.3f %1.3f moveto\n", x, y)); + } + + public void lineto(double x, double y) { + ps.append(String.format("%1.3f %1.3f lineto\n", x, y)); + } + + public void line(double x1, double y1, double x2, double y2) { + move(x1, y1); + lineto(x2, y2); + } + + public void rect(double x, double y, double width, double height) { + line(x, y, x, y + height); + line(x, y + height, x + width, y + height); + line(x + width, y + height, x + width, y); + line(x + width, y, x, y); + } + + public void stroke() { + ps.append("stroke\n"); + } + + public void rarrow(double x, double y) { + ps.append(String.format("%1.3f %1.3f rarrow\n", x,y)); + } + + public void darrow(double x, double y) { + ps.append(String.format("%1.3f %1.3f darrow\n", x,y)); + } + + public void text(String s, double x, double y) { + move(x,y); + ps.append(String.format("(%s) show\n", s)); + stroke(); + } + + // courier new: wid/hei 7.611979 10.0625 + /** All chars are 600 thousands of an 'em' wide if courier */ + public double getWidth(char c) { return fontMetrics.getWidth(c, fontSize); } + public double getWidth(String s) { return fontMetrics.getWidth(s, fontSize); } + public double getLineHeight() { return fontMetrics.getLineHeight(fontSize); } + + public int getFontSize() { return fontSize; } +} diff --git a/runtime/Java/src/org/antlr/v4/runtime/tree/gui/TimesNewRoman.java b/runtime/Java/src/org/antlr/v4/runtime/tree/gui/TimesNewRoman.java new file mode 100644 index 000000000..52c18d281 --- /dev/null +++ b/runtime/Java/src/org/antlr/v4/runtime/tree/gui/TimesNewRoman.java @@ -0,0 +1,131 @@ +/* + [The "BSD license"] + Copyright (c) 2011 Terence Parr + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.antlr.v4.runtime.tree.gui; + +public class TimesNewRoman extends FontMetrics { + { + maxCharHeight = 717; + widths[32] = 250; // space + widths[33] = 333; // exclam + widths[34] = 408; // quotedbl + widths[35] = 500; // numbersign + widths[36] = 500; // dollar + widths[37] = 833; // percent + widths[38] = 777; // ampersand + widths[39] = 180; // quotesingle + widths[40] = 333; // parenleft + widths[41] = 333; // parenright + widths[42] = 500; // asterisk + widths[43] = 563; // plus + widths[44] = 250; // comma + widths[45] = 333; // hyphen + widths[46] = 250; // period + widths[47] = 277; // slash + widths[48] = 500; // zero + widths[49] = 500; // one + widths[50] = 500; // two + widths[51] = 500; // three + widths[52] = 500; // four + widths[53] = 500; // five + widths[54] = 500; // six + widths[55] = 500; // seven + widths[56] = 500; // eight + widths[57] = 500; // nine + widths[58] = 277; // colon + widths[59] = 277; // semicolon + widths[60] = 563; // less + widths[61] = 563; // equal + widths[62] = 563; // greater + widths[63] = 443; // question + widths[64] = 920; // at + widths[65] = 722; // A + widths[66] = 666; // B + widths[67] = 666; // C + widths[68] = 722; // D + widths[69] = 610; // E + widths[70] = 556; // F + widths[71] = 722; // G + widths[72] = 722; // H + widths[73] = 333; // I + widths[74] = 389; // J + widths[75] = 722; // K + widths[76] = 610; // L + widths[77] = 889; // M + widths[78] = 722; // N + widths[79] = 722; // O + widths[80] = 556; // P + widths[81] = 722; // Q + widths[82] = 666; // R + widths[83] = 556; // S + widths[84] = 610; // T + widths[85] = 722; // U + widths[86] = 722; // V + widths[87] = 943; // W + widths[88] = 722; // X + widths[89] = 722; // Y + widths[90] = 610; // Z + widths[91] = 333; // bracketleft + widths[92] = 277; // backslash + widths[93] = 333; // bracketright + widths[94] = 469; // asciicircum + widths[95] = 500; // underscore + widths[96] = 333; // grave + widths[97] = 443; // a + widths[98] = 500; // b + widths[99] = 443; // c + widths[100] = 500; // d + widths[101] = 443; // e + widths[102] = 333; // f + widths[103] = 500; // g + widths[104] = 500; // h + widths[105] = 277; // i + widths[106] = 277; // j + widths[107] = 500; // k + widths[108] = 277; // l + widths[109] = 777; // m + widths[110] = 500; // n + widths[111] = 500; // o + widths[112] = 500; // p + widths[113] = 500; // q + widths[114] = 333; // r + widths[115] = 389; // s + widths[116] = 277; // t + widths[117] = 500; // u + widths[118] = 500; // v + widths[119] = 722; // w + widths[120] = 500; // x + widths[121] = 500; // y + widths[122] = 443; // z + widths[123] = 479; // braceleft + widths[124] = 200; // bar + widths[125] = 479; // braceright + widths[126] = 541; // asciitilde + } +} \ No newline at end of file diff --git a/runtime/Java/src/org/antlr/v4/runtime/tree/gui/TreePostScriptGenerator.java b/runtime/Java/src/org/antlr/v4/runtime/tree/gui/TreePostScriptGenerator.java new file mode 100644 index 000000000..6876bf521 --- /dev/null +++ b/runtime/Java/src/org/antlr/v4/runtime/tree/gui/TreePostScriptGenerator.java @@ -0,0 +1,169 @@ +/* + [The "BSD license"] + Copyright (c) 2011 Terence Parr + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.antlr.v4.runtime.tree.gui; + +import org.abego.treelayout.*; +import org.abego.treelayout.util.DefaultConfiguration; +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.tree.*; + +import java.awt.*; +import java.awt.geom.Rectangle2D; + +public class TreePostScriptGenerator { + public class VariableExtentProvide implements NodeExtentProvider { + @Override + public double getWidth(Tree tree) { + String s = getText(tree); + return doc.getWidth(s) + nodeWidthPadding*2; + } + + @Override + public double getHeight(Tree tree) { + String s = getText(tree); + double h = doc.getLineHeight() + nodeHeightPadding*2; + String[] lines = s.split("\n"); + return h * lines.length; + } + } + + protected double gapBetweenLevels = 30; + protected double gapBetweenNodes = 10; + protected int nodeWidthPadding = 1; // added to left/right + protected int nodeHeightPadding = 1; // added above/below + + protected Tree root; + protected TreeTextProvider treeTextProvider; + protected TreeLayout treeLayout; + + protected PostScriptDocument doc; + + public TreePostScriptGenerator(BaseRecognizer parser, Tree root) { + this(parser, root, "CourierNew", 11); + } + + public TreePostScriptGenerator(BaseRecognizer parser, Tree root, + String fontName, int fontSize) + { + this.root = root; + setTreeTextProvider(new TreeViewer.DefaultTreeTextProvider(parser)); + doc = new PostScriptDocument(fontName, fontSize); + this.treeLayout = + new TreeLayout(new TreeLayoutAdaptor(root), + new VariableExtentProvide(), + new DefaultConfiguration(gapBetweenLevels, + gapBetweenNodes, + Configuration.Location.Bottom)); + } + + public String getPS() { + // generate the edges and boxes (with text) + generateEdges(getTree().getRoot()); + for (Tree textInBox : treeLayout.getNodeBounds().keySet()) { + generateNode(textInBox); + } + + Dimension size = treeLayout.getBounds().getBounds().getSize(); + doc.boundingBox(size.width, size.height); + doc.close(); + return doc.getPS(); + } + + protected void generateEdges(Tree parent) { + if (!getTree().isLeaf(parent)) { + Rectangle2D.Double parentBounds = getBoundsOfNode(parent); + System.out.println("%% parent("+getText(parent)+")="+parentBounds); + double x1 = parentBounds.getCenterX(); + double y1 = parentBounds.y; + for (Tree child : getChildren(parent)) { + Rectangle2D.Double childBounds = getBoundsOfNode(child); + System.out.println("%% child("+getText(child)+")="+childBounds); + double x2 = childBounds.getCenterX(); + double y2 = childBounds.getMaxY(); + doc.line(x1, y1, x2, y2); + generateEdges(child); + } + } + } + + protected void generateNode(Tree t) { + // draw the text on top of the box (possibly multiple lines) + String[] lines = getText(t).split("\n"); + Rectangle2D.Double box = getBoundsOfNode(t); + // for debugging, turn this on to see boundingbox of nodes + // doc.rect(box.x, box.y, box.width, box.height); + double x = box.x+nodeWidthPadding; + double y = box.y+nodeHeightPadding; + for (int i = 0; i < lines.length; i++) { + doc.text(lines[i], x, y); + y += doc.getFontSize(); + } + } + + protected TreeForTreeLayout getTree() { + return treeLayout.getTree(); + } + + protected Iterable getChildren(Tree parent) { + return getTree().getChildren(parent); + } + + protected Rectangle2D.Double getBoundsOfNode(Tree node) { + return treeLayout.getNodeBounds().get(node); + } + + protected String getText(Tree tree) { + return treeTextProvider.getText(tree); + } + + public TreeTextProvider getTreeTextProvider() { + return treeTextProvider; + } + + public void setTreeTextProvider(TreeTextProvider treeTextProvider) { + this.treeTextProvider = treeTextProvider; + } + + public static void main(String[] args) { + CommonAST t = new CommonAST(new CommonToken(1, "+")); + CommonAST a = new CommonAST(new CommonToken(1, "expression")); + CommonAST f = new CommonAST(new CommonToken(1, "3000")); + CommonAST b = new CommonAST(new CommonToken(1, "*")); + CommonAST c = new CommonAST(new CommonToken(1, "42")); + CommonAST d = new CommonAST(new CommonToken(1, "105")); + t.addChild(a); + a.addChild(f); + t.addChild(b); + b.addChild(c); + b.addChild(d); + TreePostScriptGenerator psgen = new TreePostScriptGenerator(null, t, "TimesNewRoman", 11); + System.out.println(psgen.getPS()); + } +} diff --git a/runtime/Java/src/org/antlr/v4/runtime/tree/gui/TreeViewer.java b/runtime/Java/src/org/antlr/v4/runtime/tree/gui/TreeViewer.java index 84cb877d8..e8cffb51c 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/tree/gui/TreeViewer.java +++ b/runtime/Java/src/org/antlr/v4/runtime/tree/gui/TreeViewer.java @@ -29,20 +29,17 @@ package org.antlr.v4.runtime.tree.gui; -import org.abego.treelayout.NodeExtentProvider; -import org.abego.treelayout.TreeForTreeLayout; -import org.abego.treelayout.TreeLayout; +import org.abego.treelayout.*; import org.abego.treelayout.util.DefaultConfiguration; import org.antlr.v4.runtime.BaseRecognizer; -import org.antlr.v4.runtime.tree.Tree; -import org.antlr.v4.runtime.tree.Trees; +import org.antlr.v4.runtime.tree.*; import javax.swing.*; import java.awt.*; import java.awt.geom.Rectangle2D; public class TreeViewer extends JComponent { - public class DefaultTreeTextProvider implements TreeTextProvider { + public static class DefaultTreeTextProvider implements TreeTextProvider { BaseRecognizer parser; public DefaultTreeTextProvider(BaseRecognizer parser) { this.parser = parser;