commit ed6c91fe87a5316e691af991c4a1d551ee334d65
parent 6f9bd88894ebf146a8a1af7728545026aa3a5153
Author: tomas <tomas@logand.com>
Date: Sat, 23 Jan 2010 14:48:41 +0100
Changes from 2009-06-30
Diffstat:
M | index.org | | | 1895 | ++++++++++++++++++++++++++++++++++++------------------------------------------- |
1 file changed, 869 insertions(+), 1026 deletions(-)
diff --git a/index.org b/index.org
@@ -1,285 +1,565 @@
-* Postscript interpreter
+#+options: author:nil num:nil creator:nil timestamp:nil
-- S :: stack
-- F :: function dictionary
+PostScript and PDF interpreter in JavaScript
+
+PostWeb \\
+WebScript
+
+TODO reuse parsed wps.wps
+
+QQQ
+
+Everything is interpreted. Compilation is translation to lower
+abstraction level or precomputing.
+
+psi/z-matrix.c
+Resource/Init/opdfread.ps
+
+* PostScript interpreter
+
+- stack
+- function dictionary
+- data types
+- reader
+- interpreter/evaluator
+- native bindings (JavaScript FFI)
+- PostScript and PDF API
+
+PDF is stateless?
+
+PostScript is stateful?
+
+#+begin_html
+<style>
+tt {background-color:#fdf}
+canvas {width:12em;height:12em;border:1px dashed black}
+/*canvas {width:10em;height:10em;border:1px dashed black;position:relative;top:0;left:0}*/
+</style>
+#+end_html
+
+#+html: <div id="wps" style="display:none">
+#+include "wps.wps" src text
+#+html: </div>
+#+begin_html
+<script type="text/javascript" src="wps.js"></script>
+<script>
+function $(Id) {return document.getElementById(Id);}
+function $$(Id) {return $(Id).textContent;}
+</script>
+#+end_html
** Trivial example
+#+html: <div id="example1">
+#+begin_src js2
+function example1() {
+ // define stack and operators
+ var Os = [];
+ var Sd = {};
+ var Ds = [Sd];
+ Sd["+"] = function() {Os.push(Os.pop() + Os.pop());};
+ Sd["="] = function() {alert(Os.pop());};
+ // compute 1 2 = 3 + =
+ Os.push(1);
+ Os.push(2);
+ Sd["="]();
+ Os.push(3);
+ Sd["+"]();
+ Sd["="]();
+}
+#+end_src
+#+html: </div>
#+begin_html
<script>
function ex1() {
- var S = [];
- var F = {};
- F["+"] = function() {S.push(S.pop() + S.pop());};
- F["."] = function() {alert(S.pop());};
-
- S.push(1);
- S.push(2);
- F["."]();
- S.push(2);
- F["+"]();
- F["."]();
+ eval($$("example1"));
+ example1();
}
</script>
<button onclick="javascript:ex1()">Eval</button>
-"<tt>1 2 . 2 + .</tt>" from stack
+"<tt>1 2 = 3 + =</tt>" from harcoded stack
#+end_html
-** Example with simple reader
-
+** Example with PostScript reader
+
+#+html: <div id="example2">
+#+begin_src js2
+function example2(T) {
+ var Os = [];
+ var Sd = {};
+ var Ds = [Sd];
+ var Es = [];
+ Sd["+"] = function() {Os.push(Os.pop() + Os.pop());};
+ Sd["dup"] = function() {var X = Os.pop(); Os.push(X); Os.push(X);};
+ Sd["="] = function() {alert(Os.pop());};
+ ps0(T, Os, Ds, Es); // read and interpret code T
+}
+#+end_src
+#+html: </div>
#+begin_html
<script>
-function PdfT(V) {
- this.V = V;
- return this;
-}
-function isPdfT(V) {
- return V.constructor == PdfT; // TODO better test
+function ex2() {
+ eval($$("example2"));
+ example2($$("ex2"));
}
+</script>
+<button onclick="javascript:ex2()">Eval</button>
+"<tt id="ex2">12 34 + dup = 56 + =</tt>" from string
+#+end_html
-function ps(L, F, S) {
- var N = L.length;
- var I = 0;
- if(!S) S = [];
-
- function member(C, L) {return 0 <= L.indexOf(C);}
- function peek() {return I < N && L[I];}
- function char() {return I < N && L[I++];}
- function skip() {while(I < N && member(L[I], " \t\n")) I++;}
-
- function comment() {
- while("%" == peek()) {
- while(peek() && "\n" != peek())
- char();
- skip();
- }
- }
-
- function text() {
- char();
- var L = [];
- var N = 1;
- while(0 < N && peek()) {
- var C = char();
- switch(C) {
- case "(":
- N++;
- break;
- case ")":
- N--;
- if(N <= 0) C = false;
- break;
- case "\\":
- C = char();
- switch(C) {
- case "(": break;
- case ")": break;
- case "\\": break;
- case "n": C = "\n"; break;
- case "r": C = "\r"; break;
- case "t": C = "\t"; break;
- default:
- C = false;
- }
- break;
- }
- if(C !== false) L.push(C);
- }
- return new PdfT(L.join(""));
- }
-
- function symbol() {
- var C = char();
- var N = member(C, "+-0123456789.");
- var F = "." == C;
- var L = [C];
- while(peek() && !member(peek(), "%/[]{}<>( \t\n")) {
- C = char();
- L.push(C);
- if(N && !member(C, "0123456789")) {
- if(!F && "." == C) F = true;
- else N = false;
- }
- }
- L = L.join("");
- if(1 == L.length && member(L, "+-.")) N = false;
- return N ? (F ? parseFloat(L) : parseInt(L, 10)) : L;
- }
-
- function code() {
- char();
- var L = [];
- while(peek()) {
- var T = token();
- if("}" == T) break;
- if(T || T == 0) L.push(T);
- }
- return L;
- }
-
- function token() {
- skip();
- switch(peek()) {
- case false: return undefined;
- case "%": return comment();
- case "[": return char();
- case "]": return char();
- case "{": return code();
- case "}": return char();
- case "(": return text();
- default: return symbol();
- }
- }
-
-// function quoted(T) {
-// return typeof T == "string" && "/" == T.charAt(0);
-// }
-
- function parse(E) {
- var G = true;
- while(G && peek()) {
- var T = token();
- if(T || T == 0) {
- if(typeof T == "number" || typeof T == "object" || quoted(T))
- S.push(T);
- else {
- if(F[T]) F[T]();
- else throw "Unknown operator '" + T + "' " + typeof T;
- if(E == T) G = false;
- }
- }
- }
- return S;
- }
-
- return parse();
-}
+** Example with recursion
+
+#+html: <div id="example3">
+#+begin_src ps
+% based on the example from
+% http://en.literateprograms.org/Fibonacci_numbers_(PostScript)
+% 0, 1, 1, 2, 3, 5, 8, 13, 21
+
+%0.1 1.2 2.3 4.5 3 {pstack} repeat
+%0.1 1.2 2.3 4.5 3 {pstack} .repeat
+
+%/fibonacci{0.1 1.2 2.3 4.5 pstack 3{pstack}repeat pstack}def
+%fibonacci
+
+%/fibonacci{0.1 1.2 2.3 4.5 3{1 add pstack}repeat}def
+%fibonacci
+
+%0 1 1 4 {add} for pstack clear % 10
+%1 2 6 { } for pstack clear % 1 3 5
+%3 -.5 1 { } for pstack clear % 3.0 2.5 2.0 1.5 1.0
+
+4 {(abc)} repeat pstack clear % (abc) (abc) (abc) (abc)
+1 2 3 4 3 {pop} repeat pstack clear % 1 % Pops 3 values (down to the 1)
+4 { } repeat pstack clear % % Does nothing four times
+mark 0 {(will not happen)} repeat pstack clear % mark
+
+%false false or =
+%true false or =
+%false true or =
+%true true or =
+
+% from http://www.math.ubc.ca/~cass/graphics/manual/pdf/ch9.pdf
+
+/factorial { 1 dict begin
+ /n exch def
+ n 0 eq {
+ 1
+ }{
+ n n 1 sub factorial mul
+ } ifelse
+end } def
+
+%5 factorial pstack clear
+
+% args: array a of numbers
+% effect: sorts the array in order
+/bubblesort { 4 dict begin
+ /a exch def
+ /n a length 1 sub def
+n 0 gt {
+ % at this point only the n+1 items in the bottom of a remain to be sorted
+ % the largest item in that block is to be moved up into position n
+ n {
+ 0 1 n 1 sub {
+ /i exch def
+ a i get a i 1 add get gt {
+ % if a[i] > a[i+1] swap a[i] and a[i+1]
+ a i 1 add
+ a i get
+ a i a i 1 add get
+ % set new a[i] = old a[i+1]
+ put
+ % set new a[i+1] = old a[i]
+ put
+ } if
+ } for
+ /n n 1 sub def
+ } repeat
+} if
+end } def
+
+%[5 4 3 2 1 0] bubblesort pstack clear
+
+%{1 2 add {2 mul}} pstack exec pstack exec pstack clear
+
+%1 2 1 {add {(hi)} dup} repeat pstack clear
+%1 2 {} pstack clear
+%1 2 {} exec pstack clear
+
+%(de repeat (N . B)
+% (when (gt0 N)
+% (run B 1) )
+% (when (< 1 N)
+% (repeat (- N 1) B) ) )
+
+%/fibonacci { % n --
+% 1 sub
+% 1 1 3 2 roll
+% { 2 copy add 3 2 roll pop pstack} repeat
+%} bind def
+
+%0 fibonacci = % 0
+%1 fibonacci = % 1
+%2 fibonacci = % 1
+%6 fibonacci = % 8
+
+
+% http://en.wikibooks.org/wiki/Transwiki:Fibonacci_number_program#PostScript
+
+%/fib1 {
+% 1 dup
+% 3 -1 roll {
+% dup
+% 3 -1 roll
+% dup
+% 4 1 roll
+% add
+% 3 -1 roll
+% } repeat
+%} def
+
+%5 fib1 pstack clear
+
+/fib2 {
+ dup dup 1 eq exch 0 eq or not {
+ dup 1 sub fib2
+ exch 2 sub fib2
+ add
+ } if
+} def
-function quoted(T) {
- return typeof T == "string" && "/" == T.charAt(0);
-}
+%5 fib2 pstack clear
+#+end_src
+#+html: </div>
+#+begin_html
+<script>
+function ex3() {wps(null, [$$("wps"), $$("example3")]);}
+</script>
+<button onclick="javascript:ex3();">Eval</button>
+#+end_html
+* The interpreter
+
+A few initial ideas:
+
+- Learn and implement a Forth like language. PostScript seems a great choice:
+ - It has the right syntax and stack based evaluation.
+ - It is practical and widely used.
+ - It has long sucessful history in print and publishing.
+ - It is a predecessor of PDF.
+ - Almost everything (e.g. editors, pictures, documentation) can be
+ reused to a great extent.
+ - It is ideal for HTML 5 canvas experiments because from the
+ PostScript point of view, canvas is just another low level device.
+- Flexibility and simplicity first.
+ - Optimize for fast change, not for raw running speed. Keep the
+ code small and regular if possible.
+ - Can JavaScript be used as a portable assembler for web? Is
+ building scripting languages on top of JavaScript feasible and
+ efficient enough for real-world use? If not, why? Find the
+ limits.
+- Keep the language/environment specific core as small as possible.
+ - Allow to port the interpreter to other languages on both
+ client and server side.
+ - Be open for the possibility of running "the same code" on both the
+ client and server side.
+- Can PDF documents be displayed in web browsers without server-side
+ image rendering?
+ - Implement a canvas based version of PDF page contents in [[http://ondoc.logand.com][OnDoc]].
+- Investigate the possibility of implementing a Lisp interpreter
+ suitable for production use in web applications.
+
+Operators beginning with dot are non-standard low level operators
+which are subject to change.
+
+** PostScript data types
+
+| category | type | executable | example | spec |
+|-----------+-------------+------------+------------------------+--------------------|
+| simple | boolean | | true false | |
+| | fontID | | | |
+| | integer | | 42 -123 0 | |
+| | mark | | | |
+| | name | Y | draw /draw | |
+| | null | | null | |
+| | operator | Y | | |
+| | real | | 3.14 1e-10 | |
+| | save | | | |
+| composite | array | Y | [1 /hi 3.14] {1 2 add} | |
+| | condition | | | Display PostScript |
+| | dictionary | | <</a 1/b 2>> | |
+| | file | | | |
+| | gstate | | | Level 2 |
+| | lock | | | Display PostScript |
+| | packedarray | | | Level 2 |
+| | string | Y | (hi) <a33f> | |
+
+** Low level data types
+
+| category | type | direct | literal | executable |
+|-----------+------------+--------+---------+------------|
+| simple | boolean | Y | Y | - |
+| | number | Y | Y | - |
+| | mark | - | Y | - |
+| | name | - | Y | Y |
+| | null | Y | Y | - |
+| | operator | Y | - | Y |
+| composite | array | Y | Y | - |
+| | proc | - | - | Y |
+| | dictionary | Y | Y | - |
+| | string | Y | Y | - |
+
+All types are represented directly in JavaScript except:
+
+| type | representation |
+|-----------------+-----------------|
+| mark | unique object |
+| literal name | quoted symbol |
+| executable name | unquoted symbol |
+| operator | function |
+| proc | quoted array |
+
+*** exec
+
+pop any, case:
+
+| type | result |
+|-----------------+-------------------|
+| executable name | exec value |
+| operator | apply operator |
+| proc | exec each element |
+
+otherwise push the original value
+
+*** cvx
+
+| from | to | how |
+|--------------+-----------------+---------|
+| literal name | executable name | unquote |
+| array | proc | quote |
+| string | proc | ~ parse |
+
+** Stack
+
+
+
+* Drawing with PostScript
+
+Measuring angles:
+
+| language/device | unit |
+|-----------------+------|
+| canvas | rad |
+| PostScript | deg |
+| PDF | rad |
+
+** Bowtie example
+
+#+html: <canvas id="xbowtie"></canvas>
+#+html: <div id="bowtie">
+#+include "bowtie.wps" src ps
+#+html: </div>
+#+begin_html
+<script>
+wps($("xbowtie"), [$$("wps"), $$("bowtie")]);
+</script>
+#+end_html
-var Msie = 0 < window.navigator.userAgent.indexOf("MSIE"); // :-(
-if(!Msie && !HTMLElement.prototype.innerText) {
- HTMLElement.prototype.__defineGetter__("innerText",
- function () {return(this.textContent);});
- HTMLElement.prototype.__defineSetter__("innerText",
- function(V) {this.textContent = V;});
-}
+** Digital clock example
-function ex2() {
- var S = [];
- var F = {};
- F["+"] = function() {S.push(S.pop() + S.pop());};
- F["dup"] = function() {var X = S.pop(); S.push(X); S.push(X);};
- F["."] = function() {alert(S.pop());};
- ps(document.getElementById("ex2").innerText, F, S);
-}
+#+html: <canvas id="xclock"></canvas>
+#+html: <div id="clock">
+#+include "clock.wps" src ps
+#+html: </div>
+#+begin_html
+<script>
+wps($("xclock"), [$$("wps"), $$("clock")]);
+</script>
+#+end_html
+
+** Analog clock example
+
+#+html: <canvas id="xclock2"></canvas>
+
+Click on the clock to start/stop it.
+
+#+html: <div id="clock2">
+#+include "clock2.wps" src ps
+#+html: </div>
+#+begin_html
+<script>
+wps($("xclock2"), [$$("wps"), $$("clock2")]);
</script>
-<button onclick="javascript:ex2()">Eval</button>
-"<tt id="ex2">12 34 + dup . 56 + .</tt>" from string
#+end_html
-#+begin_src text
-{ /category (COOKING) }
+** Tiger example
-: sum
-1 2 + ;
+Text drawing in canvas is not working in Firefox and Opera, works in
+Chrome.
-1 (sdfsdf) /Tf
+Firefox throws error about linecap and linejoin not being supported.
+However, it does not throw error about missing support for text
+drawing.
-12 34 (cooking is fun) /Tf
+#+plot: title:"tiger.eps drawing times" ind:1 deps:(2) type:2d with:histograms set:"yrange [0:]" set:"xlabel 'browser'" set:"ylabel 'time [s]'" set:"style histogram gap 1" file:"tiger.png" set:"term png size 400, 300"
+| browser | time [s] |
+|---------+----------|
+| Chrome | 3.8 |
+| Opera | 13.4 |
+| Firefox | 19.5 |
-{ /key (value) }
-#+end_src
+file:tiger.png
-* PDF drawing
+** Fern example
+from http://www.pvv.ntnu.no/~andersr/fractal/PostScript.html
-#+html: <div id="wps">
-#+include "wps.wps" src ps
+#+html: <canvas id="xfern"></canvas>
+
+#+html: <div id="fern">
+#+include "fern.wps" src ps
#+html: </div>
+#+begin_html
+<script>
+//wps($("xfern"), [$$("wps"), $$("fern")]);
+</script>
+#+end_html
-#+html: <div id="bowtie">
-#+include "bowtie.wps" src ps
+** Tree example
+
+from http://www.pvv.ntnu.no/~andersr/fractal/PostScript.html
+
+#+html: <canvas id="xtree2"></canvas>
+
+#+html: <div id="tree2">
+#+include "tree2.ps" src ps
#+html: </div>
+#+begin_html
+<script>
+//wps($("xtree2"), [$$("wps"), $$("tree2")]);
+</script>
+#+end_html
+** Other
+1 0 0 0 setcmykcolor % 100% cyan \\
+0 0 1 0 setcmykcolor % 100% yellow
+** Fill example
+#+html: <canvas id="xfill"></canvas>
+#+html: <div id="fill">
+#+include "fill.wps" src ps
+#+html: </div>
+#+begin_html
+<script>
+wps($("xfill"), [$$("wps"), $$("fill")]);
+</script>
+#+end_html
+
+** Chessboard example
+#+html: <canvas id="xchess"></canvas>
+#+html: <div id="chess">
+#+include "chess.eps" src ps
+#+html: </div>
#+begin_html
-<pre id="ex3x">
-1 2.3 + -5.6 + .
-</pre>
-<pre id="ex3">
+<div id="ychess" style="display:none">
+0 0 180 180 .gbox
+%1 0 0 -1 0 180 cm
+</div>
+<script>
+wps($("xchess"), [$$("wps"), $$("ychess"), $$("chess")]);
+</script>
+#+end_html
-%%% ps operators
+* Drawing with PDF
-/setlinewidth {/lineWidth gput} def
+PDF documents have the origin of the coordinate system in the bottom
+left corner while HTML 5 canvas int the top left corner. Thus, some
+of the following pictures are displayed upside down (unless an
+explicit coordinate transformation was added which is not part of the
+visible example code).
-/setlinecap {/lineCap gput} def
+** Heart example
-/setlinejoin {/lineJoin gput} def
+#+html: <canvas id="xheart"></canvas>
+#+html: <div id="heart">
+#+include "heart.wpdf" src ps
+#+html: </div>
+#+begin_html
+<script>
+wps($("xheart"), [$$("wps"), $$("heart")]);
+</script>
+#+end_html
-/setmiterlimit {/miterLimit gput} def
+** Rectangle example
-/setgray {255 mul dup dup rgb /fillStyle gput} def
+#+html: <canvas id="xrect"></canvas>
+#+html: <div id="rect">
+#+include "rect.wpdf" src ps
+#+html: </div>
+#+begin_html
+<script>
+wps($("xrect"), [$$("wps"), $$("rect")]);
+</script>
+#+end_html
-%%% examples
+** Triangles example
-1 0 0 -1 0 446 cm % 0,0 in bottom left corner
+#+html: <canvas id="xtriangles"></canvas>
+#+html: <div id="triangles">
+#+include "triangles.wpdf" src ps
+#+html: </div>
+#+begin_html
+<script>
+wps($("xtriangles"), [$$("wps"), $$("triangles")]);
+</script>
+#+end_html
-% E1
+** Smile example
-q
-0 0 m 0 0 150 150 re f
-q
-0 150 255 rg
-0 0 m 15 15 120 120 re f
-q
-255 255 255 rg
-%0.5 alpha
-0 0 m 30 30 90 90 re f
-Q
-0 0 m 45 45 60 60 re f
-Q
-0 0 m 60 60 30 30 re f
-Q
+#+html: <canvas id="xsmile"></canvas>
+#+html: <div id="smile">
+#+include "smile.wpdf" src ps
+#+html: </div>
+#+begin_html
+<script>
+wps($("xsmile"), [$$("wps"), $$("smile")]);
+</script>
+#+end_html
-% E2
+** Star example
-q
-255 0 0 rg
-0 0 m 10 10 55 50 re f
-0 0 200 rg
-0 0 m 30 30 55 50 re f
-Q
+#+html: <canvas id="xstar"></canvas>
+#+html: <div id="star">
+#+include "star.wpdf" src ps
+#+html: </div>
+#+begin_html
+<script>
+wps($("xstar"), [$$("wps"), $$("star")]);
+</script>
+#+end_html
-% E3
+** Squares 2 example
-q
-1 0 0 -1 50 200 cm
-0 0 0 rg
-%BT
-(serif) 24 Tf
-%1 0 0 1 260 254
-(Hello World) Tj
-%ET
-Q
+#+html: <canvas id="xsquares2"></canvas>
+#+html: <div id="squares2">
+#+include "squares2.wpdf" src ps
+#+html: </div>
+#+begin_html
+<script>
+wps($("xsquares2"), [$$("wps"), $$("squares2")]);
+</script>
+#+end_html
-q
-0 0 255 rg
-4 0 0 4 315 204 cm
- 0 5.5 m
--4 -5.5 l
- 6 1 l
--6 1 l
- 4 -5.5 l
-f
-Q
+** Junk
+
+#+begin_html
+<pre>
+
+1 0 0 -1 0 446 cm % 0,0 in bottom left corner
% Ex4
@@ -321,45 +601,8 @@ Q
b
Q
-% E5
-
-1 0 0 1 100 100 cm
-
-255 255 255 rg
-75 50 m
-100 75 l
-100 25 l
-f
-
-% http://developer.mozilla.org/samples/canvas-tutorial/2_2_canvas_moveto.html
-%0 0 m
-%75 75 50 0 pi 2 * true arc
-%110 75 m
-%75 75 35 0 pi false arc
-%65 65 m
-%60 65 5 0 pi 2 * true arc
-%95 65 m
-%90 65 5 0 pi 2 * true arc
-%S
-
-% http://developer.mozilla.org/samples/canvas-tutorial/2_3_canvas_lineto.html
-
-1 0 0 1 100 100 cm
-
-25 25 m
-105 25 l
-25 105 l
-f
-
-125 125 m
-125 45 l
-45 125 l
-h S
-
% http://developer.mozilla.org/samples/canvas-tutorial/2_5_canvas_quadraticcurveto.html
-1 0 0 1 100 100 cm
-
%75 25 m
%25 25 25 62 5 c2
%25 100 50 100 c2
@@ -369,70 +612,12 @@ h S
%125 25 75 25 c2
%S
-q % heart (bezier)
-1 0 0 -1 0 0 cm
-255 0 0 rg
-75 40 m
-75 37 70 25 50 25 c
-20 25 20 62.5 20 62.5 c
-20 80 40 102 75 120 c
-110 102 130 80 130 62.5 c
-130 62.5 130 25 100 25 c
-85 25 75 37 75 40 c
-f
-Q
-
-
-/triangle {
- 255 255 255 rg
- 75 50 m
- 100 75 l
- 100 25 l
- f
-} def
-
-/triangle2 {
- 255 0 255 rg
- 75 50 m
- 100 75 l
- 100 25 l
- f
-} def
-
-triangle
-1 0 0 1 100 -100 cm
-triangle2
-1 0 0 1 100 -100 cm
-triangle
-
%3 8 div 6 add .
%6 3 8 div add .
%8 7 3 mul sub .
%7 3 mul 8 exch sub .
-7.2 36.0 m
-14.4 7.2 l
-S
-14.4 43.2 m
-0 -21.6 l
-S
-
-1 0 0 1 27.0 36.0 cm
-0 72 m
-72 0 l
-0 -72 l
--72 0 l
-4 setlinewidth
-h S
-
-/pi 3.141592653589 def
-%pi .
-%pi 2 mul .
-
-/inch {72 mul} def
-%5 inch .
-
/box {
0 0 m
72 0 l
@@ -453,623 +638,46 @@ box
% TODO not, and, or, xor
% TODO for loop exit
-
-/factorial %stack: n --- n! (after)
-{ dup 1 gt
- {dup 1 sub factorial mul} if
-} def
-
-%5 factorial .
-
-% https://developer.mozilla.org/samples/canvas-tutorial/4_1_canvas_fillstyle.html
-
-% for (i=0;i<6;i++){
-% for (j=0;j<6;j++){
-% ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' +
-% Math.floor(255-42.5*j) + ',0)';
-% ctx.fillRect(j*25,i*25,25,25);
-
-%0 2 6 {.} for
-
-1 1 6 { %% i
- dup 255 exch 255 6 div mul sub %% i ii
- 1 1 6 { %% i ii j
- dup 255 exch 255 6 div mul sub %% i ii j jj
-% fillstyle
-% fillrect 25 j mul | 25 i mul | 25 | 25
- } for
-} for
-
-
-% https://developer.mozilla.org/en/drawing_graphics_with_canvas
-
-/bowtie { % fillStyle
- 200 200 200 0.3 rgba /fillStyle gput
- -30 -30 60 60 fillRect
- /fillStyle gput
- 1.0 /globalAlpha gput
- newpath
- 25 25 moveto
- -25 -25 lineto
- 25 -25 lineto
- -25 25 lineto
- closepath
- fill
-} def
-
-/dot {
- gsave
- (black) /fillStyle gput
- -2 -2 4 4 fillRect
- grestore
-} def
-
-0 -100 translate
-
-45 45 translate
-
-gsave
-(red) bowtie
-dot
-grestore
-
-gsave
-85 0 translate
-45 pi mul 180 div rotate
-(green) bowtie
-dot
-grestore
-
-gsave
-0 85 translate
-135 pi mul 180 div rotate
-(blue) bowtie
-dot
-grestore
-
-gsave
-85 85 translate
-90 pi mul 180 div rotate
-(yellow) bowtie
-dot
-grestore
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
</pre>
+#+end_html
-<script>
-function min(X, Y) {
- return X < Y ? X : Y;
-}
-
-function max(X, Y) {
- return X < Y ? Y : X;
-}
+/MediaBox [0 0 612 446]
-function ex3() {
- var S = [];
- var F = {};
- var W = document.getElementById("c");
- var C = W.getContext("2d");
-
- W.setAttribute("width", 612);
- W.setAttribute("height", 446);
-
- // basic operators
-
- F["neg"] = function() {S.push(- S.pop());};
- F["add"] = function() {S.push(S.pop() + S.pop());};
- F["sub"] = function() {F["neg"](); F["add"]();};
- F["mul"] = function() {S.push(S.pop() * S.pop());};
- F["div"] = function() {
- var X = S.pop();
- S.push(S.pop() / X);
- };
- F["idiv"] = function() {
- var X = S.pop();
- S.push(Math.floor(S.pop() / X));
- };
- F["mod"] = function() {
- var X = S.pop();
- S.push(S.pop() % X);
- };
- // TODO sqrt, exp, ceiling, sin
- F["exch"] = function() {
- var Y = S.pop();
- var X = S.pop();
- S.push(Y);
- S.push(X);
- };
-
- F["dup"] = function() {var X = S.pop(); S.push(X); S.push(X);};
- F["clear"] = function() {S = [];};
- F["pop"] = function() {S.pop();};
- // TODO roll
-
- F["eq"] = function() {
- var Y = S.pop();
- var X = S.pop();
- S.push(X == Y);
- };
- F["ne"] = function() {
- var Y = S.pop();
- var X = S.pop();
- S.push(X != Y);
- };
- F["gt"] = function() {
- var Y = S.pop();
- var X = S.pop();
- S.push(X > Y);
- };
- F["lt"] = function() {
- var Y = S.pop();
- var X = S.pop();
- S.push(X < Y);
- };
- F["ge"] = function() {
- var Y = S.pop();
- var X = S.pop();
- S.push(X >= Y);
- };
- F["le"] = function() {
- var Y = S.pop();
- var X = S.pop();
- S.push(X <= Y);
- };
-
- F["if"] = function() {
- var B = S.pop();
- var C = S.pop();
- if(C == true) run(B);
- };
- F["ifelse"] = function() {
- var N = S.pop();
- var P = S.pop();
- var C = S.pop();
- if(C == true) run(P);
- else run(N);
- };
- F["repeat"] = function() {
- var B = S.pop();
- var N = S.pop();
- for(var I = 0; I < N; I++) run(B);
- };
- F["for"] = function() {
- var B = S.pop();
- var L = S.pop();
- var K = S.pop();
- var J = S.pop();
- if(K < 0) {
- for(var I = J; L <= I; I += K) {
- S.push(I);
- run(B);
- }
- } else {
- for(var I = J; I <= L; I += K) {
- S.push(I);
- run(B);
- }
- }
- };
-
- F["."] = function() {alert(S.pop());};
- F["=="] = function() {alert(S[0]);};
- F["pstack"] = function() {alert(S);};
-
- function run(C) {
- if(!C.length) S.push(C);
- else {
- var M = C.length;
- for(var I = 0; I < M; I++) {
- var T = C[I];
- if(typeof T == "number" || typeof T == "object" || quoted(T))
- S.push(T);
- else {
- if(F[T]) F[T]();
- else throw "Unknown operator '" + T + "' " + typeof T;
- }
- }
- }
- }
-
- F["def"] = function() {
- var C = S.pop();
- var N = S.pop();
- if(quoted(N)) F[N.substring(1)] = function() {run(C);}
- else throw "Wrong operator name " + N;
- };
-
- // html5 graphic operators
-
- //transform
- //setTransform
- //createLinearGradient
- //createRadialGradient
- //createPatternI
- //createPatternC
- //createPatternV
- F["clearRect"] = function() {
- var H = S.pop();
- var W = S.pop();
- var Y = S.pop();
- var X = S.pop();
- C.clearRect(X, Y, W, H);
- };
- F["fillRect"] = function() {
- var H = S.pop();
- var W = S.pop();
- var Y = S.pop();
- var X = S.pop();
- C.fillRect(X, Y, W, H);
- };
- F["strokeRect"] = function() {
- var H = S.pop();
- var W = S.pop();
- var Y = S.pop();
- var X = S.pop();
- C.strokeRect(X, Y, W, H);
- };
- //quadraticCurveTo
- F["rect"] = function() {
- var H = S.pop();
- var W = S.pop();
- var Y = S.pop();
- var X = S.pop();
- C.strokeRect(X, Y, W, H);
- };
- //isPointInPath
- //fillText
- //strokeText
- //measureText
- //drawImageI1
- //drawImageI2
- //drawImageC1
- //drawImageC2
- //drawImageV1
- //drawImageV2
- //createImageData1
- //createImageData2
- //getImageData
- //putImageData
-
- // html5 utility operators
-
- F["gput"] = function() {
- var K = S.pop();
- var V = S.pop();
- C[K.substring(1)] = isPdfT(V) ? V.V : V;
- };
- F["gget"] = function() {
- var K = S.pop();
- S.push(C[K.substring(1)]);
- };
-
- F["rgb"] = function() {
- var B = S.pop();
- var G = S.pop();
- var R = S.pop();
- S.push(new PdfT("rgba(" + R + "," + G + "," + B + ")"));
- };
- F["rgba"] = function() {
- var A = S.pop();
- var B = S.pop();
- var G = S.pop();
- var R = S.pop();
- S.push(new PdfT("rgba(" + R + "," + G + "," + B + "," + A + ")"));
- };
-
- // ps graphic operators
-
- F["gsave"] = function() {C.save();};
- F["grestore"] = function() {C.restore();};
- F["scale"] = function() {
- var Y = S.pop();
- var X = S.pop();
- C.scale(X, Y);
- };
- F["rotate"] = function() {
- var A = S.pop();
- C.rotate(A);
- };
- F["translate"] = function() {
- var Y = S.pop();
- var X = S.pop();
- C.translate(X, Y);
- };
- F["newpath"] = function() {C.beginPath();};
- F["closepath"] = function() {C.closePath();};
- F["moveto"] = function() {
- var Y = S.pop();
- var X = S.pop();
- C.moveTo(X, Y);
- };
- F["lineto"] = function() {
- var Y = S.pop();
- var X = S.pop();
- C.lineTo(X, Y);
- };
- F["arcto"] = function() {
- var R = S.pop();
- var Y2 = S.pop();
- var X2 = S.pop();
- var Y1 = S.pop();
- var X1 = S.pop();
- C.arcTo(X1, Y1, X2, Y2, R);
- };
- F["arc"] = function() {
- var A = S.pop();
- var E = S.pop();
- var S = S.pop();
- var R = S.pop();
- var Y = S.pop();
- var X = S.pop();
- C.arc(X, Y, R, S, E, A);
- };
- F["fill"] = function() {C.fill();};
- F["stroke"] = function() {C.stroke();};
- F["clip"] = function() {C.clip();};
-
- // pdf graphic operators
-
- F["w"] = function() {C.lineWidth = S.pop();};
- F["J"] = function() {C.lineCap = S.pop();};
- F["j"] = function() {C.lineJoin = S.pop();};
- F["M"] = function() {C.mitterLimit = S.pop();};
- F["d"] = function() {
- var P = S.pop();
- var A = S.pop();
- alert("TODO d");
- };
- F["ri"] = function() {alert("TODO ri");};
- F["i"] = function() {alert("TODO i");};
- F["gs"] = function() {alert("TODO gs");};
-
- F["q"] = function() {C.save();};
- F["Q"] = function() {C.restore();};
- F["cm"] = function() { // TODO fix cm
- var Dy = S.pop();
- var Dx = S.pop();
- var M22 = S.pop();
- var M21 = S.pop();
- var M12 = S.pop();
- var M11 = S.pop();
- //alert(M11 +"|"+ M12 +"|"+ M21 +"|"+ M22 +"|"+ Dx +"|"+ Dy);
- //C.setTransform(M11, M12, M21, M22, Dx, Dy);
- C.transform(M11, M12, M21, M22, Dx, Dy);
- };
-
- F["m"] = function() {
- var Y = S.pop();
- var X = S.pop();
- C.beginPath(); // TODO only if not m previously
- C.moveTo(X, Y);
- };
- F["l"] = function() {
- var Y = S.pop();
- var X = S.pop();
- C.lineTo(X, Y);
- };
- F["c"] = function() {
- var Y3 = S.pop();
- var X3 = S.pop();
- var Y2 = S.pop();
- var X2 = S.pop();
- var Y1 = S.pop();
- var X1 = S.pop();
- C.bezierCurveTo(X1, Y1, X2, Y2, X3, Y3); // TODO the right c method
- };
-// F["c2"] = function() { // not in pdf
-// var Y3 = S.pop();
-// var X3 = S.pop();
-// var Y2 = S.pop();
-// var X2 = S.pop();
-// var Y1 = S.pop();
-// var X1 = S.pop();
-// C.bezierCurveTo(X1, Y1, X2, Y2, X3, Y3); // TODO the right c method
+#+begin_html
+<script>
+function xreq(Url, Cb, Er) {
+// var req = new XMLHttpRequest();
+// alert(Url);
+// req.open('GET', Url, true);
+// req.onreadystatechange = function (e) {
+// if(req.readyState == 4) {
+// if(req.status == 200) Cb(req.responseText);
+// else if(Er) Er();
+// }
// };
- F["v"] = function() {alert("TODO v");};
- F["y"] = function() {alert("TODO y");};
- F["h"] = function() {C.closePath();};
- F["re"] = function() {
- var Y2 = S.pop();
- var X2 = S.pop();
- var Y1 = S.pop();
- var X1 = S.pop();
- C.rect(X1, Y1, X2, Y2);
- };
-
- F["S"] = function() {C.stroke();};
- F["s"] = function() {F["h"](); F["S"]();};
- F["f"] = function() {C.fill();};
- F["F"] = function() {C.fill();};
- F["f*"] = function() {alert("TODO f*");};
- F["B"] = function() {F["f"](); F["S"]();};
- F["B*"] = function() {F["f*"](); F["S"]();};
- F["b"] = function() {F["h"](); F["B"]();};
- F["b*"] = function() {F["h"](); F["B*"]();};
- F["n"] = function() {alert("TODO n");};
-
- F["W"] = function() {C.clip();};
- F["W*"] = function() {alert("TODO W*");};
-
- F["BT"] = function() {alert("TODO BT")};
- F["ET"] = function() {alert("TODO ET")};
-
- F["Tc"] = function() {alert("TODO Tc");};
- F["Tw"] = function() {alert("TODO Tw");};
- F["Tz"] = function() {alert("TODO Tz");};
- F["TL"] = function() {alert("TODO Tf");};
- F["Tf"] = function() {
- var N = S.pop();
- var F = S.pop();
- C.font = N + "pt " + F.V;
- };
- F["Tr"] = function() {alert("TODO Tr");};
- F["Ts"] = function() {alert("TODO Ts");};
-
- F["Td"] = function() {alert("TODO Td");};
- F["TD"] = function() {alert("TODO TD");};
- F["Tm"] = function() {alert("TODO Tm");};
- F["T*"] = function() {alert("TODO T*");};
-
- F["Tj"] = function() {
- var T = S.pop();
- //alert(T.V);
- //if(C.strokeText) C.strokeText(T.V, 0, 0);
- if(C.fillText) C.fillText(T.V, 0, 0);
- };
- F["TJ"] = function() {alert("TODO TJ");};
- F["'"] = function() {alert("TODO '");};
- F["\""] = function() {alert("TODO \"");};
-
- F["d0"] = function() {alert("TODO d0");};
- F["d1"] = function() {alert("TODO d1");};
-
- F["CS"] = function() {alert("TODO CS");};
- F["cs"] = function() {alert("TODO cs");};
- F["SC"] = function() {alert("TODO SC");};
- F["SCN"] = function() {alert("TODO SCN");};
- F["sc"] = function() {alert("TODO sc");};
- F["scn"] = function() {alert("TODO scn");};
- F["G"] = function() {alert("TODO G");};
- F["g"] = function() {alert("TODO g");};
- F["RG"] = function() {alert("TODO RG");};
- F["rg"] = function() { // TODO color spaces
- var B = S.pop();
- var G = S.pop();
- var R = S.pop();
- C.fillStyle = "rgb(" + R + "," + G + "," + B + ")";
- };
- F["K"] = function() {alert("TODO K");};
- F["k"] = function() {alert("TODO k");};
-
- F["sh"] = function() {alert("TODO sh");};
-
- F["BI"] = function() {alert("TODO BI");};
- F["ID"] = function() {alert("TODO ID");};
- F["EI"] = function() {alert("TODO EI");};
-
- F["Do"] = function() {alert("TODO Do");};
-
- F["MP"] = function() {alert("TODO MP");};
- F["DP"] = function() {alert("TODO DP");};
- F["BMC"] = function() {alert("TODO BMC");};
- F["BDC"] = function() {alert("TODO BDC");};
- F["EMC"] = function() {alert("TODO EMC");};
-
- F["BX"] = function() {alert("TODO BX");};
- F["EX"] = function() {alert("TODO EX");};
-
- ps(document.getElementById("ex3").innerText, F, S);
+// req.send(null);
+
+ try {netscape.security.PrivilegeManager.enablePriviledge(priviledge);}
+ catch(e) {}
+ var req = new XMLHttpRequest();
+ req.open('GET', Url, false);
+ req.send(null);
+ if(req.status == 200) Cb(req.responseText);
+ else alert("uff");
}
</script>
-<button onclick="javascript:ex3()">Draw</button>
#+end_html
-/MediaBox [0 0 612 446]
+#+html: <canvas id="c"></canvas>
-#+html: <canvas id="c" style="width:612pt;height:446pt;background-color:yellow"/>
+[[http://svn.ghostscript.com/viewvc/trunk/gs/examples/tiger.eps?view=co][tiger.eps]]:
+#+html: <button onclick="javascript:xreq('http://svn.ghostscript.com/viewvc/trunk/gs/examples/tiger.eps?view=co', wps)">Draw</button>
+#+html: <button onclick="javascript:xreq('file:///home/tomas/src/pdf4web/tiger.eps', alert)">Draw</button>
-** CanvasRenderingContext2D
+* JavaScript bindings
http://www.whatwg.org/specs/web-apps/current-work/#the-canvas-element
-Operators:
-
-| | category | operator |
-|---+------------------------+----------|
-| / | | < |
-| | General graphics state | w |
-| | | J |
-| | | j |
-| | | M |
-| | | d |
-| | | ri |
-| | | i |
-| | | gs |
-| | Special graphics state | q |
-| | | Q |
-| | | cm |
-| | Path construction | m |
-| | | l |
-| | | c |
-| | | v |
-| | | y |
-| | | h |
-| | | re |
-| | Path painting | S |
-| | | s |
-| | | f |
-| | | F |
-| | | f* |
-| | | B |
-| | | B* |
-| | | b |
-| | | b* |
-| | | n |
-| | Clipping paths | W |
-| | | W* |
-| | Text objects | BT |
-| | | ET |
-| | Text state | Tc |
-| | | Tw |
-| | | Tz |
-| | | TL |
-| | | Tf |
-| | | Tr |
-| | | Ts |
-| | Text positioning | Td |
-| | | TD |
-| | | Tm |
-| | | T* |
-| | Text showing | Tj |
-| | | TJ |
-| | | ' |
-| | | " |
-| | Type 3 fonts | d0 |
-| | | d1 |
-| | Color | CS |
-| | | cs |
-| | | SC |
-| | | SCN |
-| | | sc |
-| | | scn |
-| | | G |
-| | | g |
-| | | RG |
-| | | rg |
-| | | K |
-| | | k |
-| | Shading patterns | sh |
-| | Inline images | BI |
-| | | ID |
-| | | EI |
-| | XObjects | Do |
-| | Marked content | MP |
-| | | DP |
-| | | BMC |
-| | | BDC |
-| | | EMC |
-| | Compatibility | BX |
-| | | EX |
-
-Special graphics state q, Q, cm 57
-Path construction m, l, c, v, y, h, re 59
-
??? rlineto rmoveto findfont scalefont setfont show rightshow
stringwidth arcn loop/exit forall cvs array put get length aload
astore mark ashow widthshow awidthshow kshow currentpoint makefont
@@ -1084,108 +692,343 @@ octal chars in string \234
/Times-Roman findfont typography 15 scalefont setfont
-
-Methods:
-
-| | html5 | ps | pdf | method |
-|---+----------------------+-----------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| / | | | | < |
-| | | gsave | q | void save(); |
-| | | grestore | Q | void restore(); |
-| | | scale | | void scale(in float x, in float y); |
-| | | rotate | | void rotate(in float angle); |
-| | | translate | | void translate(in float x, in float y); |
-| | transform | | | void transform(in float m11, in float m12, in float m21, in float m22, in float dx, in float dy); |
-| | setTransform | | cm ? | void setTransform(in float m11, in float m12, in float m21, in float m22, in float dx, in float dy); |
-| | createLinearGradient | | | CanvasGradient createLinearGradient(in float x0, in float y0, in float x1, in float y1); |
-| | createRadialGradient | | | CanvasGradient createRadialGradient(in float x0, in float y0, in float r0, in float x1, in float y1, in float r1); |
-| | createPatternI | | | CanvasPattern createPattern(in HTMLImageElement image, in DOMString repetition); |
-| | createPatternC | | | CanvasPattern createPattern(in HTMLCanvasElement image, in DOMString repetition); |
-| | createPatternV | | | CanvasPattern createPattern(in HTMLVideoElement image, in DOMString repetition); |
-| | clearRect | | | void clearRect(in float x, in float y, in float w, in float h); |
-| | fillRect | | | void fillRect(in float x, in float y, in float w, in float h); |
-| | strokeRect | | | void strokeRect(in float x, in float y, in float w, in float h); |
-| | | newpath | m ! | void beginPath(); |
-| | | closepath | h | void closePath(); |
-| | | moveto | | void moveTo(in float x, in float y); |
-| | | lineto | | void lineTo(in float x, in float y); |
-| | quadraticCurveTo | | | void quadraticCurveTo(in float cpx, in float cpy, in float x, in float y); |
-| | | | c | void bezierCurveTo(in float cp1x, in float cp1y, in float cp2x, in float cp2y, in float x, in float y); |
-| | | arcto | | void arcTo(in float x1, in float y1, in float x2, in float y2, in float radius); |
-| | rect | | | void rect(in float x, in float y, in float w, in float h); |
-| | | arc | | void arc(in float x, in float y, in float radius, in float startAngle, in float endAngle, in boolean anticlockwise); |
-| | | fill | f | void fill(); |
-| | | | F ! | |
-| | | stroke | S | void stroke(); |
-| | | | s ! | |
-| | | | b ! | |
-| | | | b* ! | |
-| | | clip | W | void clip(); |
-| | | | W* ! | |
-| | isPointInPath | | | boolean isPointInPath(in float x, in float y); |
-| | fillText | | | void fillText(in DOMString text, in float x, in float y, [Optional] in float maxWidth); |
-| | strokeText | | | void strokeText(in DOMString text, in float x, in float y, [Optional] in float maxWidth); |
-| | measureText | | | TextMetrics measureText(in DOMString text); |
-| | drawImageI1 | | | void drawImage(in HTMLImageElement image, in float dx, in float dy, [Optional] in float dw, in float dh); |
-| | drawImageI2 | | | void drawImage(in HTMLImageElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh); |
-| | drawImageC1 | | | void drawImage(in HTMLCanvasElement image, in float dx, in float dy, [Optional] in float dw, in float dh); |
-| | drawImageC2 | | | void drawImage(in HTMLCanvasElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh); |
-| | drawImageV1 | | | void drawImage(in HTMLVideoElement image, in float dx, in float dy, [Optional] in float dw, in float dh); |
-| | drawImageV2 | | | void drawImage(in HTMLVideoElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh); |
-| | createImageData1 | | | ImageData createImageData(in float sw, in float sh); |
-| | createImageData2 | | | ImageData createImageData(in ImageData imagedata); |
-| | getImageData | | | ImageData getImageData(in float sx, in float sy, in float sw, in float sh); |
-| | putImageData | | | void putImageData(in ImageData imagedata, in float dx, in float dy, [Optional] in float dirtyX, in float dirtyY, in float dirtyWidth, in float dirtyHeight); |
-
-Attributes:
-
-| | html5 | ps | pdf | attribute | default |
-|---+--------------------------+-----------------+-----+----------------------------------------------------------------------------------------------+-------------------|
-| / | < | < | < | < | < |
-| | globalAlpha | | | float globalAlpha; | 1.0 |
-| | globalCompositeOperation | | | DOMString globalCompositeOperation; | source-over |
-| | strokeStyle | (~setdash?) | | any strokeStyle; | black |
-| | fillStyle | | | any fillStyle; | black |
-| | lineWidth | ~ setlinewidth | | float lineWidth; | 1 |
-| | lineCap | ~ setlinecap | | DOMString lineCap; // "butt", "round", "square" | butt |
-| | lineJoin | ~ setlinejoin | | DOMString lineJoin; // "round", "bevel", "miter" | miter |
-| | miterLimit | ~ setmiterlimit | | float miterLimit; | 10 |
-| | shadowOffsetX | | | float shadowOffsetX; | 0 |
-| | shadowOffsetY | | | float shadowOffsetY; | 0 |
-| | shadowBlur | | | float shadowBlur; | 0 |
-| | shadowColor | | | DOMString shadowColor; | transparent black |
-| | font | | | DOMString font; | 10px sans-serif |
-| | textAlign | | | DOMString textAlign; // "start", "end", "left", "right", "center" | start |
-| | textBaseline | | | DOMString textBaseline; // "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" | alphabetic |
-
-
-#+begin_src idl
-interface CanvasGradient {
- // opaque object
- void addColorStop(in float offset, in DOMString color);
-};
-
-interface CanvasPattern {
- // opaque object
-};
-
-interface TextMetrics {
- readonly attribute float width;
-};
-
-interface ImageData {
- readonly attribute unsigned long width;
- readonly attribute unsigned long height;
- readonly attribute CanvasPixelArray data;
-};
-
-[IndexGetter, IndexSetter]
-interface CanvasPixelArray {
- readonly attribute unsigned long length;
-};
-#+end_src
+** Built-in operators
+
+| category | in | operator | out |
+|----------------+-------------------------+----------+-------------------------------------------------------------|
+| Trivial | | true | true |
+| | | false | false |
+| | | null | null |
+| Math | x | neg | -x |
+| | x y | add | x+y |
+| | x y | mul | x*y |
+| | x y | div | x/y |
+| | x y | mod | x%y |
+| Stack | | mark | mark |
+| | x y | exch | y x |
+| | | clear | |
+| | x | pop | |
+| | any_n ...any_0 n | index | any_n ... any_0 any_n |
+| | any_(n-1) ... any_0 n j | roll | any_((j-1) mod n) ... any_0 ... any_(n-1) ... any_(j mod n) |
+| | any_1 ... any_n n | copy | any_1 ... any_n any_1 ... any_n |
+| Array | array | length | n |
+| Conditionals | x y | eq | bool |
+| | x y | lt | bool |
+| | y | not | bool |
+| | x y | and | z |
+| | x y | or | z |
+| | bool then else | ifelse | |
+| | n proc | repeat | |
+| | i j k proc | for | |
+| Debugging | x | . | |
+| | | pstack | |
+| Dictionaries | n | dict | dict |
+| | dict key | get | any |
+| | dict key any | put | |
+| | sym proc | def | |
+| Arrays | n | array | array |
+| JavaScript FFI | dict key nargs | .call | any |
+| | | .gc | gc |
+| | | .math | Math |
+| HTML 5 | r g b | .rgb | text |
+| | r g b a | .rgba | text |
+
+** Core operators
+
+| category | in | operator | out |
+|--------------+-------------+-------------+--------|
+| Math | | abs | |
+| | | .acos | |
+| | | .asin | |
+| | | atan | |
+| | | .atan2 | |
+| | | ceiling | |
+| | | cos | |
+| | | .exp | |
+| | | floor | |
+| | | log | |
+| | | .max | |
+| | | .min | |
+| | | .pow | |
+| | | .random | |
+| | | rand | |
+| | | round | |
+| | | sin | |
+| | | sqrt | |
+| | | .tan | |
+| | | truncate | |
+| | | .e | |
+| | | .ln2 | |
+| | | .ln10 | |
+| | | .log2e | |
+| | | .log10e | |
+| | | .pi | |
+| | | .sqrt1_2 | |
+| | | .sqrt2 | |
+| | | sub | |
+| | | idiv | |
+| Stack | x | dup | x x |
+| Conditionals | x y | ne | bool |
+| | x y | ge | bool |
+| | x y | le | bool |
+| | x y | gt | bool |
+| | bool proc | if | |
+| HTML 5 | key | .gget | |
+| | any key | .gput | |
+| | key nargs | .gcall0 | |
+| | key nargs | .gcall1 | |
+| | | .gcanvas | canvas |
+| | w h | .gdim | |
+| | x0 y0 x1 y1 | .gbox | |
+| PostScript | gray | setgray | |
+| | r g b | setrgbcolor | |
+| | ??? | setfont ? | |
+| | | clippath ? | |
+| | text | show ? | |
+| | x y | rlineto | |
+
+** Canvas methods
+
+| | in | canvas | out | ps | pdf |
+|---+----------------------------------------------+-----------------------+----------------+------------+-------------|
+| / | | | | < | < |
+| | | .save | | gsave | q |
+| | | .restore | | grestore | Q |
+| | x y | scale | | scale | - |
+| | angle | rotate | | rotate | - |
+| | x y | translate | | translate | - |
+| | m11 m12 m21 m22 dx dy | .transform | | - | cm |
+| | m11 m12 m21 m22 dx dy | .setTransform | | - | - |
+| | x0 y0 x1 y1 | .createLinearGradient | canvasGradient | | |
+| | x0 y0 r0 x1 y1 r1 | .createRadialGradient | canvasGradient | | |
+| | image repetition | .createPattern | canvasPattern | | |
+| | x y w h | .clearRect | | rectclip | |
+| | x y w h | .fillRect | | rectfill | |
+| | x y w h | .strokeRect | | rectstroke | |
+| | | .beginPath | | newpath | m ? |
+| | | .closePath | | closepath | ~ h ? ~ n ? |
+| | x y | .moveTo | | moveto | m ? |
+| | x y | .lineTo | | lineto | l |
+| | cpx cpy x y | .quadraticCurveTo | | | |
+| | cp1x cp1y cp2x cp2y x y | .bezierCurveTo | | | c |
+| | x1 y1 x2 y2 radius | .arcTo | | arcto | |
+| | x y w h | .rect | | - | ~ re |
+| | x y radius startAngle endAngle anticlockwise | .arc | | ~ arc | |
+| | | fill | | fill | ~ f ? |
+| | | stroke | | stroke | S |
+| | | clip | | clip | ~ W ? |
+| | x y | .isPointInPath | boolean | | |
+| | text x y | .fillText1 | | | |
+| | text x y maxWidth | .fillText2 | | | |
+| | text x y | .strokeText1 | | | |
+| | text x y maxWidth | .strokeText2 | | | |
+| | text | .measureText | textMetrics | | |
+| | image dx dy | .drawImage1 | | | |
+| | image dx dy dw dh | .drawImage2 | | | |
+| | image sx sy sw sh dx dy dw dh | .drawImage3 | | | |
+| | imagedata | .createImageData1 | imageData | | |
+| | sw sh | .createImageData1 | imageData | | |
+| | sx sy sw sh | .getImageData | imageData | | |
+| | imagedata dx dy | .putImageData1 | | | |
+| | imagedata dx dy dirtyX dirtyY dirtyW dirtyH | .putImageData2 | | | |
+
+** Canvas attributes
+
+| | type | attribute | values | ps | pdf |
+|---+------+---------------------------+----------------------------------------------------+---------------+-------|
+| / | | < | | < | < |
+| | num | .globalAlpha | (1.0) | | |
+| | str | .globalCompositeOperation | (source-over) | | |
+| | any | .strokeStyle | (black) | ~ setdash ? | ~ d ? |
+| | any | .fillStyle | (black) | | |
+| | num | .lineWidth | (1) | setlinewidth | w |
+| | str | .lineCap | (butt) round square | ~ setlinecap | J |
+| | str | .lineJoin | round bevel (miter) | ~ setlinejoin | j |
+| | num | .miterLimit | (10) | setmiterlimit | M |
+| | num | .shadowOffsetX | (0) | | |
+| | num | .shadowOffsetY | (0) | | |
+| | num | .shadowBlur | (0) | | |
+| | str | .shadowColor | (transparent black) | | |
+| | str | .font | (10px sans-serif) | | |
+| | str | .textAlign | (start) end left right center | | |
+| | str | .textBaseline | top hanging middle (alphabetic) ideographic bottom | | |
+
+** Other operators
+
+| | canvas | ps | pdf |
+|---+---------------------------------------------+----+-----|
+| / | < | | |
+| | canvasGradient offset color *.addColorStop* | | |
+
+** Other attributes
+
+| | dict | type | attribute | values | ps | pdf |
+|---+------------------+------------------+-----------+--------+----+-----|
+| / | | | < | | < | < |
+| | textMetrics | num | width | | | |
+| | imageData | cnt | width | | | |
+| | imageData | cnt | heigth | | | |
+| | imageData | canvasPixelArray | data | | | |
+| | canvasPixelArray | cnt | length | | | |
+
+[IndexGetter, IndexSetter] CanvasPixelArray
+
+** PostScript operators
+
+| | category | in | operator | out |
+|---+----------+---------+------------+-----|
+| / | | < | < | < |
+| | | x y [m] | transform | x y |
+| | | x y [m] | itransform | x y |
+
+** PDF operators
+
+| | category | operator | |
+|---+------------------------+----------+-----------------------------------------------------------|
+| / | | < | |
+| | General graphics state | w | setlinewidth |
+| | | J | ~ setlinecap |
+| | | j | ~ setlinejoin |
+| | | M | setmiterlimit |
+| | | d | ~ setdash ? |
+| | | ri | {SetColorRenderingIntent} |
+| | | i | {1 .min setflat} |
+| | | gs | {SetExtGState} |
+| | Special graphics state | q | gsave |
+| | | Q | grestore |
+| | | cm | .transform { //TempMatrix astore concat } |
+| | Path construction | m | moveto |
+| | | l | lineto |
+| | | c | .bezierCurveTo (curveto) |
+| | | v | ! currentpoint cp2 p3 c { currentpoint 6 2 roll curveto } |
+| | | y | ! cp1 p3 p3 c { 2 copy curveto } |
+| | | h | closepath |
+| | | re | ! x y m , x+w y l , x+w y+h l , x y+h l , h |
+| | Path painting | S | stroke |
+| | | s | h S |
+| | | f | (fill) |
+| | | F | f |
+| | | f* | {eofill} |
+| | | B | f S { gsave fill grestore stroke } |
+| | | B* | f* S { gsave eofill grestore stroke } |
+| | | b | h b { closepath gsave fill grestore stroke } |
+| | | b* | h B* { closepath gsave eofill grestore stroke } |
+| | | n | {newpath} |
+| | Clipping paths | W | clip |
+| | | W* | {eoclip} |
+| | Text objects | BT | |
+| | | ET | {grestore} |
+| | Text state | Tc | |
+| | | Tw | |
+| | | Tz | |
+| | | TL | |
+| | | Tf | |
+| | | Tr | |
+| | | Ts | |
+| | Text positioning | Td | |
+| | | TD | |
+| | | Tm | |
+| | | T* | |
+| | Text showing | Tj | ~ show |
+| | | TJ | |
+| | | ' | |
+| | | " | |
+| | Type 3 fonts | d0 | setcharwidth |
+| | | d1 | setcachedevice |
+| | Color | CS | |
+| | | cs | |
+| | | SC | |
+| | | SCN | |
+| | | sc | |
+| | | scn | |
+| | | G | g |
+| | | g | setgray |
+| | | RG | rg |
+| | | rg | setrgbcolor |
+| | | K | k |
+| | | k | setcmykcolor |
+| | Shading patterns | sh | |
+| | Inline images | BI | |
+| | | ID | |
+| | | EI | |
+| | XObjects | Do | |
+| | Marked content | MP | |
+| | | DP | |
+| | | BMC | |
+| | | BDC | |
+| | | EMC | |
+| | Compatibility | BX | |
+| | | EX | |
+
+* References
+
+** PostScript in JavaScript by others
+
+Somebody before: http://www.feiri.de/pcan/ RPN calculator with many
+PostScript operators implemented directly in JavaScript. Fast drawing
+but not "real" PostScript.
+
+Wish list: http://svgkit.sourceforge.net/
+
+** Interesting PostScript applications
+
+http://starynkevitch.net/Basile/NeWS_descr_oct_1993.html \\
+http://www.art.net/studios/Hackers/Hopkins/Don/hyperlook/index.html \\
+http://books.google.com/books?id=xHSoK66z34YC&pg=PA193 \\
+http://www.art.net/studios/Hackers/Hopkins/Don/lang/NeWS.html \\
+http://en.wikipedia.org/wiki/Display_PostScript
+
+** Mess
http://canvaspaint.org/blog/2006/12/rendering-text/ \\
http://dev.opera.com/articles/view/html-5-canvas-the-basics/ \\
http://www.benjoffe.com/code/ \\
http://arapehlivanian.com/wp-content/uploads/2007/02/canvas.html
+
+http://two.pairlist.net/pipermail/reportlab-users/2002-September/000599.html
+
+http://www.capcode.de/help/put ref \\
+http://www.math.ubc.ca/~cass/courses/ps.html ps operator summary \\
+http://atrey.karlin.mff.cuni.cz/~milanek/PostScript/Reference/PSL2d.html \\
+http://gauss.upf.es/www-storage/PS_Guide-1.0/operators.html \\
+http://web.mit.edu/ghostscript/www/Language.htm \\
+http://pages.cs.wisc.edu/~ghost/doc/gnu/7.05/Ps-style.htm \\
+http://www.tailrecursive.org/postscript/operators.html \\
+
+http://www.math.ubc.ca/~cass/courses/m308-7b/ch5.pdf
+
+http://en.wikibooks.org/wiki/PostScript_FAQ
+
+: http://www.nihilogic.dk/labs/canvas_sheet/HTML5_Canvas_Cheat_Sheet.png
+
+http://dev.opera.com/articles/view/creating-pseudo-3d-games-with-html-5-can-1/
+
+http://dev.opera.com/articles/view/html-5-canvas-the-basics/
+
+js closure over value, not var!
+
+http://www.pvv.ntnu.no/~andersr/fractal/PostScript.html
+http://www.cs.unh.edu/~charpov/Programming/L-systems/
+http://www.cs.unh.edu/~charpov/Programming/PostScript-primes/
+
+http://www.adobe.com/print/features/psvspdf/index.html
+
+ A PDF file is actually a PostScript file which has already been
+ interpreted by a RIP and made into clearly defined objects.
+
+http://c2.com/cgi/wiki?PortableDocumentFormat
+
+ Unfortunately, Adobe have a history of making needlessly
+ incompatible changes to the PDF format. It's not quite as bad as
+ PostScript in terms of the number of broken documents out there,
+ but it's definitely not a stable format.
+
+hate pdf http://www.useit.com/alertbox/20030714.html
+
+* Ideas
+
+do better than http://processingjs.org/ http://processingjs.org/reference
+
+try 3d interface in chrome
+
+reactive programming http://conal.net/fran/tutorial.htm